how to get source code text in ruby? - ruby

inspired by some lisp magic of runtime edit sourcecode,
I want to do it in ruby. looks like I cannot get sourcecode from method/class,
is there a way to do it?
I write a sample sourcecode here:
def helloworld n
"hello #{n}"
end
o = Kernel.method :helloword
Kernel.define_singleton_method o.name do |n|
eval o.source_code.sub('hello', 'hello world')
end
helloworld 'halida' #=> 'hello world halida'

You can't get the string representation of a part of the code, edit it and expect Ruby to reevaluate your changes. The only way to do something near to what you want is using ParseTree to get s-expressions of the source, edit and use Ruby2Ruby to generate a string of ruby code. Them add def ... and end to the string and call eval with it.
It's too hard and error-prone to be useful in a real-world situation. But I don't know any other way.
Note: ParseTree only works on Ruby 1.8.

Have a look at method_source gem. It's used by pry REPL for show-method command.
Looks like this gem utilizes standard Method#source_location (available in Ruby 1.9) to locate method and get its source code. Obviously, it doesn't work for dynamically defined methods and C methods. See docs for more information.

You can easily get source code for a method in Ruby.
Imagine the following hypothetical class:
class Klass
def self.foo
:foo
end
def bar
:bar
end
end
As you can see, this class has two methods:
a class method .foo
an instance method #bar
Use .method and .instance_method to access them programmatically:
m1 = Klass.method :foo
=> #<Method: Klass.foo>
m2 = Klass.instance_method :bar
=> #<UnboundMethod: Klass#bar>
You can use the .source method to view their source code:
puts m1.source
def self.foo
:foo
end
=> nil
puts m2.source
def self.bar
:bar
end
=> nil
Because Ruby has open classes and dynamic loading, you can also add or
change methods at run time. Just re-open the class and redefine the method:
Klass.foo
=> :foo
class Klass
def self.foo
:foobar
end
end
Klass.foo
=> :footer
The other methods previously defined in the class will remain unaffected:
Klass.bar
=> :bar
WARNING: Redefining class behavior during runtime (also called "Monkey Patching")
is a very powerful tool, it can also be somewhat dangerous. Current versions of Ruby
support a much more controlled way of going about this called 'refinements'.
You can learn more about using refinements here

Related

Safely extending functionality of a standard library class

