Access Ruby accessors using block variables - ruby

I have an application that I am using Active Record to access a database. I'm trying to take the information and put it into a hash for later use.
Here is basically what I am doing.
require 'active_support'
#emailhash = Hash.new
emails = Email.find(:all)
emails.each do |email|
email.attributes.keys.each do |#column|
#emailhash[email.ticketno] || Hash.new
#emailhash[email.ticketno] = email.#column
end
end
The line that doesn't work is:
#emailhash[email.ticketno] = email.#column
Is there any way that I can do this properly? Basically my goal is to build a hash off of the values that are stored in the table columns, any input is appreciated.

Ruby programmers usually indent 2
Your code was squishing all of the emails into one hash entry, rather than an entry per email.
If you want to call a method dynamically, use Object.send.
#emailhash[email.ticketno] || Hash.new doesn't do anything.
Something like this might do it:
require 'active_support'
#emailhash = {}
Email.find(:all).each do |email|
#mailhash[email.ticketno] = {}
email.attributes.keys.each do |key|
#emailhash[email.ticketno][key] = email.send(key)
end
end
The key piece is "send", which calls the method identified by a string or symbol.

You cannot have an iterator variable starting with an #. Try something like this:
require 'active_support'
#emailhash = Hash.new
emails = Email.find(:all)
emails.each do |email|
#emailhash[email.ticketno] = email.attributes.keys.collect{|key| key.column}
end

In addition to blinry's comment, the line
#emailhash[email.ticketno] || Hash.new
looks suspicious. Are you sure you don't want
#emailhash[email.ticketno] ||= Hash.new
?

