I just started using Shoes and i know a lille bit of ruby but there is something i quite dont understand with the objects and constructor.
I learned to create objects this way:
#obj = SomeClass.new(:someParameter => 3)
Now Shoes want me to create objects this way:
Shoes.app do
#shape = star(points: 5)
motion do |left, top|
#shape.move left, top
end
end
Here is an other example:
require 'shoes'
class ListCell < Shoes::Widget
def initialize
stack :margin_left => 30, :top => 30 do
line 50, 100, 200, 200
end
end
end
Shoes.app :width => 500, :height => 400 do
stack do
#line = list_cell
end
end
Why is there a .new missing?
Why does shoes use the syntax with the colon to pass parameter in the first example?
In the second example i create a ListCell object but I use the syntax list_cell without the new.
Why does this behave like this?
This is maybe a very basic question, but i am trying to learn ruby and i have VB.Net/Java background and some things are just wierd and not very usual to me. The syntax is confusing me.
It is just a DSL. Those methods like star will call .new under the hood.
The colon syntax is just an alternative hash syntax introduced in Ruby 1.9.3:
{ :a => :b }
{ a: :b }
These two lines do the same thing.
Class methods
Shoes.app do is not creating an instance, this is calling a class method.
This allows to call a method directly on a class, without having to instantiate it.
class Foo
def self.hello
puts "hello"
end
end
Foo.hello # outputs "hello"
Block parameter
The block form may confuse you, but it's an other ruby idiom that allows to pass chunk of logic to a method :
def yell( message, &block )
block.call( message.upcase )
end
yell( 'hello' ) do |message|
puts message
end
# outputs "HELLO"
DSL
Finally, there's a special form of block parameter often used to have good looking configuration : blocks that are evaluated in an other context.
When you call a block like in the previous example, the code inside blocks won't be able to access any private method or variable from the class where it's called ; it can only access what is in the scope of where the block was declared.
You can change that using #instance_eval :
class Foo
def config( &block )
instance_eval &block
end
def write!
# perform some writing
end
end
foo = Foo.new
foo.config do
write! # this will work
end
So, basically, your shoes are doing a combination of those three concepts :)
This is not instantiating a class (although it probably does so behind the hood) and you don't especially need that, just use initialization as you are used to.
Related
I'm learning ruby, and noticed that I cannot create a class method called puts:
class Printer
def initialize(text="")
#text = text
end
def puts
puts #text
end
end
The error is:
`puts': wrong number of arguments (given 1, expected 0)
My expectation was that I could use the code like this:
p = Printer.new("hello")
p.puts
It's not just because puts is a built-in method, though. For instance, this code also gives a syntax error:
def my_puts(text)
puts text
end
class Printer
def initialize(text="")
#text = text
end
def my_puts
my_puts #name
end
end
tldr; within the scope of the instance, the puts resolves to self.puts (which then resolves to the locally defined method, and not Kernel#puts). This method overriding is a form of shadowing.
Ruby has an 'implicit self' which is the basis for this behavior and is also how the bare puts is resolved - it comes from Kernel, which is mixed into every object.
The Kernel module is included by class Object, so its methods [like Kernel#puts] are available in every Ruby object. These methods are called without a receiver and thus can be called in functional form [such as puts, except when they are overridden].
To call the original same-named method here, the super keyword can be used. However, this doesn't work in the case where X#another_method calls X#puts with arguments when it expects to be calling Kernel#puts. To address that case, see Calling method in parent class from subclass methods in Ruby (either use an alias or instance_method on the appropriate type).
class X
def puts
super "hello!"
end
end
X.new.puts
P.S. The second example should trivially fail, as my_puts clearly does not take any parameters, without any confusion of there being another "puts". Also, it's not a syntax error as it occurs at run-time after any language parsing.
To add to the previous answer (https://stackoverflow.com/a/62268877/13708583), one way to solve this is to create an alias of the original puts which you use in your new puts method.
class Printer
alias_method :original_puts, :puts
attr_reader :text
def initialize(text="")
#text = text
end
def puts
original_puts text
end
end
Printer.new("Hello World").puts
You might be confused from other (static) programming languages in which you can overwrite a method by creating different signatures.
For instance, this will only create one puts method in Ruby (in Java you would have two puts methods (disclaimer: not a Java expert).
def puts(value)
end
def puts
end
If you want to have another method with the same name but accepting different parameters, you need to use optional method parameters like this:
def value(value = "default value")
end
I'm having trouble understanding this code below.
I get the idea of Unary Ampersand Operator and passing procs as arguments to methods. But I really can't wrap my head around passing self to the language.call. I understand it like this: we're passing self as an argument to the proc/block language. It doesn't make any sense to me. Can someone please explain? :)
class Translator
def speak &language
language.call(self)
end
protected
def french
'bon jour'
end
def spanish
'hola'
end
def turkey
'gobble'
end
def method_missing(*args)
'awkward silence'
end
end
We're using it with:
translator.speak(&:spanish)
This example beautifully ties together multiple Ruby concepts. Because of that, I will try to explain all of them.
Blocks
Methods in Ruby can accept blocks (pieces of code) in elegant matter:
def run_code
yield
end
run_code { puts 42 } # => prints 42
Procs are similar to blocks, but they are actual addressable objects:
deep_thought = proc { puts 42 }
deep_thought.call # => prints 42
You can turn a proc into a block when calling a method with the & operator:
def run_code
yield
end
deep_thought = proc { puts 42 }
run_code(&deep_thought) # => prints 42
Procs and blocks can accept arguments:
def reveal_answer
yield 5_000
end
deep_thought = proc do |years_elapsed|
years_elapsed >= 7_500_000 ? 42 : 'Still processing'
end
reveal_answer(&deep_thought) # => 'Still processing'
You can turn a block into proc using & in the method signature:
def inspector(&block)
puts block.is_a?(Proc)
puts block.call
end
inspector { puts 42 } # => prints true and 42
inspector(&proc { puts 42 }) # => the same
Symbol#to_proc creates a proc that calls methods with the same name on the object:
class Dummy
def talk
'wooooot'
end
end
:talk.to_proc.call(Dummy.new) # => "wooooot"
In other words,
:bar.to_proc.call(foo)
is pretty much equivalent to
foo.bar
BasicObject#method_missing:
When you try to call a method on an object, Ruby traverses it's ancestor chain, searching for a method with that name. How the chain is constructed is a different topic, lengthy enough for another day, the important thing is that if the method is not found til the very bottom (BasicObject), a second search is performed on the same chain - this time for a method called method_missing. It gets passed as arguments the name of the original method plus any argument it received:
class MindlessParrot
def method_missing(method_name, *args)
"You caldt #{method_name} with #{args} on me, argh!"
end
end
MindlessParrot.new.foo # => "You caldt foo with [] on me, argh!"
MindlessParrot.new.bar :baz, 42 # => "You caldt bar with [:baz, 42] on me, argh!"
So what does all this mean in our specific case? Lets assume for a second there was no protected.
translator.speak(&:spanish)
calls the method Translator#speak with :spanish converted to block.
Translator#speak takes that block and transforms it to a proc, named language, and calls it, passing self as argument.
self is an instance of Translator, therefore, it has the methods speak, french, spanish, turkey and method_missing.
And so:
Translator.new.speak(&:spanish)
is equivalent to:
:spanish.to_proc.call(Translator.new)
which is equivalent to:
Translator.new.spanish
giving us "hola".
Now, taking the protected back, all the language methods of our translator object are still present, but they can not be directly accessed by outsiders.
Just as you can't call
Translator.new.spanish
and expect "hola" back, you can't call
Translator.new.speak(&:spanish)
And since the method is not directly accessible, it is considered not found and method_missing is called, thus giving us "awkward silence".
In a unit test I need to test whether alias methods defined by alias_method have been properly defined. I could simply use the same tests on the aliases used for their originals, but I'm wondering whether there's a more definitive or efficient solution. For instance, is there a way to 1) dereference a method alias and return its original's name, 2) get and compare some kind of underlying method identifier or address, or 3) get and compare method definitions? For example:
class MyClass
def foo
# do something
end
alias_method :bar, :foo
end
describe MyClass do
it "method bar should be an alias for method foo" do
m = MyClass.new
# ??? identity(m.bar).should == identity(m.foo) ???
end
end
Suggestions?
According to the documentation for Method,
Two method objects are equal if that
are bound to the same object and
contain the same body.
Calling Object#method and comparing the Method objects that it returns will verify that the methods are equivalent:
m.method(:bar) == m.method(:foo)
bk1e's method works most of the time, but I just happened to hit the case where it doesn't work:
class Stream
class << self
alias_method :open, :new
end
end
open = Stream.method(:open)
new = Stream.method(:new)
p open, new # => #<Method: Stream.new>, #<Method: Class#new>
p open.receiver, new.receiver # => Stream, Stream
p open == new # => false
The output is produced in Ruby 1.9, not sure if it's a bug or not since Ruby 1.8 produces true for the last line. So, if you are using 1.9, be careful if you are aliasing an inherited class method (like Class#new), These two methods are bound to the same object (the class object Stream), but they are considered not equivalent by Ruby 1.9.
My workaround is simple - alias the original method again and test the equality of the two aliases:
class << Stream; alias_method :alias_test_open, :new; end
open = Stream.method(:open)
alias_test_open = Stream.method(:alias_test_open)
p open, alias_test_open # => #<Method: Stream.new>, #<Method: Stream.new>
p open.receiver, alias_test_open.receiver # => Stream, Stream
p open == alias_test_open # => true
Hope this helps.
UPDATE:
See http://bugs.ruby-lang.org/issues/7613
So Method#== should return false in this case since a super call would invoke different methods; it is not a bug.
Calling MyClass.instance_method(:foo) will result UnboundMethod instance, which has eql? method.
So the answer is:
describe MyClass do
subject { described_class }
specify do
expect(subject.instance_method(:foo)).to be_eql(subject.instance_method(:bar))
end
end
While trying to brush up my Ruby skills I keep running across this case which I can't figure out an explanation for by just reading the API docs. An explanation would be greatly appreciated. Here's the example code:
for name in [ :new, :create, :destroy ]
define_method("test_#{name}") do
puts name
end
end
What I want/expect to happen is that the name variable will be bound to the block given to define_method and that when #test_new is called it will output "new". Instead each defined method outputs "destroy" -- the last value assigned to the name variable. What am I misunderstanding about define_method and its blocks? Thanks!
Blocks in Ruby are closures: the block you pass to define_method captures the variable name itself–not its value—so that it remains in scope whenever that block is called. That's the first piece of the puzzle.
The second piece is that the method defined by define_method is the block itself. Basically, it converts a Proc object (the block passed to it) into a Method object, and binds it to the receiver.
So what you end up with is a method that has captured (is closed over) the variable name, which by the time your loop completes is set to :destroy.
Addition: The for ... in construction actually creates a new local variable, which the corresponding [ ... ].each {|name| ... } construction would not do. That is, your for ... in loop is equivalent to the following (in Ruby 1.8 anyway):
name = nil
[ :new, :create, :destroy ].each do |name|
define_method("test_#{name}") do
puts name
end
end
name # => :destroy
for name in [ :new, :create, :destroy ]
local_name = name
define_method("test_#{local_name}") do
puts local_name
end
end
This method will behave as you expect. The reason for the confusion is that 'name' is not created once per iteration of the for loop. It is created once, and incremented. In addition, if I understand correctly, method definitions are not closures like other blocks. They retain variable visibility, but do not close over the current value of the variables.
The problem here is that for loop expressions do not create a new scope. The only things that create new scopes in Ruby are script bodies, module bodies, class bodies, method bodies and blocks.
If you actually look up the behavior of for loop expressions in the Draft ISO Ruby Specification, you will find that a for loop expression gets executed exactly like an each iterator except for the fact that it does not create a new scope.
No Rubyist would ever use a for loop, anyway: they would use an iterator instead, which does take a block and thus creates a new scope.
If you use an idiomatic iterator, everything works as expected:
class Object
%w[new create destroy].each do |name|
define_method "test_#{name}" do
puts name
end
end
end
require 'test/unit'
require 'stringio'
class TestDynamicMethods < Test::Unit::TestCase
def setup; #old_stdout, $> = $>, (#fake_logdest = StringIO.new) end
def teardown; $> = #old_stdout end
def test_that_the_test_create_method_prints_create
Object.new.test_create
assert_equal "create\n", #fake_logdest.string
end
def test_that_the_test_destroy_method_prints_destroy
Object.new.test_destroy
assert_equal "destroy\n", #fake_logdest.string
end
def test_that_the_test_new_method_prints_new
Object.new.test_new
assert_equal "new\n", #fake_logdest.string
end
end
Previously, I asked about a clever way to execute a method on a given condition "Ruby a clever way to execute a function on a condition."
The solutions and response time was great, though, upon implementation, having a hash of lambdas gets ugly quite quickly. So I started experimenting.
The following code works:
def a()
puts "hello world"
end
some_hash = { 0 => a() }
some_hash[0]
But if I wrap this in a class it stops working:
class A
#a = { 0 => a()}
def a()
puts "hello world"
end
def b()
#a[0]
end
end
d = A.new()
d.b()
I can't see why it should stop working, can anyone suggest how to make it work?
that code doesn't work. it executes a at the time it is added to the hash, not when it is retrieved from the hash (try it in irb).
It doesn't work in the class because there is no a method defined on the class (you eventually define a method a on the instance.
Try actually using lambdas like
{0 => lambda { puts "hello world" }}
instead
First of all, you are not putting a lambda in the hash. You're putting the result of calling a() in the current context.
Given this information, consider what the code in your class means. The context of a class definition is the class. So you define an instance method called a, and assign a class instance variable to the a hash containing the result of calling a in the current context. The current context is the class A, and class A does not have a class method called a, so you're trying to put the result of a nonexistent method there. Then in the instance method b, you try to access an instance variable called #a -- but there isn't one. The #a defined in the class context belongs to the class itself, not any particular instance.
So first of all, if you want a lambda, you need to make a lambda. Second, you need to be clear about the difference between a class and an instance of that class.
If you want to make a list of method names to be called on certain conditions, you can do it like this:
class A
def self.conditions() { 0 => :a } end
def a
puts "Hello!"
end
def b(arg)
send self.class.conditions[arg]
end
end
This defines the conditions hash as a method of the class (making it easy to access), and the hash merely contains the name of the method to call rather than a lambda or anything like that. So when you call b(0), it sends itself the message contained in A.conditions[0], which is a.
If you really just want to pretty this sort of thing up,
why not wrap all your methods in a class like so:
# a container to store all your methods you want to use a hash to access
class MethodHash
alias [] send
def one
puts "I'm one"
end
def two
puts "I'm two"
end
end
x = MethodHash.new
x[:one] # prints "I'm one"
x.two # prints "I'm one"
or, to use your example:
# a general purpose object that transforms a hash into calls on methods of some given object
class DelegateHash
def initialize(target, method_hash)
#target = target
#method_hash = method_hash.dup
end
def [](k)
#target.send(#method_hash[k])
end
end
class A
def initialize
#a = DelegateHash.new(self, { 0 => :a })
end
def a()
puts "hello world"
end
def b()
#a[0]
end
end
x = A.new
x.a #=> prints "hello world"
x.b #=> prints "hello world"
One other basic error that you made is that you initialized #a outside of any instance method -
just bare inside of the definition of A. This is a big time no-no, because it just doesn't work.
Remember, in ruby, everything is an object, including classes, and the # prefix means the instance
variable of whatever object is currently self. Inside an instance method definitions, self is an instance
of the class. But outside of that, just inside the class definition, self is the class object - so you defined
an instance variable named #a for the class object A, which none of the instances of A can get to directly.
Ruby does have a reason for this behaviour (class instance variables can be really handy if you know what
you're doing), but this is a more advanced technique.
In short, only initialize instance variables in the initialize method.
table = {
:a => 'test',
:b => 12,
:c => lambda { "Hallo" },
:d => def print(); "Hallo in test"; end
}
puts table[:a]
puts table[:b]
puts table[:c].call
puts table[:d].send( :print )
Well, the first line in your class calls a method that doesn't exist yet. It won't even exist after the whole class is loaded though, since that would be a call to the class method and you've only defined instance methods.
Also keep in mind that {0 => a()} will call the method a(), not create a reference to the method a(). If you wanted to put a function in there that doesn't get evaluated until later, you'd have to use some kind of Lambda.
I am pretty new to using callbacks in Ruby and this is how I explained it to myself using an example:
require 'logger'
log = Logger.new('/var/tmp/log.out')
def callit(severity, msg, myproc)
myproc.call(sev, msg)
end
lookup_severity = {}
lookup_severity['info'] = Proc.new { |x| log.info(x) }
lookup_severity['debug'] = Proc.new { |x| log.debug(x) }
logit = Proc.new { |x,y| lookup_sev[x].call(y) }
callit('info', "check4", logit)
callit('debug', "check5", logit)
a = ->(string="No string passed") do
puts string
end
some_hash = { 0 => a }
some_hash[0].call("Hello World")
some_hash[0][]