I'm working inside a one-off Ruby script (so not inside an explicitly defined module or class) and I'm having a hard time accessing a function I've defined earlier in the script, from within a .each block.
def is_post?(hash)
if hash["data"]["post"] == "true" #yes, actually a string
true
else
false
end
end
#further down
threads["data"]["children"].each do |item|
puts item["data"]["title"] unless item.is_post?
end
Result:
in 'block in <top (required)>': private method `is_post?' called for #<Hash:0x007f9388008cf0\> (NoMethodError)
threads is a very, very nested hash. A hash, contaning a hash of arrays, the arrays contain a hash with header data, which contains another hash with the rest of the details. A bit messy, but I didn't write the module that generates that :P
The idea is to iterate through the arrays and retrieve the data from each one.
My questions are:
What manner of shenaniganery do I need to do to access my is_post? function from within the block?
Why is it coming up as a private method when I don't have any private declarations anywhere in my script?
Kernel vs instance method, self vs argument
def is_post?(hash)
...
end
By defining the methods in that way, you are defining a method for Kernel. You have the choice of either calling this method through Kernel.is_post?(hash), or is_post?(arg). Unless item is the Kernel object, you wont have defined the method is_post? for it.
Your method takes exactly one argument. In case item has a is_post? method, by doing item.is_post?, you are not providing an argument but only self to the method.
The solution
You probably should replace
item.is_post?
by
is_post?(item)
You don't want to call is_post? on the item (it's a Hash like the error message says).
What you want is the following:
threads["data"]["children"].each do |item|
puts item["data"]["title"] unless is_post?(item)
end
Related
How is a good way of passing a method that accept a block?
I.e. to treat the method as a variable so it could be used in this way:
(#glob&.each || crawl_dir(#base_dir)) do |file|
puts "#{file}"
end
A simple example that can be tried out:
> require 'csv'
=> true
> CSV {|v|v}
=> <#CSV io_type:$stdout encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
> a=CSV
=> CSV
> a==CSV
=> true
> a {|v|v}
Traceback (most recent call last):
1: from (irb):14
NoMethodError (undefined method `a' for main:Object)
Is this possible?
In your example, you are using different things which are all called CSV.
CSV {|v|v}
Here, you are calling the method named CSV with a block. You get the return value of that method back. Methods such as this are usually used as converters. E.g. there is the Integer() method which takes an argument (such as a String) which is converted to an Integer object. Usually, those methods are called the same as the class of object they return.
a=CSV
Here, you are assigning the value of the CSV constant (which is the CSV class) to the a variable. In your code, you can then either use the CSV constant or the a variable to refer to the class object.
In these cases where you have the same name refer to different things (a class and a method respectively), Ruby can distinguish which one to call / return based on how you use it. Only of you explicitly and unambiguously call the "thing" (i.e. by passing a block or any other arguments), Ruby will call the method.
In all other cases, if you refer to a thing with a name starting with a capital letter, Ruby expects it to a constant and returns its referred to object (which in this case is the CSV class object).
a {|v|v}
Here, you get an error since Ruby tries to call the method named a (which doesn't exist). Even if this would work, the a variable is at this point a reference to the CSV class (which can't be called directly).
(Note: to call a method whose name you have stored in a variable, you can use the send method, e.g. my_receiver.send(a).)
Now, to solve your initial issue, you could create a method object and use it to call the desired method, e.g.
method_proc = #glob&.method(:each) || method(:crawl_dir).curry(#base_dir)
method_proc.call do |file|
puts file
end
However, this is not very idiomatic Ruby. Here, method references are seldom carried around (rather than in Javascript or Python where you regularly do this with passed function objects). A more idiomatic implementation in Ruby could be:
def handle_file(file)
puts file
end
if #glob.respond_to(:each)
#glob.each { |file| handle_file(file) }
else
crawl_dir(#base_dir) { |file| handle_file(file) }
end
Even more idiomatic would be if your crawl_dir method would (optionally) return an Enumerator object, in which case you could simplify the calling code.
Here, I assume that #glob is either nil or an Enumerable object (such as an Array or an Enumerator which thus response directly to each). This allows us to simplify the code further.
def crawl_dir(directory)
# Return an Enumerator object for the current method invocation if no
# block was passed, similar to how the standard `Enumerable#each` method
# works.
return enum_for(__method__) unless block_given?
# the rest of the method here...
end
enumerable = #glob || crawl_dir(#base_dir)
enumerable.each do |file|
puts file
end
What happens here is that you either take #glob (which we assume to be an Enumerable object if it exists, and thus response do each) or crawl_dir(#base_dir) without a block. From your crawl_dir method, you will get then an Enumerator object back, which is again an Enumerable. You can then loop over this object with each. Both of your objects thus have the same return type can can thus be used similarly.
If you want to get a reference to a method, you can use the Object#method method. You can then call this method using the Method#call method, or the .() syntactic sugar:
require 'csv'
a = method(:CSV)
a.() {|v| v }
#=> #<CSV io_type:$stdout encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
You can always use tap on any object:
a.tap do |v|
p v
end
I have a class that creates objects. I've created getter/setter methods for that class.
Class Test
attr_accessor :method1, :method2, :method3, :method4
I have created several instances from that class, and appended them to a list
#object_array = [obj1, obj2, obj3]
I have a dictionary that contains the keys and values. The keys have the same string value that the instance variables in the test class use. (For example 'method1' exists as :method1) I would like to access those keys as the getter methods.
#method_hash = {'method1' => ['data1','data2'], 'method2' => ['data3','data4']}
I expect this to work, but it isn't. What am I doing wrong?
I should mention that the method below is taking place inside a class and that #object_list and #method_list are themselves instance variables of this second class. (This might not be relevant to solve the issue, but wanted to mention just in case..)
block (2 levels) in func1': undefined method `key' for #<Obj:0x007ffbe1061870> (NoMethodError)
def func1
#object_array.each do |o|
#method_hash.each do |key, value|
puts o."#{key}"
end
end
end
I tried using .to_s, .to_sym to get it to work with no luck.
puts o."#{key}" is syntactically wrong. You need to fetch the property on runtime. For this you can:
puts o.instance_variable_get("##{key}") # dynamically inspect instance variable
# above will only work if key is instance variable and not a method of o.
or
puts o.send(key) #dyanmic dispatch
# will work as long o responds to the key like o.method1.
Update: Prefer o.public_send(key) over send to dynamically dispatch only the publicly accessible method/attribute, as it is safer inspection of object without leaking it's private content.
If you are sure that is an instance variable, go with the safer first option.
Here is an expectation that utilizes a custom RSpec matcher, yield_variables:
specify { expect{ |p| [3,4,5].my_each(&p) }.to yield_variables [3,4,5] }
my yield_variables matcher's matches? method utilizes a custom class called Probe (Probe is a stripped down version of RSpec's yield probe):
...
def matches? block
ap Probe.probe block
# note i am inspecting what is returned by Probe.probe with ap
end
...
# Probe class is what all my questions are about!
class Probe
attr_accessor :yielded_args
def initialize
self.yielded_args = []
end
def self.probe(block)
probe = new
block.call(probe)
probe.yielded_args
end
def to_proc
Proc.new { |*args| yielded_args << args }
end
end
Now my ap inside matches? reports this: [3,4,5] That is what I expect. However, I have no idea how the Probe class works!!
Problem 1) the matches? block
Normally, the argument we pass to matches? is what we expect the subject to return. i.e, I expect [3,4,5] to be passed into block.
Instead, |p| [3,4,5].my_each(&p) is passed into block, as a proc. Why is this?
Problem 2) block.call(probe)
I'm a bit shakey on procs so please explain slowly. But basically, here we take a new instance of my Probe class and 'send' the block to it, as an argument. That's how I'd explain it to the best of my abilities, but I might have it totally wrong so please explain slowly.
Problem 3) How is to_proc called?
How on earth is .to_proc called automatically? I believe it's called automatically by block.call(probe). Is to_proc an automatically called method like initialize? Is it automatically called whenever the class is sent to a proc? (Btw, the phrase the class is sent to a proc doesn't even make 100% sense to me - please explain. The block isn't passed into the class as an argument anymore. Or if the block is passed as an argument the block.call syntax feels really weird and backwards)
Problem 4) to_proc
How does to_proc have access to the expectation's subject i.e. |p| [3,4,5].my_each(&p) ? How is Proc.new 's *args automatically populated with every single possible yield argument, even though I've only passed in |p| ? How does Proc.new loop along with my my_each, incrementally placing all my args in an array? How does Proc.new have any knowledge of the subject |p| [3,4,5].my_each(&p)? How?? Explain please, and thanks.
Block based marchers work a little differently to other matchers. Typically you want to do something that would not be possible if the expression you were interested in was evaluated and the result passed to you.
For example the raises_error matcher wants to execute the block itself to see that the correct exception is raised and the change matcher wants to evaluate some other expression before and after to see if it changes in the specified way. This is why you are passed a block rather than the value.
The block you are passing to expect takes 1 argument and uses this as the block in the call to my_each, so when your Probe.probe method calls the block it has to pass something as the value. You've phrased as "sending the block to the probe instance" but it is the other way around: the block is called using probe as its argument.
The block executes and calls my_each. Inside here p is the instance of Probe. Prefixing an argument with a & tells ruby that this argument should be used as the method's block (the method being my_each). If the argument is not already a proc ruby calls to_proc on it. This is how Probe#to_proc is called
Assuming that my_each behaves in a similar way to normal each it will call its block (ie the return value of to_proc) once for each of the values in the array.
Normally your matcher would then compare the return value from Probe.probe to the actual value.
I need some help understanding what's going on here. It's a block inside of a method. Basically I get everything here except the call in the if statement wasABlock_nowAProc.call. This is not defined here, so what is it calling?
class Array
def eachEven(&wasABlock_nowAProc)
isEven = true # We start with "true" because arrays start with 0, which is even.
self.each do |object|
if isEven
wasABlock_nowAProc.call object
end
isEven = (not isEven) # Toggle from even to odd, or odd to even.
end
end
end
['apple', 'bad apple', 'cherry', 'durian'].eachEven do |fruit|
puts 'Yum! I just love '+fruit+' pies, don\'t you?'
end
# Remember, we are getting the even-numbered elements
# of the array, all of which happen to be odd numbers,
# just because I like to cause problems like that.
[1, 2, 3, 4, 5].eachEven do |oddBall|
puts oddBall.to_s+' is NOT an even number!'
end
def eachEven(&wasABlock_nowAProc) declares that the eachEven method accepts a block, which is the do ... end stuff from your two examples. It is then accessible within the method as a .callable Proc/Lambda object with the name wasABlock_nowAProc.
wasABlock_nowAProc.call object basically invokes the attached block from within the method and passes it one argument, object.
Do a google search for "ruby block to proc" and any of the first results should give you a thorough explanation.
Basically, when you define a method parameter with an & prefix (as in def eachEven(&wasABlock_nowAProc)), it tells Ruby that this method is expecting to receive a Proc object as an argument. In the method body you can then do stuff with Proc, such as use the #call method to run it or pass it on to another method.
Now, it's rare for Ruby programmer to manually create Proc objects. It's much more common to just use a block (less typing, easier to read, etc). If you try to pass a block to method that requires a Proc, well, Ruby handles that just fine. It magically converts the block to a Proc and uses that.
In this particular example, the only reason I can see to define the &wasABlock_nowAProc parameter is to tell Ruby to raise an error if the method is called with a block. You could remove the parameter and replace the #call line with yield to achieve the same functionality.
I've just started on ruby and can't wrap my head around blocks
How is it different from an anonymous function?
On what instance would I want to use it?
And when would I choose it over an anonymous function?
Ruby doesn't have anonymous functions like JavaScript (for example) has. Blocks have 3 basic uses:
Creating Procs
Creating lambdas
With functions
An example of where blocks are similar to anonymous functions is here (Ruby and JavaScript).
Ruby:
[1,2,3,4,5].each do |e| #do starts the block
puts e
end #end ends it
JS (jQuery):
$.each([1,2,3,4,5], function(e) { //Anonymous *function* starts here
console.log(e);
}); //Ends here
The power of Ruby blocks (and anonymous functions) is the fact that they can be passed to any method (including those you define). So if I want my own each method, here's how it could be done:
class Array
def my_each
i = 0
while(i<self.length)
yield self[i]
i+=1
end
end
end
For example, when you declare a method like this:
def foo(&block)
end
block is a Proc object representing the block passed. So Proc.new, could look like this:
def Proc.new(&block)
block
end
Blocks, by necessity, are bound to a method. They can only be turned into an object by a method like I described above. Although I'm not sure of the exact implementation of lambda (it does extra arg checking), but it is the same idea.
So the fundamental idea of a block is this: A block of code, bound to a method, that can either be contained in a Proc object by an & argument, or called by the yield keyword.