Besides the previous accurate observations, I would like to add the following:
Point 1.
Is important to state that #ivars may not work on formal function parameters... This said, I think it is invalid to have:
collection.each { |#not_valid| }
Is also a bad practice to have #ivars inside blocks, you won't know for sure in which context this block will be executed in (As you many know, the self reference inside that block may be different than the self reference outside it).
Point 2.
Another point that you should have in mind is that if you don't assign the result of a (||) operator this won't do any modification at all (just will be a time waster), however you could use:
mail_hash[email.ticketno] = mail_hash[email.ticketno] || Hash.new
That can be easily rewritten to:
mail_hash[email.ticketno] ||= Hash.new
Point 3.
Even if email.attributes.keys is a cheap instruction, is not free... I would suggest to have that outside the iteration block (given that the keys will always be the same for each record, given we are not using Document Databases).
Final Result
require 'active_support'
mails = Email.all
#mailshash = mails.inject(Hash.new) do |hsh, mail|
# mail.attributes is already a representation of the
# email record in a hash
hsh[mail.ticketno] = mail.attributes
hsh
end

Related

Hash not being added to array

I give up, I have no idea why the hashes I'm creating are not being added to the end of the array. When I pp the hash it is correct, but for some reason the first hash is getting duplicated, while the second hash isn't being added..
The result I'm getting is this:
[{:id=>"36757153479", :quantity=>1, :status=>"new"},
{:id=>"36757153479", :quantity=>1, :status=>"new"}]
#notice that the id is the same
While what I want is this:
[{:id=>"36767751239", :quantity=>1, :status=>"new"},
{:id=>"36757153479", :quantity=>1, :status=>"new"}]
The incoming array looks like this:
me = [{"id"=>36767751239, "quantity"=>1,"vendor"=>"Martha
Stewart", "product_id"=>9707911431, "gift_card"=>false}, {"id"=>36757153479,
"quantity"=>1, "vendor"=>"Naturalizer", "product_id"=>9707504007,
"gift_card"=>false}]
And my code that steps thru it is this:
incoming_cart_array = []
incoming_cart_hash = {}
unless me.nil?
me.each do |product|
incoming_cart_hash[:id] = product['variant_id'].to_s
incoming_cart_hash[:quantity] = product['quantity']
incoming_cart_hash[:status] = "new"
incoming_cart_array << incoming_cart_hash
end
end
I've done this sort of thing 100's of times, but somehow this isn't working. Its probably something right in front of me, I just can't see it.
Thanks
I seemed to be able to solve it as
incoming_cart_array = []
unless me.nil?
me.each do |product|
incoming_cart_hash = {}
incoming_cart_hash[:id] = product['id'].to_s
incoming_cart_hash[:quantity] = product['quantity']
incoming_cart_hash[:status] = "new"
incoming_cart_array << incoming_cart_hash
end
end
However, I cannot seem to find the reason, that it cannot overwrite incoming_cart_hash[:id] when it isn't defined in the same scope.
I'll dig into it, and update my answer if I figure it out!
Edit: My first initial though after a little debugging is, that when the hash isn't a local variable, it's defined (In the Ruby Source, which is C-based), as a pointer to the hash-type. Therefore in the array << hash line, you're inserting a pointer to the hash in the array. When you're running me.each n-times (2 in this case), the hash is updated, thus you'll have n-pointers in the array, all pointing to the same element. The hash which you're updating. It's seen as the same ruby object.
If you're outputting incoming_cart_hash.object_id inside the loop, each time, you'll see that the object_id is the same every time, when the hash-definition is outside the loop. However, when it's inside - defined as a new local variable every time, it'll differ, as it is a new and redefined object every time.
I found a bit of notes about it here: Ruby - Parameters by reference or by value?
Your code creates only one {} ever, so you get an array with n times the same hash.
You must create a new {} for each iteration.
incoming_cart_array = []
unless me.nil?
me.each do |product|
incoming_cart_hash = {}
...
end
end
Pro tipp — best practice in Ruby is to use map to create and array from an array. And you can use literal syntax to create a new hash, and use && to check for the nil case.
incoming_cart_array = me && me.map do | product |
{
id: product['id'].to_s,
quantity: product['quantity'],
status: "new",
}
end

I an getting an "Undefined method 'new' for.... (A number that changes each time)"

I made a simple program with a single method and I'm trying to test it, but I keep getting this weird error, and I have no idea why it keeps happening.
Here's my code for the only method I wrote:
def make_database(lines)
i = 0
foods = hash.new()
while i < lines.length do
lines[i] = lines[i].chomp()
words = lines[i].split(',')
if(words[1].casecmp("b") == 0)
foods[words[0]] = words[3]
end
end
return foods
end
And then here's what I have for calling the method (Inside the same program).
if __FILE__ == $PROGRAM_NAME
lines = []
$stdin.each { |line| lines << line}
foods = make_database(lines).new
puts foods
end
I am painfully confused, especially since it gives me a different random number for each "Undefined method 'new' for (Random number)".
It's a simple mistake. hash calls a method on the current object that returns a number used by the Hash structure for indexing entries, where Hash is the hash class you're probably intending:
foods = Hash.new()
Or more succinctly:
foods = { }
It's ideal to use { } in place of Hash.new unless you need to specify things like defaults, as is the case with:
Hash.new(0)
Where all values are initialized to 0 by default. This can be useful when creating simple counters.
Ruby classes are identified by leading capital letters to avoid confusion like this. Once you get used to the syntax you'll have an easier time spotting mistakes like that.
Note that when writing Ruby code you will almost always omit braces/brackets on empty argument lists. That is x() is expressed simply as x. This keeps code more readable, especially when chaining, like x.y.z instead of x().y().z()
Other things to note include being able to read in all lines with readlines instead of what you have there where you manually compose it. Try:
make_database($stdin.readlines.map(&:chomp))
A more aggressive refactoring of your code looks like this:
def make_database(lines)
# Define a Hash based on key/value pairs in an Array...
Hash[
# ...where these pairs are based on the input lines...
lines.map do |line|
# ...which have comma-separated components.
line.split(',')
end.reject do |key, flag, _, value|
# Pick out only those that have the right flag.
flag.downcase == 'b'
end.map do |key, flag, _, value|
# Convert to a simple key/value pair array
[ key, value ]
end
]
end
That might be a little hard to follow, but once you get the hang of chaining together a series of otherwise simple operations your Ruby code will be a lot more flexible and far easier to read.

advantage of tap method in ruby

I was just reading a blog article and noticed that the author used tap in a snippet something like:
user = User.new.tap do |u|
u.username = "foobar"
u.save!
end
My question is what exactly is the benefit or advantage of using tap? Couldn't I just do:
user = User.new
user.username = "foobar"
user.save!
or better yet:
user = User.create! username: "foobar"
When readers encounter:
user = User.new
user.username = "foobar"
user.save!
they would have to follow all the three lines and then recognize that it is just creating an instance named user.
If it were:
user = User.new.tap do |u|
u.username = "foobar"
u.save!
end
then that would be immediately clear. A reader would not have to read what is inside the block to know that an instance user is created.
Another case to use tap is to make manipulation on object before returning it.
So instead of this:
def some_method
...
some_object.serialize
some_object
end
we can save extra line:
def some_method
...
some_object.tap{ |o| o.serialize }
end
In some situation this technique can save more then one line and make code more compact.
This can be useful with debugging a series of ActiveRecord chained scopes.
User
.active .tap { |users| puts "Users so far: #{users.size}" }
.non_admin .tap { |users| puts "Users so far: #{users.size}" }
.at_least_years_old(25) .tap { |users| puts "Users so far: #{users.size}" }
.residing_in('USA')
This makes it super easy to debug at any point in the chain without having to store anything in in a local variable nor requiring much altering of the original code.
And lastly, use it as a quick and unobtrusive way to debug without disrupting normal code execution:
def rockwell_retro_encabulate
provide_inverse_reactive_current
synchronize_cardinal_graham_meters
#result.tap(&method(:puts))
# Will debug `#result` just before returning it.
end
Using tap, as the blogger did, is simply a convenience method. It may have been overkill in your example, but in cases where you'd want to do a bunch of things with the user, tap can arguably provide a cleaner looking interface. So, perhaps it may be better in an example as follows:
user = User.new.tap do |u|
u.build_profile
u.process_credit_card
u.ship_out_item
u.send_email_confirmation
u.blahblahyougetmypoint
end
Using the above makes it easy to quickly see that all those methods are grouped together in that they all refer to the same object (the user in this example). The alternative would be:
user = User.new
user.build_profile
user.process_credit_card
user.ship_out_item
user.send_email_confirmation
user.blahblahyougetmypoint
Again, this is debatable - but the case can be made that the second version looks a little messier, and takes a little more human parsing to see that all the methods are being called on the same object.
If you wanted to return the user after setting the username you'd need to do
user = User.new
user.username = 'foobar'
user
With tap you could save that awkward return
User.new.tap do |user|
user.username = 'foobar'
end
It results in less-cluttered code as the scope of variable is limited only to the part where it is really needed. Also, the indentation within the block makes the code more readable by keeping relevant code together.
Description of tap says:
Yields self to the block, and then returns self. The primary purpose
of this method is to “tap into” a method chain, in order to perform
operations on intermediate results within the chain.
If we search rails source code for tap usage, we can find some interesting usages. Below are few items (not exhaustive list) that will give us few ideas on how to use them:
Append an element to an array based on certain conditions
%w(
annotations
...
routes
tmp
).tap { |arr|
arr << 'statistics' if Rake.application.current_scope.empty?
}.each do |task|
...
end
Initializing an array and returning it
[].tap do |msg|
msg << "EXPLAIN for: #{sql}"
...
msg << connection.explain(sql, bind)
end.join("\n")
As syntactic sugar to make code more readable - One can say, in below example, use of variables hash and server makes the intent of code clearer.
def select(*args, &block)
dup.tap { |hash| hash.select!(*args, &block) }
end
Initialize/invoke methods on newly created objects.
Rails::Server.new.tap do |server|
require APP_PATH
Dir.chdir(Rails.application.root)
server.start
end
Below is an example from test file
#pirate = Pirate.new.tap do |pirate|
pirate.catchphrase = "Don't call me!"
pirate.birds_attributes = [{:name => 'Bird1'},{:name => 'Bird2'}]
pirate.save!
end
To act on the result of a yield call without having to use a temporary variable.
yield.tap do |rendered_partial|
collection_cache.write(key, rendered_partial, cache_options)
end
Visualize your example within a function
def make_user(name)
user = User.new
user.username = name
user.save!
end
There is a big maintenance risk with that approach, basically the implicit return value.
In that code you do depend on save! returning the saved user. But if you use a different duck (or your current one evolves) you might get other stuff like a completion status report. Therefore changes to the duck might break the code, something that would not happen if you ensure the return value with a plain user or use tap.
I have seen accidents like this quite often, specially with functions where the return value is normally not used except for one dark buggy corner.
The implicit return value tends to be one of those things where newbies tend to break things adding new code after the last line without noticing the effect. They do not see what the above code really means:
def make_user(name)
user = User.new
user.username = name
return user.save! # notice something different now?
end
A variation on #sawa's answer:
As already noted, using tap helps figuring out the intent of your code (while not necessarily making it more compact).
The following two functions are equally long, but in the first one you have to read through the end to figure out why I initialized an empty Hash at the beginning.
def tapping1
# setting up a hash
h = {}
# working on it
h[:one] = 1
h[:two] = 2
# returning the hash
h
end
Here, on the other hand, you know right from the start that the hash being initialized will be the block's output (and, in this case, the function's return value).
def tapping2
# a hash will be returned at the end of this block;
# all work will occur inside
Hash.new.tap do |h|
h[:one] = 1
h[:two] = 2
end
end
It’s a helper for call chaining. It passes its object into the given block and, after the block finishes, returns the object:
an_object.tap do |o|
# do stuff with an_object, which is in o #
end ===> an_object
The benefit is that tap always returns the object it’s called on, even if the block returns some other result. Thus you can insert a tap block into the middle of an existing method pipeline without breaking the flow.
I would say that there is no advantage to using tap. The only potential benefit, as #sawa points out is, and I quote: "A reader would not have to read what is inside the block to know that an instance user is created." However, at that point the argument can be made that if you're doing non-simplistic record creation logic, your intent would be better communicated by extracting that logic into its own method.
I hold to the opinion that tap is an unnecessary burden on the readability of the code, and could be done without, or substituted with a better technique, like Extract Method.
While tap is a convenience method, it's also personal preference. Give tap a try. Then write some code without using tap, see if you like one way over another.
There is a tool called flog that measures how difficult it is to read a method. "The higher the score, the more pain the code is in."
def with_tap
user = User.new.tap do |u|
u.username = "foobar"
u.save!
end
end
def without_tap
user = User.new
user.username = "foobar"
user.save!
end
def using_create
user = User.create! username: "foobar"
end
and according on flog's result the method with tap is the most difficult to read (and I agree with it)
4.5: main#with_tap temp.rb:1-4
2.4: assignment
1.3: save!
1.3: new
1.1: branch
1.1: tap
3.1: main#without_tap temp.rb:8-11
2.2: assignment
1.1: new
1.1: save!
1.6: main#using_create temp.rb:14-16
1.1: assignment
1.1: create!
There could be number of uses and places where we may be able to use tap. So far I have only found following 2 uses of tap.
1) The primary purpose of this method is to tap into a method chain, in order to perform operations on intermediate results within the chain. i.e
(1..10).tap { |x| puts "original: #{x.inspect}" }.to_a.
tap { |x| puts "array: #{x.inspect}" }.
select { |x| x%2 == 0 }.
tap { |x| puts "evens: #{x.inspect}" }.
map { |x| x*x }.
tap { |x| puts "squares: #{x.inspect}" }
2) Did you ever find yourself calling a method on some object, and the return value not being what you wanted it to? Maybe you wanted to add an arbitrary value to a set of parameters stored in a hash. You update it with Hash.[], but you get back bar instead of the params hash, so you have to return it explicitly. i.e
def update_params(params)
params[:foo] = 'bar'
params
end
In order to overcome this situation here, tap method comes into play. Just call it on the object, then pass tap a block with the code that you wanted to run. The object will be yielded to the block, then be returned. i.e
def update_params(params)
params.tap {|p| p[:foo] = 'bar' }
end
There are dozens of other use cases, try finding them yourself :)
Source:
1) API Dock Object tap
2) five-ruby-methods-you-should-be-using
You're right: the use of tap in your example is kind of pointless and probably less clean than your alternatives.
As Rebitzele notes, tap is just a convenience method, often used to create a shorter reference to the current object.
One good use case for tap is for debugging: you can modify the object, print the current state, then continue modifying the object in the same block. See here for example: http://moonbase.rydia.net/mental/blog/programming/eavesdropping-on-expressions.
I occasionally like to use tap inside methods to conditionally return early while returning the current object otherwise.
You can make your codes more modular using tap, and can achieve a better management of local variables. For example, in the following code, you don't need to assign a local variable to the newly created object, in the scope of the method. Note that the block variable, u, is scoped within the block. It is actually one of the beauties of ruby code.
def a_method
...
name = "foobar"
...
return User.new.tap do |u|
u.username = name
u.save!
end
end
In rails we can use tap to whitelist parameters explicitly:
def client_params
params.require(:client).permit(:name).tap do |whitelist|
whitelist[:name] = params[:client][:name]
end
end
I will give another example which I have used. I have a method user_params which returns the params needed to save for the user (this is a Rails project)
def user_params
params.require(:user).permit(
:first_name,
:last_name,
:email,
:address_attributes
)
end
You can see I dont return anything but ruby return the output of the last line.
Then, after sometime, I needed to add a new attribute conditionally. So, I changed it to something like this:
def user_params
u_params = params.require(:user).permit(
:first_name,
:last_name,
:email,
:address_attributes
)
u_params[:time_zone] = address_timezone if u_params[:address_attributes]
u_params
end
Here we can use tap to remove the local variable and remove the return:
def user_params
params.require(:user).permit(
:first_name,
:last_name,
:email,
:address_attributes
).tap do |u_params|
u_params[:time_zone] = address_timezone if u_params[:address_attributes]
end
end
In the world where functional programming pattern is becoming a best practice (https://maryrosecook.com/blog/post/a-practical-introduction-to-functional-programming), you can see tap, as a map on a single value, indeed, to modify your data on a transformation chain.
transformed_array = array.map(&:first_transformation).map(&:second_transformation)
transformed_value = item.tap(&:first_transformation).tap(&:second_transformation)
No need to declare item multiple times here.
What is the difference?
The difference in terms of code readability is purely stylistic.
Code Walk through:
user = User.new.tap do |u|
u.username = "foobar"
u.save!
end
Key points:
Notice how the u variable is now used as block parameter?
After the block is done, the user variable should now point to a User ( with a username: ‘foobar’, and who is also saved).
It's just pleasant and easier to read.
API Documentation
Here’s an easy to read version of the source code:
class Object
def tap
yield self
self
end
end
For more info, see these links:
https://apidock.com/ruby/Object/tap
http://ruby-doc.org/core-2.2.3/Object.html#method-i-tap
Apart from the above answers, I have used tap in stubbing and mocking while writing RSpecs.
Scenario: When I have a complex query to stub and mock with multiple arguments which shouldn't go missed. The alternative here is to use receive_message_chain (but it lacks the details).
# Query
Product
.joins(:bill)
.where("products.availability = ?", 1)
.where("bills.status = ?", "paid")
.select("products.id", "bills.amount")
.first
# RSpecs
product_double = double('product')
expect(Product).to receive(:joins).with(:bill).and_return(product_double.tap do |product_scope|
expect(product_scope).to receive(:where).with("products.availability = ?", 1).and_return(product_scope)
expect(product_scope).to receive(:where).with("bills.status = ?", "paid").and_return(product_scope)
expect(product_scope).to receive(:select).with("products.id", "bills.amount").and_return(product_scope)
expect(product_scope).to receive(:first).and_return({ id: 1, amount: 100 })
end)
# Alternative way by using `receive_message_chain`
expect(Product).to receive_message_chain(:joins, :where, :where, :select).and_return({ id: 1, amount: 100 })

Explanation of Ruby code for building Trie data structures

So I have this ruby code I grabbed from wikipedia and I modified a bit:
#trie = Hash.new()
def build(str)
node = #trie
str.each_char { |ch|
cur = ch
prev_node = node
node = node[cur]
if node == nil
prev_node[cur] = Hash.new()
node = prev_node[cur]
end
}
end
build('dogs')
puts #trie.inspect
I first ran this on console irb, and each time I output node, it just keeps giving me an empty hash each time {}, but when I actually invoke that function build with parameter 'dogs' string, it actually does work, and outputs {"d"=>{"o"=>{"g"=>{"s"=>{}}}}}, which is totally correct.
This is probably more of a Ruby question than the actual question about how the algorithm works. I don't really have adequate Ruby knowledge to decipher what is going on there I guess.
You're probably getting lost inside that mess of code which takes an approach that seems a better fit for C++ than for Ruby. Here's the same thing in a more concise format that uses a special case Hash for storage:
class Trie < Hash
def initialize
# Ensure that this is not a special Hash by disallowing
# initialization options.
super
end
def build(string)
string.chars.inject(self) do |h, char|
h[char] ||= { }
end
end
end
It works exactly the same but doesn't have nearly the same mess with pointers and such:
trie = Trie.new
trie.build('dogs')
puts trie.inspect
Ruby's Enumerable module is full of amazingly useful methods like inject which is precisely what you want for a situation like this.
I think you are just using irb incorrectly. You should type the whole function in, then run it, and see if you get correct results. If it doesn't work, how about you post your entire IRB session here.
Also here is a simplified version of your code:
def build(str)
node = #trie
str.each_char do |ch|
node = (node[ch] ||= {})
end
# not sure what the return value should be
end

how to name an object reference (handle) dynamically in ruby

So I have a class like this:
def Word
end
and im looping thru an array like this
array.each do |value|
end
And inside that loop I want to instantiate an object, with a handle of the var
value = Word.new
Im sure there is an easy way to do this - I just dont know what it is!
Thanks!
To assign things to a dynamic variable name, you need to use something like eval:
array.each do |value|
eval "#{value} = Word.new"
end
but check this is what you want - you should avoid using eval to solve things that really require different data structures, since it's hard to debug errors created with eval, and can easily cause undesired behaviour. For example, what you might really want is a hash of words and associated objects, for example
words = {}
array.each do |value|
words[value] = Word.new
end
which won't pollute your namespace with tons of Word objects.
Depending on the data structure you want to work with, you could also do this:
# will give you an array:
words = array.map { |value| Word.new(value) }
# will give you a hash (as in Peter's example)
words = array.inject({}) { |hash, value| hash.merge value => Word.new }
# same as above, but more efficient, using monkey-lib (gem install monkey-lib)
words = array.construct_hash { |value| [value, Word.new ] }

Resources