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.
Related
I have a Rails model, which is using the str_enum gem.
I'm building a generator which reads the models and creates pages for them, and so I'd like to be able to understand what str_enums are attached to a model.
For example
class User < ApplicationRecord
str_enum :email_frequency, %i[every daily weekly], default: 'every'
end
Ideally, I'd like to be able to query the User model and understand there is a str_enum attached to email_frequency, with values of every, daily & weekly.
Once I can understand there is a str_enum attached to a given field, I can pluralize the field and get the values:
irb(main):004:0> User.email_frequencies
=> ["every", "daily", "weekly"]
The question has also be asked over here and the suggestion is to use Module#prepend. I'm familiar with prepend to conditionally insert methods into a model.
How can I use it for this problem?
EDIT
This is quite simple with validations, for example: get validations from model
If I understand your question correctly is that you wanna get all column that has attached with enum string. If so you can override the gem method like this
# lib/extenstions/str_enum.rb
module Extensions
module StrEnum
module ClassMethods
def str_enum(column, *args)
self.str_enums << column.to_s.pluralize
super
end
end
def self.prepended(base)
class << base
mattr_accessor :str_enums
self.str_enums = []
prepend ClassMethods
end
end
end
end
In the User model
prepend Extensions::StrEnum
Now you can use
User.str_enums
to list all columns has attached with str enum.
Make sure you have add lib directory into load path.
So for starters, you could, of course, use the approach that Ninh Le has described and monkeypatch your desired behavior into the gem. In fact, I'm fairly confident that it would work, since your use case is currently relatively easy and you really just need to keep track of all the times the str_enum method gets called.
I would, however, encourage you to consider doing one of two things:
If you plan to do more complex stuff with your enums, consider using one of the more heavy-duty enum gems like enumerize, enumerate_it or active_enum. All of these are packages that have been around for a decade (give or take) and still receive support and all of them have been built with a certain degree of extensibility and introspection in mind (albeit with different approaches).
Have a look at the gem and consider building your own little macro on top of it. IMO one of multiple of Andrew Kane's libraries' biggest weaknesses is arguably their kind of hacky/scripty approach which, while making the libraries hard to extend, makes them inherently easy to understand and thus use as a basis for your own stuff (whereas the gems with a better/more elaborate approach are harder to understand and adapt beyond the means the author has intended to).
Either way, you'll be fine with both of my suggestions as well as Ninh Le's.
I have a collection of 'data endpoints'. Each endpoint has a name and can be available or unavailable. In Ruby I want to present the available endpoints as a Hash to make it easy to work with them. The difficulty is that getting information about the endpoints is costly and should be done lazily.
Some examples of how I want my object to behave:
endpoints = get_endpoints.call # No endpoint information is accessed yet
result = endpoints['name1'] # This should only query endpoint "name1"
is_available = endpoints.key? 'name2' # This should only query endpoint "name2"
all_available = endpoints.keys # This has to query all endpoints
The comments describe how the object internally makes requests to the 'data endpoints'.
It is straightforward to make a Hash that can do the first 2 lines. However I don't know how to support the last 2 lines. To do this I need a way to make the keys lazy, not just the values.
Thank you for taking a look!
You'd have to override the key? method, and do your own checking in there.
class LazyHash < Hash
def key?(key)
# Do your checking here. However that looks for your application
end
end
In my opinion, you're asking for trouble though. One of the most powerful virtues in computer science is expectability. If you're changing the behavior of something, modifying it far beyond it's intent, it doesn't serve you to continue calling it by the original name. You don't need to shoe-horn your solution into existing classes/interfaces.
Programming offers you plenty of flexibility, so you can do stuff like this (dependent on the language of course), but in that same argument, you have no reason not to simply build a new object/service with it's own API.
I recommend starting fresh with a new class and building out your desired interface and functionality.
class LazyEndpoints
def on?(name)
end
def set(name, value)
end
end
(Or something like that, the world is yours for the taking!)
I'm looking for a way to replicate the behavior of none in Sequel. So far I haven't been able to find a way to create a dataset, or a dataset like thing, without tying it to a table.
At the moment I am just returning an enum but I would like to preserve the dataset API to not break any chaining.
E.g.
class User < Sequel::Model
end
User.none # => instance of dataset
Sequel has a null_dataset extension for this: http://sequel.jeremyevans.net/rdoc-plugins/files/lib/sequel/extensions/null_dataset_rb.html
I have a Sinatra application using ActiveRecord and I wish to add a feature where I can generate a fingerprint (SHA1) for a set of records.
The way I've implemented this is by defining a module and including it within ActiveRecord::Relation as follows:
module Fingerprints
def sha1
Digest::SHA1.hexdigest map{ |record| record.attributes.values.join }.join
end
end
ActiveRecord::Relation.send :include, Fingerprints
I can now call 'sha1' on a ActiveRecord::Relation and get the value I need.
My question is whether this is the "preferred" way to be doing this (extending ActiveRecord with additional functionality)?
The final line that uses send feels unclean to me and the simple fact that I'm bolting features onto a class that isn't my own also feels like a hack. I know this is a standard pattern in Ruby but reaching into ActiveRecords guts and patching it in this way is unfamiliar to me.
The alternative is to create a Sinatra helper that takes a ActiveRecord::Relation and returns the fingerprint. While this feels cleaner, I can't help feeling that the sha1 method should really belong to the ActiveRecord::Relation class to better describe it's intent.
This might be simply down to personal preference but I'd be interested how others do this and whether there is a feeling of the "right" way this is done.
Thanks
In all honesty I can't see any real problem with what you've done. Perhaps call the method fingerprint_sha to prevent clobbering, maybe add an custom exception so that if any problems occur you know that it started in your code and not AR's.
Personally, I'd probably have made this a helper and passed in the relation, it could well be more obvious where the method was defined for others if it's in the helpers, but like I say I don't see a problem with what you've done and think it's a good solution.
Maybe someone else will come along and say different and we'll both learn something here :)
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).