Naming convention for filter class? - refactoring

I wonder how could this be named better.
I've have class Filter (it happens to be in Ruby, but the language isn't all that important), which filters objects just like this:
class Filter
def initialize(items)
#items = items
end
def filter
#returns filtered items
end
end
In use it looks like this:
items = Filter.filter
I don't like it. Does anyone have any other better construction for this?

It's fairly clear that plain Filter co-opts to this one class a name that could reasonably be used by many classes that do parallel but distinct jobs.
If you can parameterize the selection criterion (preferably in the initialization function so that you don't store items that won't be returned), then you could call this Filter. If you can't parameterize it, then you should be using a more specific name such as BrokenWidgetsFilter (if the filter picks out the broken widgets presented to it).

Related

Collections in Ruby - is there a collections class like Set but with the member access of Hash?

After reading the Collections chapter in Peter Jones' book, Effective Ruby, the Set class may seem to provide an interesting alternative to Hash. Concerning the Set class, Jones relates:
It’s a lot like its mathematical cousin, a collection of unordered unique elements with operations such as union, intersection, and subset/superset testing.
My only concern is in whether the Set class may not provide direct access to actual member objects.
Presently, I'm trying to use Set (or something like Set) to implement a naive OptionSet API, such that an option in the OptionSet may be of a type Option or ValueOption, with the latter being a subclass of Option. This API may need access to the objects stored in what respective collection for each OptionSet - whether stored in a separate Hash, Array, some other container object, or stored in the OptionSet via some inherited implementation e.g with Set as a superclass.
I'd like to use Set within OptionSet, or to simply implement OptionSet as a subclass of Set. However, if Set may not provide direct access to the member objects, once stored - short of iterating across every member object in the Set, as until finding any ostensible match (e.g. once finding any Option or ValueOption in the collection, such that the "match" would have an equivalent Option.name, typically a symbol) - maybe there's a more effective alternative?
I'd provide sample code, but the implementation of OptionSet is not presently usable. In pseudocode, I'm trying to implement OptionSet#getopt(name) as to return the value of any named Option object stored in the OptionSet, or false if no such option is stored.
The #getopt method would call self.getoptObj(name), a protected method such that would need to access the named option's actual Option object in the collection. Except for that part of the implementation, otherwise Set might be directly suitable.
In any analogy to Scheme-like languages, the Ruby standard library might not provide an AssociativeList class, per se? Simply, I wonder if there's any class like Set -- i.e with set-theoretic methods as in Set -- but with the member access of Hash?
Update
I've tried to implement a MappedSet class, at least in pseudocode, such as to use an instance Hash value to store a mapping between general "Keys" and member objects. I believe that would be redundant to the international storage of Set, however. Maybe I should simply extend Hash.
If you want to create a hash like class you can use DelegateClass:
class FalsyHash < DelegateClass(Hash)
def initialize(hash)
super.tap { |result| result.default = false }
end
end
irb(main):001:0> f = FalsyHash.new(a: :b)
=> {:a=>:b}
irb(main):002:0> f[:b]
=> false
irb(main):003:0> f.is_a?(Hash)
=> false
This is basically just a class that takes an instance of the provided class and wraps it so that method calls are forwarded. Since its not actually an instance of Hash we avoid the pitfalls that happen when core methods check if we are dealing with a hash which would occur if we used a subclass of Hash.
The same thing can be acheived with Delegator, SimpleDelegator and Forwardable - DelegateClass is just a straight forward way of wrapping classes.
You can also augment specific instances of Hash by extending them with a module:
module Reversable
def reverse
transform_values { |v| v.respond_to?(:reverse) ? v.reverse : v }
end
end
# Guess what this returns for a cookie
{ foo: 'olleH', bar: nil, baz: 'dlrow' }.extend(Reversable)
.reverse
.values
.compact
.sort
.join(" ")

Better method for dynamically calling methods from input?

Is it better to use case/when things or the send method when dynamically calling methods based on user input? "better" based primarily on good coding practices.
input = gets.chomp
case input
when foo
foo
when bar
bar
end
versus
input = gets.chomp #Where hopefully the input would be 'foo' or 'bar'
send(input)
Your wording makes the question incredibly hard to read.
If I understood you correctly, you want to call methods based on user input. One alternative would be to check every possible value and call a method, the other - to use send directly.
First of all, notice that in your first example, you were calling method1 when the user entered foo. If you used send(input) you would have called foo instead. So they are not exactly the same.
You can achieve the same behavior by putting the input->method mapping in a hash like so:
dispatch = {foo: :method1, bar: :method2}
input = gets.chomp.to_sym
send(dispatch[input])
Another thing to note is that send in the original situation would call any method passed. You can instead whitelist the possible methods with the hash above and checking if such value exists:
send(dispatch[input]) if dispatch.key? input
Now to the question of when to use one or the other:
If you have 2, 3, 5 or so possibilities, prefer explicitly listing them. It will be faster, easier to read, easier to do static code analysis and so on.
If you have hundreds and thousands of different methods, prefer send. The costs outweigh the benefits of being DRY.
If the list of allowed methods is generated dynamically, you don't have a choice - use send. Examples:
You want to call methods to a given object and that object is different each time
You want to allow different methods depending on the user's permissions
You want to implement a REPL or some other awesome tool that has extremely dynamic needs
In general, don't use meta programming, unless there is significant gain or you don't have any other choice.
Unless you'd like your user to be able to call any method in the method lookup chain, including private methods which send can invoke, it probably makes sense for you to lock it down and only allow your users some methods.
If you don't specify an object to send to (like in your code above), Ruby will look at self for a method by that name and then use a normal method lookup. In other words self will be the first link in the method lookup chain. If you do specify an object, maybe an object that you create for that purpose for example, another option might be to use the methods like try or respond_to?.
input = gets.chomp
if defined?(input.to_sym)
send(input)
else
puts "No such thing!"

