Ruby Print Inject Do Syntax

Ruby Print Inject Do Syntax

The block written using the curly braces binds to the inject method, which is what your intention is, and it will work fine.

However, the block that is encapsulated in the do/end block, will bind to the p-method. Because of this, the inject call does not have an associated block. In this case, inject will interpret the argument, in this case 0, as a method name to call on every object. Bacuase 0 is not a symbol that can be converted into a method call, this will yield a warning.

Need a simple explanation of the inject method

You can think of the first block argument as an accumulator: the result of each run of the block is stored in the accumulator and then passed to the next execution of the block. In the case of the code shown above, you are defaulting the accumulator, result, to 0. Each run of the block adds the given number to the current total and then stores the result back into the accumulator. The next block call has this new value, adds to it, stores it again, and repeats.

At the end of the process, inject returns the accumulator, which in this case is the sum of all the values in the array, or 10.

Here's another simple example to create a hash from an array of objects, keyed by their string representation:

[1,"a",Object.new,:hi].inject({}) do |hash, item|
hash[item.to_s] = item
hash
end

In this case, we are defaulting our accumulator to an empty hash, then populating it each time the block executes. Notice we must return the hash as the last line of the block, because the result of the block will be stored back in the accumulator.

About the inject method: How does it work?

inject takes an optional start value, and a block taking an intermediate value and element and returning a new intermediate value.

So:

What does (0) stand for?

The start value parameter to inject.

What does the command "do" do?

It is not a command; it marks the start of the block (terminated by end). .inject(0) do ... end is almost (except for some syntactic issues) the same as .inject(0) { ... }. Usually, do ... end is used for multi-line blocks and { ... } for single-line blocks, but it is not a rule.

What does |res, e| mean?

Those are the block parameters (intermediate value and current element), here probably called after "result" and "element", respectively.

Let's see on a simplified example: (1..3).inject(0) do |res, e| res + e end will set the intermediate result to 0. Then it will pass this intermediate result and the first element of the enumerable being injected: res is 0 and e is 1. The value of the block is the value of its last expression, which is 1 (result of 0 + 1). This 1 now becomes the new intermediate value, and 2 becomes the next current element. The value of the block is 3 (result of 1 + 2). In the next iteration, intermediate value is 3, and the current element also 3, resulting in 6 (3 + 3). The range will stop yielding elements now that we reached its upper boundary, and inject returns with the last intermediate result calculated, 6.

Also, the last question am I right to assume that "p" at the end just stands for puts or print?

Almost. p is its own beast. p x is roughly synonymous with puts x.inspect; x - i.e. it prints the value in a bit different format, and unlike puts which always returns nil, p returns the value unchanged. Thus, p res at the end of your block will not destroy the code by making it return nil, but transparently return res.

In Ruby, why is a method invocation not able to be treated as a unit when do and end is used?

From the (unofficial) ruby grammar, we see that the contents of (...) in puts (...) must be CALL_ARGS, which don't directly reduce to STMT. However, they can reduce to '(' COMPSTMT ')'. By including an extra set of parentheses, you can use do ... end.

a = [1,2,3,4]

puts ((a.inject do |sum, x|
sum + x
end))

Ruby how does this inject code work?

Every method/block/etc. in Ruby returns something, and unless there is an early return statement, whatever the last statement in the method/block/etc. is, is what is returned.

In your case, having list be the last line in the block passed to inject ensures that list is returned by the block. When you remove it, the return value of list[key].push(ws) is returned, which obviously isn't what you want.

Note that this behavior also makes using the return keyword when it is the last statement that would be executed otherwise is unnecessary (this includes the return you have at the end of your method). Though some prefer to be explicit that they intend to return something and use them even when not needed.

On an unrelated note: your if !list.has_key?(key) can be rewritten unless list.has_key?(key).

How can I print syntax-highlighted Ruby code?

A good solution which I use is to print from TextMate via vim which gives you a syntax-highlighted and line-numbered result (or however you choose to configure it.) In addition to vim it requires ps2pdf but these are easy to install with macports etc.

The only limitation is that the file needs to be saved first.

See this page, which shows how to set up the macro as a TextMate 'command'.

