Looking for a little wisdom from fellow Rubyists. For a while now, I've used the following for convenience in some of my applications, and I'm wondering if there's a language feature I'm just missing:
class Object
def as_block
yield
end
end
There are other uses, but the normal case for me is a conditional assignment that requires a little non-trivial logic. Two obvious ways to do this:
# via a second method:
def foo
#foo ||= set_foo
end
# via conditional logic:
def foo
if #foo
#foo
else
# do complicated stuff
end
end
Both of these approaches seem kind of ugly: in the first case, #set_foo seems extraneous, and the second just looks kind of nasty. So, instead, I like this:
def foo
#foo ||= as_block do
# do complicated stuff
end
end
The problem here (aside from monkey patching Object) is that it's really a dependency (on the monkey patch) that looks like a language feature. That is, something like this really shouldn't be in (say) a Rails initializer---it seems like it should be in a gem, so the dependency can be managed correctly. Then I'm packaging an entire gem to run five lines of code to monkey patch Object...
So, my questions:
1. Anyone else use this, or something like it?
2. Has the Ruby team ever considered including something like this by default? It seems like a really easy way to use blocks as plain old expressions, but it's not there (as far as I know) which makes me wonder if there's some reason for not including it, or...
3. Is there already some better way of doing this that I'm just unaware of?
Thanks!
-E
What you're looking for is begin ... end. This isn't the same thing as a block or Proc, as it's not an object you can pass around or a closure which creates a new scope, but it should serve your purpose just fine:
def foo
#foo ||= begin
# do complicated stuff
end
end
You could use a lambda:
def foo
#foo ||= lambda do
# do complicated stuff
end.call
end
Note that it is important to call the lambda to actually execute the expression, ie
def foo
#foo ||= lambda do
# do complicated stuff
end
end
will return a lambda rather than your evaluated expression.
Related
I see this popping up all the time in my code
class Foo
def initialize(foo)
#foo = foo
end
#...
end
This isn't too bad, but it gets worse:
class Foo
def initialize(foo,baz,bar,a,b,c,d)
#foo = foo
#baz = baz
#bar = bar
#etc...
You can sortof get around this by doing something like
#foo, #baz, #bar = foo, baz, bar
But even that feels wrong and is annoying to type. Is there a better way to define instance variables according to arguments?
Edit:
There seem to be 2 distinct solutions to this problem. See:
spickermann's answer
Antarr Byrd's answer
You might want to consider using a Struct:
class Foo < Struct.new(foo,baz,bar,a,b,c,d)
end
foo = Foo.new(1,2,3,4,5,6,7)
foo.bar #=> 2
No need to define an extra initialize method at all...
Yes, that's the preferred way to initialize instance variables in Ruby. It can be annoying to type, but it's a well understood pattern. As always in Ruby, using metaprogramming to automate it away is possible, but will make your code harder to follow.
I'd also argue that it's probably a good thing for a class to look ugly when it's taking more than two or three arguments. If your class depends on six different things to function, it's a strong candidate for refactoring.
def initialize args
#foo, #baz, #bar = *args
end
I think there are 3 ways to make initialization of instance variables shorter:
Use Struct or OpenStruct.
Use ruby's parallel assignment.
Use metaprogramming to make a macro like this.
The fattr gem was recently endorsed on Ruby Tapas to help solve this problem. Another consideration though, is whether there are too many things being passed into the initializer. It could be that this class is doing too much and needs to be broken into smaller pieces.
We often shorten a block using the & notation on a symbol like this:
some_array.group_by(&:foo)
Is there a similar way to shorten expressions like {|x| x}?
some_array.group_by{|x| x}
If there were a method Object#self that returns self, then we can do
some_array.group_by(&:self)
but unfortunately, there is no such method. In terms of the number of characters, it may be longer, but readability improves.
Yes. #itself was implemented in Ruby 2.2.0.
You can access the Ruby core team discussion about this feature here.
As an interesting analogue, the #ergo method has been proposed, which would yield the receiver to a given block.
If you haven't yet upgraded to Ruby 2.2.0, you may wish to backport #itself and/or define #ergo as follows:
class Object
def itself; self end
def ergo
fail ArgumentError, "Block expected!" unless block_given?
yield self
end
end
And then:
some_array.group_by &:itself
Well, there's no built-in as far as I know, but you can make a reusable identity block:
id = Proc.new {|x| x}
some_array.group_by(&id)
And then if you really wish this were a language feature:
class Object
def it
Proc.new {|x| x}
end
end
And then you can do:
some_array.group_by(&it)
wherever you like. This may void your warranty.
Yes! The method Kernel#itself was added in Ruby 2.2.0. This method simply returns the object it was called on, so you can write:
some_array.group_by(&:itself)
You can see the extensive discussion of this feature here: https://bugs.ruby-lang.org/issues/6373. The patch was submitted by Rafael França in message #53. You can see it in the official Ruby source by looking in object.c.
If you are using a version of Ruby older than 2.2.0, you can easily add Kernel#itself into your project by putting this code somewhere in your project and making sure it gets required:
module Kernel
def itself
self
end
end if !Kernel.instance_methods.include?(:itself)
However, monkey-patching a part of the Ruby core like that can be dangerous and I would not recommend it if you are making reusable code, like a gem. Instead I would recommend just making your own identity function, as suggested by user2246674:
module MyLibrary
IDENT = Proc.new { |x| x }
array.group_by(&IDENT)
end
I'm writing a simple dsl in ruby. Few weeks ago I stumbled upon some blog post, which show how to transform code like:
some_method argument do |book|
book.some_method_on_book
book.some_other_method_on_book :with => argument
end
into cleaner code:
some_method argument do
some_method_on_book
some_other_method_on_book :with => argument
end
I can't remember how to do this and I'm not sure about downsides but cleaner syntax is tempting. Does anyone have a clue about this transformation?
def some_method argument, &blk
#...
book.instance_eval &blk
#...
end
UPDATE: However, that omits book but don't let you use the argument. To use it transparently you must transport it someway. I suggest to do it on book itself:
class Book
attr_accessor :argument
end
def some_method argument, &blk
#...
book.argument = argument
book.instance_eval &blk
#...
end
some_method 'argument' do
some_method_on_book
some_other_method_on_book argument
end
Take a look at this article http://www.dan-manges.com/blog/ruby-dsls-instance-eval-with-delegation — there is an overview of the method (specifically stated in the context of its downsides and possible solution to them), plus there're several useful links for further reading.
Basically, it's about using instance_eval to execute the block in the desirable context.
Speaking about downside of this technique:
So what's the problem with it? Well, the problem is that blocks are
generally closures. And you expect them to actually be full closures.
And it's not obvious from the point where you write the block that
that block might not be a full closure. That's what happens when you
use instance_eval: you reset the self of that block into something
else - this means that the block is still a closure over all local
variables outside the block, but NOT for method calls. I don't even
know if constant lookup is changed or not.
Using instance_eval changes the rules for the language in a way that
is not obvious when reading a block. You need to think an extra step
to figure out exactly why a method call that you can lexically see
around the block can actually not be called from inside of the block.
Check out the docile gem. It takes care of all the sharp edges, making this very easy for you.
(StackOverflow is telling me that this question is "subjective and likely to be closed"… well, I'll give it a shot regardless)
I'm writing a bunch of helper methods (for a TextMate bundle), and I'd like (and I need) to have them neatly namespaced.
These methods are really just functions, i.e. they don't operate on anything outside their own scope, and thus don't really belong in a class. There's nothing that needs instantiating.
So far, I've been doing this and that works just fine
module Helpers::Foo
module_function
def bar
# ...
end
end
Helpers::Foo.bar # this is how I'd like to call the method/function
But would it be better to:
1. Skip module_function and declare the methods/functions as self.*?
2. Or would it be better to declare a class instead of a module?
3. Or use class << self (inside a module or a class)?
4. Or something else entirely?
I realize this is a pretty open-ended question, but I'm really just looking to hear what people are doing.
I prefer either
module Foo
def self.bar
"bar"
end
end
Foo.bar #=> "bar"
or
module Foo
def Foo.bar
"bar"
end
end
Foo.bar #=> "bar"
but probably lean towards the former, i think self. is really descriptive.
Edit: After reading the comments I propose a third option that I prefer for readability. Technically I think this would be defined as extending the methods included on the Eigen class.
module Foo
module ClassMethods
def baz
"baz"
end
end
extend ClassMethods
end
Foo.baz #=> "baz"
I would like to do some fairly heavy-duty reflection in Ruby. I want to create a function that returns the names of the arguments of various calling functions higher up the call stack (just one higher would be enough but why stop there?). I could use Kernel.caller, go to the file and parse the argument list but that would be ugly and unreliable.
The function that I would like would work in the following way:
module A
def method1( tuti, fruity)
foo
end
def method2(bim, bam, boom)
foo
end
def foo
print caller_args[1].join(",") #the "1" mean one step up the call stack
end
end
A.method1
#prints "tuti,fruity"
A.method2
#prints "bim, bam, boom"
I would not mind using ParseTree or some similar tool for this task but looking at Parsetree, it is not obvious how to use it for this purpose. Creating a C extension like this is another possibility but it would be nice if someone had already done it for me.
I can see that I'll probably need some kind of C extension. I suppose that means my question is what combination of C extension would work most easily. I don't think caller+ParseTree would be enough by themselves.
As far as why I would like to do this goes, rather than saying "automatic debugging", perhaps I should say that I would like to use this functionality to do automatic checking of the calling and return conditions of functions:
def add x, y
check_positive
return x + y
end
Where check_positive would throw an exception if x and y weren't positive. Obviously, there would be more to it than that but hopefully this gives enough motivation.
In Ruby 1.9.2, you can trivially get the parameter list of any Proc (and thus of course also of any Method or UnboundMethod) with Proc#parameters:
A.instance_method(:method1).parameters # => [[:req, :tuti], [:req, :fruity]]
The format is an array of pairs of symbols: type (required, optional, rest, block) and name.
For the format you want, try
A.instance_method(:method1).parameters.map(&:last).map(&:to_s)
# => ['tuti', 'fruity']
Of course, that still doesn't give you access to the caller, though.
I suggest you take a look at Merb's action-args library.
require 'rubygems'
require 'merb'
include GetArgs
def foo(bar, zed=42)
end
method(:foo).get_args # => [[[:bar], [:zed, 42]], [:zed]]
If you don't want to depend on Merb, you can choose and pick the best parts from the source code in github.
I have a method that is quite expensive and only almost works.
$shadow_stack = []
set_trace_func( lambda {
|event, file, line, id, binding, classname|
if event == "call"
$shadow_stack.push( eval("local_variables", binding) )
elsif event == "return"
$shadow_stack.pop
end
} )
def method1( tuti, fruity )
foo
end
def method2(bim, bam, boom)
foo
x = 10
y = 3
end
def foo
puts $shadow_stack[-2].join(", ")
end
method1(1,2)
method2(3,4,4)
Outputs
tuti, fruity
bim, bam, boom, x, y
I'm curious as to why you'd want such functionality in such a generalized manner.
I'm curious how you think this functionality would allow for automatic debugging? You'd still need to inject calls to your "foo" function. In fact, something based on set_trace_func is more able to be automatic, as you don't need to touch existing code. Indeed this is how debug.rb is implemented, in terms of set_trace_func.
The solutions to your precise question are indeed basically, as you outlined. use caller + parsetree, or open the file and grab the data that way. There is no reflection capability that I am aware of that will let you get the names of arguments. You can approve upon my solution by grabbing the associated method object and calling #arity to then infer what of local_variables are arguments, but though it appears the result of that function is ordered, I'm not sure it is safe to rely on that. If you don't mind me asking, once you have the data and the interface you describe, what are you going to do with it? Automatic debugging was not what initially came to mind when I imagined uses for this functionality, although perhaps it is failing of imagination on my part.
Aha!
I would approach this differently then. There are several ruby libraries for doing design by contract already, including ruby-contract, rdbc, etc.
Another option is to write something like:
def positive
lambda { |x| x >= 0 }
end
def any
lambda { |x| true }
end
class Module
def define_checked_method(name, *checkers, &body)
define_method(name) do |*args|
unless checkers.zip(args).all? { |check, arg| check[arg] }
raise "bad argument"
end
body.call(*args)
end
end
end
class A
define_checked_method(:add, positive, any) do |x, y|
x + y
end
end
a = A.new
p a.add(3, 2)
p a.add(3, -1)
p a.add(-4, 2)
Outputs
5
2
checked_rb.rb:13:in `add': bad argument (RuntimeError)
from checked_rb.rb:29
Of course this can be made much more sophisticated, and indeed that's some of what the libraries I mentioned provided, but perhaps this is a way to get you where you want to go without necessarily taking the path you planned to use to get there?
if you want the value for the default values, too, there's the "arguments" gem
$ gem install rdp-arguments
$ irb
>> require 'arguments'
>> require 'test.rb' # class A is defined here
>> Arguments.names(A, :go)
In fact, the method you describe clearly fails to distinguish arguments from local variables while also failing to work automatically
That's because what you're trying to do is not something which is supported. It's possible (everything is possible in ruby), but there's no documented or known way to do it.
Either you can eval the backtrace like what logan suggested, or you can bust out your C compiler and hack sourcecode for ruby. I'm reasonably confident there aren't any other ways to do this.