Rails Metaprograming/Refactoring/DRYing the controller

I have a controller with several actions. Many follow this pattern:
def favorites
#favorites = Favorite.where(organization_id: #resource.id).page(params[:page]).per(50)
end
It's not just favorites, but there's also downloads, searches, lists etc and they're all so similar that I wanted to create a method that I could call in a before_filter. Something like this:
def set_instance_variable
subject = __method__
class = __method__.singularize.constantize
instance_variable = self.class.instance_variable_set("##{subject}", "#{class}.where(organization_id: #resource.id).page(params[:page]).per(50)")
end
The syntax might be a little off here, but I know this won't work because __method__ will always be set_instance_variable and not the parent method where it is called.
Is there a way to dynamically set instance variables based on the method that defines them? Is this example above even on the right track?
I like the way the CanCan library handles this problem. With CanCan, you call a class method at the top of your controller:
load_resource
CanCan then looks at:
the action you're in to determine whether you want a collection or singular resource,
the name of the controller to determine the class to load
authorization rules to add scopes like your organization_id restriction (cancan is also a library for defining these)
I think pagination and resource loading are separate things, and you shouldn't put them in the same method. I'd shoot for an interface like this:
class FavoritesController
load_resource
paginate_resource only: [:index]
def show
# #favorite loaded here
end
def index
# #favorites loaded and paginated here
end
end
https://github.com/CanCanCommunity/cancancan/blob/develop/lib/cancan/controller_resource.rb#L29
If it makes more sense in your application to have non-restful resources, then you can't re-use the convention-based thing cancan is and instead have to define your own function. Consider something like this:
def favorites
#favorites = load_resource Favorite
end
private
def load_resource(klass)
klass.where(organization_id: #resource.id).page(params[:page]).per(50)
end

Overriding AR order scope

I have a Project model and a Developer model. I have the concept of calculating the "interestingness" for a project for a particular developer:
class Project < ActiveRecord::Base
def interestingness_for(developer)
some_integer_based_on_some_calculations
end
end
I think it would be neat, instead of having something like Project.order_by_interestingness_for(bill), to be able to say
Project.order(:interestingness, :developer => bill)
and have it be a scope as opposed to just a function, so I can do stuff like
Project.order(:interestingness, :developer => bill).limit(10)
I don't know how to do this, though, because it's not obvious to me how to override a scope. Any advice?
Assuming you will not need to use the standard ActiveRecord order query method for the Project class, you can override it like any other class method:
def self.order(type, options)
self.send(:"special_#{type}_calculation_via_scopes", options)
end
Then the trick is to ensure you create the needed calculation methods (which will vary according to your interestingness and other algorithms). And that the calculation methods only use scopes or other AR query interface methods. If you aren't comfortable converting the method logic to a SQL equivalent using the query interface, you can try using the Squeel DSL gem which can potentially work with the method directly depending on your specific calculation.
If you may be needing the classic order method (and this is usually a safe assumption), then don't override it. Either create a proxy non-ActiveRecord object for this purpose, or use a different naming convention.
If you really want to, you can use aliasing to achieve a similar effect, but it may have unintended consequences for the long term if the second argument ('options' in this case) suddenly takes on another meaning as Rails progresses. Here is an example of what you can use:
def self.order_with_options(type, options = nil)
if options.nil?
order_without_options(type)
else
self.send(:"special_#{type}_calculation_via_scopes", options)
end
end
class << self
alias_method_chain :order, :options
end

Is there a Ruby CSV parser that generates column getter methods?

I'm trying to generalize a data retrieval mechanism with Ruby, and can't seem to find a way to retrieve a CSV file and access one of the row's columns by using a dot operator like so:
Let's say I have a CSV table:
#some_file.csv
name,age
albert,13
And I create a FasterCSV table from it:
a = FasterCSV.new(File.open('some_file.csv'), :headers => :first_row)
Then, when accessing a row, I'd like to be able to say:
a[0].name
=> 'albert'
Instead of
a[0]['name']
=> 'albert'
Anyone know how to do that?
Well, if you don't find one, you can always monkey-patch FasterCSV::Row class, something like:
class FasterCSV::Row
def method_missing(m,*args)
if self.field?(m.to_s)
return self[m.to_s]
else
super
end
end
end
(Haven't tried the code myself.)
PS. As you are generalizing data retrieval mechanism, I assume that CSV is just one of several data sources you plan to support. The logical thing then would be to create a single wrapper class for each of your data sources, with some common interface (which might or might not use accessors for accessing row fields). But underneath it should still access CSV row usual way, using [] method. So, as Glenjamin already asked, why do you need this at all? ;)
The simplest answer would be.. why?
I'll assume its mostly as syntactic sugar, so here's a little monkeypatch that should do what it is you want:
class FasterCSV::Row
def method_missing(row)
field(row)
end
end
Note that any field names conflicting with existing Row methods wont work like this.

Resources