Ruby - print the variable name and then its value

Sure it is possible!

My solution tests the var by Object#object_id identity: http://codepad.org/V7TXRxmL

It's crippled in the binding passing style ...

Although it works just for local vars yet, it can be easily be made "universal" adding use of the other scope-variable-listing methods like instance_variables etc.

# the function must be defined in such a place 
# ... so as to "catch" the binding of the vars ... cheesy
# otherwise we're kinda stuck with the extra param on the caller
@_binding = binding
def write_pair(p, b = @_binding)
eval("
local_variables.each do |v|
if eval(v.to_s + \".object_id\") == " + p.object_id.to_s + "
puts v.to_s + ': ' + \"" + p.to_s + "\"
end
end
" , b)
end

# if the binding is an issue just do here:
# write_pair = lambda { |p| write_pair(p, binding) }

# just some test vars to make sure it works
username1 = "tyndall"
username = "tyndall"
username3 = "tyndall"

# the result:
write_pair(username)
# username: tyndall

In Ruby, how to show or print out a function object, without invoking it?

You can use defined? for that:

def foo
return 123
end
foo
#=> 123

defined?(foo)
#=> "method"

A local variable would return:

bar = 123
#=> 123

defined?(bar)
#=> "local-variable"

Or:

def foo
return 123
end
foo
#=> 123

method(:foo)
#=> Object#foo()
method(:foo).call
#=> 123

Rewriting Enum#inject to take a Symbol as a Parameter in Ruby

The build-in inject is quite polymorphic, so before trying to implement it from scratch (without looking at the source code)
we would need to explore how it behaves in different cases. I skip things that you already know (like using the 1st element as
an initial value if not provided explicitly etc), other than that:

[1,2,3].inject(0, :+, :foo) #=> ArgumentError: wrong number of arguments (given 3, expected 0..2)
# Max. arity is strict

[1,2,3].inject(0, :+) { 1 } #=> 6
# If both symbol _and_ block are provided, the former dominates

[1,2,3].inject(:+) { |acc, x| acc } #=> :+
# With only 1 parameter and a block the former will be treated as an init value, not a proc.

[1,2,3].inject("+") #=> 6
[1,2,3].inject("+") { |acc, x| acc } #=> "+"
# Strings work too. This is important, because strings _don't respond to `to_proc`_, so we would need smth. else

[1,2,3].inject #=> LocalJumpError: no block given
# Ok, local jump error means that we try to yield in the cases where the 2nd parameter is not provided

[1,2,3].inject(nil) #=> TypeError: nil is not a symbol nor a string
# But if it is provided, we try to do with it something that quacks pretty much like `send`...

With these bits in mind, we can write something like

module Enum
# Just for convenience, you don't need it if you implement your own `each`
include Enumerable

def my_inject(acc = nil, sym = nil)
# With a single attribute and no block we assume that the init value is in fact nil
# and what is provided should be "called" on elements somehow
if acc && !sym && !block_given?
sym, acc = acc, nil
end

each do |element|
if !acc
# If we are not initialized yet, we just assign an element to our accumulator
# and proceed
acc = element
elsif sym
# If the "symbol" was provided explicitly (or resolved as such in a single parameter case)
# we try to call the appropriate method on the accumulator.
acc = acc.send(sym, element)
else
# Otherwise just try to yield
acc = yield acc, element
end
end

acc
end
end

Bear with me, we're almost there :) Just let's check how it quacks:

class Ary < Array
include Enum
end

ary = Ary.new.push(*[1,2,3])

ary.my_inject #=> LocalJumpError: no block given
ary.my_inject(0) #=> TypeError: 0 is not a symbol nor a string
ary.my_inject("+") #=> 6
ary.my_inject(:+) #=> 6
ary.my_inject(0, :+) #=> 6
ary.my_inject(1, :+) #=> 7
ary.my_inject(1, :+) { 1 } #=> 7
ary.my_inject(:+) { |acc, x| acc } #=> :+

So, pretty much the same. There might be some other edge cases that my implementation doesn't satisfy, but I leave them to you :)



Related Topics



Leave a reply



Submit