Is there a simple way to extend a functionality of a standard library class like String inside a module without affecting anything outside of it? Example (won't work):
module Foo
class String
def hello
"hello #{self}!"
end
end
class Bar
def greet name
name.hello
end
end
end
Result I'm looking for:
Foo::Bar.new.greet 'Tom' #=> hello Tom!
'Tom'.hello #=> NoMethodError
I'm aware of solutions like creating MyString < String with desired functionality, but I would rather not call MyString.new('foo') every time I want to use a string inside the module.
I realise this may not be considered good practice, I'm just looking to expand my understanding of the language.
What you're looking for is Refinement:
Refinements are designed to reduce the impact of monkey patching on
other users of the monkey-patched class. Refinements provide a way to
extend a class locally.
module Foo
refine String do
def hello
"hello #{self}!"
end
end
end
puts 'Tom'.hello
#=> undefined method `hello' for "Tom":String
using Foo
puts 'Tom'.hello
#=> hello Tom!
Using refinement inside Bar class:
# Without refinement
class Bar
def greet(name)
name.hello
end
end
puts Bar.new.greet('Tom')
#=> undefined method `hello' for "Tom":String
# With refinement
class Bar
using Foo
def greet(name)
name.hello
end
end
puts Bar.new.greet('Tom')
#=> hello Tom!
For the complete info about scoping, method lookup and stuff look into docs link I've provided :)
P.S. Be aware, that Rubinius developers are philosophically opposed to Refinements and thus will never implement them (c) Jörg W Mittag.
Write a class of the same name then use require_relative (or similar method) to include it.
class Date
def itis
puts "It is " + self.to_s
end
Example:
[1] pry(main)> require_relative 'date.rb'
=> true
[2] pry(main)> require 'date'
=> true
[3] pry(main)> Date.new(2018, 10, 9).itis
It is 2018-10-09
=> nil

Defining and calling a method in irb

I'm struggling with understanding understanding OOP.
I am trying to use IRB to play around with Ruby and deepen my understanding.
In IRB
foo = Object.new
Creates a new object
However if I try and give irb a definition and call it on that object it doesn't work. (does the def have to happen in a .rb file and loaded into Ruby?)
def bar "hello" end
You need to define the method in the class you want it to apply to.
class NewObject
def foo
puts "hello"
end
end
these methods are called like:
x = NewObject.new
x.foo
You can create methods that are not specific to a class just by defining them:
def bar
puts "bar!"
end
and just call them as:
bar
Use pry
gem install pry
its better than irb
everything in ruby is an object
dot notation on an object means that this is a method of that object
this is why you need to wrap it inside a class / module
I suggest read here for more info:
https://rubymonk.com/learning/books/4-ruby-primer-ascent/chapters/45-more-classes/lessons/113-class-variables

Is there a way to create temporary namespaces and constants in Ruby?

I have a class:
class MyClass
def self.say_hello
puts "hello"
end
end
and I want to create a process to override the class and its method temporarily:
begin "a temporary namespace, constants, variables and methods within this code"
Thread.current[:neverland] = -> do
Object.instance_exec do
class MyClass
def self.say_hi
puts "hi"
end
end
MyClass.say_hi
MyClass.say_hello
end
end
end
> Thread.current[:neverland].call
=> "hi"
=> "hello"
> MyClass.methods - Object.methods
=> ["say_hello"]
> MyClass.say_hi
=> undefined method `say_hi' for MyClass:Class (NoMethodError)
Is there something like this in Ruby or am I just dreaming? Namespace pollution-free, temporary constants, methods, namespace, class. Clean, focused and optimized code, without too much distractions.
You're probably thinking of something like Refinements that are scheduled for release in Ruby 2.0.
Until then you're going to have to be creative.

Ruby: Is there a way to get the enclosing Module const of a Class?

I'm doing some metaprogramming in Ruby, and I need to dynamically generate a sibling class inside of a module. In doing so, I want to call const_set on the module, but I don't know which Module constant to call that on until runtime. An example:
Given classes
Foo::Bar::Baz
Foo::Quox::Quack
I want to be able to call a function like this (oversimplified here):
def generate_from klass
mod = klass.enclosing_module # <- THIS LINE is the one I need to figure out
mod.const_set("GeneratedClassName", Class.new)
end
and what I want to end up with, when calling with Baz, is a new class defined as
Foo::Bar::GeneratedClassName
and with a Quack, I want
Foo::Quox::GeneratedClassName
The only way I know of is to split up klass.name, then repeatedly call const_get on those strings, constantized. Does anyone know of a more elegant way?
This should get you on track:
module Foo
module Bar
class Baz
def initialize
#nesting = Module.nesting
end
def enclosing_module
#nesting.last
end
end
end
end
puts Foo::Bar::Baz.new.enclosing_module #=> Foo
Relevant documentation:
http://ruby-doc.org/core/classes/Module.html#M000441
Got it.
ActiveSupport has this Ruby extension, Module#parent. It's good enough for my use.
In Rails you can use a combination of deconstantize and constantize.
'Foo::Bar::Baz'.deconstantize.constantize # => Foo::Bar
so in a method of the class it can be used like this:
self.class.name.deconstantize.constantize
In case anyone is looking for a pure ruby version:
def get_parent_type
#Note: This will break for base types (lacking '::' in the name)
parent_type=self.class.name.split('::')[0...-1]
begin
Object.const_get(parent_type.join('::'))
rescue NameError => e
nil
end
end

Kernel#__method__ doesn't seem to work correctly in dynamically defined methods

I've been trying to dynamically define some instance methods in Ruby 1.9. Here's the code I've been using to try this out:
class Testing
[:one, :two].each do |name|
define_method(name) do
puts __method__
end
end
end
And here's the output:
ruby-1.9.2-p180 :008 > t = Testing.new
=> #<Testing:0x00000100961878>
ruby-1.9.2-p180 :009 > t.one
two
=> nil
ruby-1.9.2-p180 :010 > t.two
two
=> nil
ruby-1.9.2-p180 :011 >
I would expect the result to be one and two respectively. If I call define_method of each one outside of the iteration it works as expected. What am I not understanding here?
Here is one of many examples I saw around online of define_method being called in an iteration. Dynamically defined setter methods using define_method?
What's missing?
Also: Using __method__ isn't critical for me, but it was the best way I could show, that it seems like only the last block sent to define_method is being used for the defined methods. Maybe that is starting to explain the problem to me, but I still don't understand..
Nice find on the weird behavior. Of all the Rubies I tested, only MRI 1.9.2 demonstrates this.
Ryan Davis has reported the bug on the ruby-core list (referencing this question).
You can use something like this instead of define_method:
class Testing
[:one, :two].each do |name|
eval <<-EOM
def #{name}
puts __method__
end
EOM
end
end
t = Testing.new
t.one #=> "one"
t.two #=> "two"
The reason this happens is that define_method defines a method in a slightly different way than def does. It has to do with creating anonymous procs and lambdas. What I would suggest is to simply use the method name since you already have it. This should avoid having to search the stack trace for the method name as well, so it should perform better:
class Testing
[:one, :two].each do |name|
define_method name do
"This method's name is #{name}."
end
end
end
Testing.new.one
=> This method's name is one.
Testing.new.two
=> This method's name is two.
To clarify, notice what is returned by the following two statements:
class Testing
define_method :one do
__method__
end
end
=> #<Proc:0x000001009ebfc8#(irb):54 (lambda)>
class Testing
def one
__method__
end
end
=> nil
P.S: There's also a performance difference between using the two formats. You can verify yourself that def is faster than define_method using Benchmark.

Resources