I have this piece of code here:
class MyFile
attr_accessor :byte_content
alias_method :read, :byte_content
alias_method :write, :byte_content=
end
On the class MyFile there is an alias_method, but I do not understand how this method is working. Does it change the way the getter and setter for :byte_content are called?
Also, what is the difference between this method and just using alias? When should I one over the other?
Thanks in advance for your time!
This:
attr_accessor :byte_content
Essentially does:
def byte_content
#byte_content
end
def byte_content=(value)
#byte_content = value
end
Then
alias_method :read, :byte_content
alias_method :write, :byte_content=
will create copies of the byte_content and byte_content= methods with read and write as the new names . If you modify the byte_content or byte_content= methods after the aliasing, the read and write will remain unchanged.
So, the intention of the alias_method in the example appears to be to give the user a more "File-like" interface. Without the method aliases, you would use:
file = MyFile.new
file.byte_content = "abcd"
puts file.byte_content
With the aliases, the user can use:
file = MyFile.new
file.write("abcd")
file.read
Which is quite similar to the methods of the standard library File class,
file = File.open('/tmp/foo.txt', 'w')
file.write('hello')
file.rewind
puts file.read
And this makes it possible to use instances of MyFile in place of real File instances in some very simple use-cases, also known as Duck-typing.
alias vs alias_method
The differences of alias and alias_method are described in the answers to this question, most imporantly:
you can override alias_method but not alias
alias_method is used with symbols as the method names, making it useful for dynamically created methods
Related
To define a class I must do the following (for example)
class Foo
#attr_accessors
#methods
#so on
end
foo = Foo.new #to create an instance
Problem
I need to achieve the following
case_class Foo_inmutable #I change class for case_class
#attr_accessors
#methods
#so on
end
foo_inmutable = Foo_inmutable.new
#->SyntaxError: uninitialze constant Foo_inmutable
I need the ruby interpreter to treat the case_class the same way to keyword class
Like almost all programming languages, Ruby does not allow you to modify its syntax or semantics. So, what you want is not possible.
You can, however, quite easily write a method that accomplishes your goal, but without changing the syntax and semantics of Ruby:
class Module
def case_class(name, superclass = ::Object, &blk)
const_set(name, Class.new(superclass, &blk))
end
end
def case_class(name, superclass = ::Object, &blk)
self.class.case_class(name, superclass, &blk)
end
case_class :Foo_immutable do
# ↑ ↑↑
# these are the only differences to your proposed syntax
#attr_accessors
#methods
#so on
end
foo_immutable = Foo_immutable.new
To achieve this, besides defining what's already been said in the previous answer:
class Module
def case_class(name, superclass = ::Object, &blk)
const_set(name, Class.new(superclass, &blk))
end
end
def case_class(name, superclass = ::Object, &blk)
self.class.case_class(name, superclass, &blk)
end
You may want to have a look at the const_missing method, and the "Lookup" that ruby does for constants inside the various scopes
That will allow you to do stuff like
case_class Foo do
...
end
For further explanation you can refer to this page: tadp-utn-frba.github.io
It has tons of useful scripts explaining ruby metaprogramming (in spanish) and how to achieve what you are looking for, also it has contact references for the
people in charge of the page, so you can email them at any time (Given you are a student of the class) for academic reasons.
Cheers!
I know I can do the following, and it's just 3 lines:
class << self
alias :generate :new
end
But out of curiosity, is there a simpler way (without semicolons) like:
class_alias :generate, :new
Since Ruby 1.9 you can use the singleton_class method to access the singleton object of a class. This way you can also access the alias_method method. The method itself is private so you need to invoke it with send. Here is your one liner:
singleton_class.send(:alias_method, :generate, :new)
Keep in mind though, that alias will not work here.
I am pasting some alias method examples
class Test
def simple_method
puts "I am inside 'simple_method' method"
end
def parameter_instance_method(param1)
puts param1
end
def self.class_simple_method
puts "I am inside 'class_simple_method'"
end
def self.parameter_class_method(arg)
puts arg
end
alias_method :simple_method_new, :simple_method
alias_method :parameter_instance_method_new, :parameter_instance_method
singleton_class.send(:alias_method, :class_simple_method_new, :class_simple_method)
singleton_class.send(:alias_method, :parameter_class_method_new, :parameter_class_method)
end
Test.new.simple_method_new
Test.new.parameter_instance_method_new("I am parameter_instance_method")
Test.class_simple_method_new
Test.parameter_class_method_new(" I am parameter_class_method")
OUTPUT
I am inside 'simple_method' method
I am parameter_instance_method
I am inside 'class_simple_method'
I am parameter_class_method
I don't believe there is any class-specific version of alias. I usually use it as you have previously demonstrated.
However you may want to investigate the difference between alias and alias_method. This is one of those tricky areas of ruby that can be a bit counter-intuitive. In particular the behavior of alias with regard to descendants is probably not what you expect.
Hope this helps!
I'm deeping into ruby metaprogramming and have next question.
Example:
module ExampleAliaser
def do_example_alias(prefix=:origin)
class_eval <<-EOS
class << self
alias_method :#{prefix}_example, :example
def example
puts "in aliase will call :#{prefix}_example"
#{prefix}_example
end
end
EOS
end
end
class Example1
def self.example
puts "Example"
end
end
Example1.extend(ExampleAliaser)
class Example1
do_example_alias(:origin)
end
class Example2 < Example1
do_example_alias(:origin)
end
Example1.example
in aliase will call :origin_example
Example
=> nil
Example2.example
in aliase will call :origin_example
in aliase will call :origin_example
in aliase will call :origin_example
SystemStackError: stack level too deep
from /Users/igorfedoronchuk/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/irb/workspace.rb:80
Maybe IRB bug!!
So when mixin used 2 times it causes error.
What is the best way to fix such things? How to determine that mixing exists and remove it before new mixing
Follow the definition of methods to see why this is happening.
You first define Example1::example in the class definition of Example1. It writes a string to the console.
Then you extend ExampleAliaser. When you call Example1::do_example_alias, you then alias the method example to origin_example and redefine the method example to write a different string to the console and call origin_example.
Then you define the class Example2 to inherit from Example1, which now has two methods defined on it: origin_example and example. When you call Example2::do_example_alias, you alias the method example to origin_example. But remember that example was already redefined to call origin_example. So effectively, Example2::example will call itself until you run out of room on the stack.
If you want to avoid double-aliasing, you could include some kind of guard in do_example_alias:
def do_example_alias(prefix = :origin)
unless methods.include?("#{prefix}_example")
# do the aliasing
end
end
You can also undef :method_name in subclasses to remove methods that you no longer want defined.
I found a blog post on alias vs. alias_method. As shown in the example given in that blog post, I simply want to alias a method to another within the same class. Which should I use? I always see alias used, but someone told me alias_method is better.
Usage of alias
class User
def full_name
puts "Johnnie Walker"
end
alias name full_name
end
User.new.name #=>Johnnie Walker
Usage of alias_method
class User
def full_name
puts "Johnnie Walker"
end
alias_method :name, :full_name
end
User.new.name #=>Johnnie Walker
Blog post link here
alias_method can be redefined if need be. (it's defined in the Module class.)
alias's behavior changes depending on its scope and can be quite unpredictable at times.
Verdict: Use alias_method - it gives you a ton more flexibility.
Usage:
def foo
"foo"
end
alias_method :baz, :foo
Apart from the syntax, the main difference is in the scoping:
# scoping with alias_method
class User
def full_name
puts "Johnnie Walker"
end
def self.add_rename
alias_method :name, :full_name
end
end
class Developer < User
def full_name
puts "Geeky geek"
end
add_rename
end
Developer.new.name #=> 'Geeky geek'
In the above case method “name” picks the method “full_name” defined in “Developer” class. Now lets try with alias.
class User
def full_name
puts "Johnnie Walker"
end
def self.add_rename
alias name full_name
end
end
class Developer < User
def full_name
puts "Geeky geek"
end
add_rename
end
Developer.new.name #=> 'Johnnie Walker'
With the usage of alias the method “name” is not able to pick the method “full_name” defined in Developer.
This is because alias is a keyword and it is lexically scoped. It means it treats self as the value of self at the time the source code was read . In contrast alias_method treats self as the value determined at the run time.
Source: http://blog.bigbinary.com/2012/01/08/alias-vs-alias-method.html
A point in favor of alias instead of alias_method is that its semantic is recognized by rdoc, leading to neat cross references in the generated documentation, while rdoc completely ignore alias_method.
I think there is an unwritten rule (something like a convention) that says to use 'alias' just for registering a method-name alias, means if you like to give the user of your code one method with more than one name:
class Engine
def start
#code goes here
end
alias run start
end
If you need to extend your code, use the ruby meta alternative.
class Engine
def start
puts "start me"
end
end
Engine.new.start() # => start me
Engine.class_eval do
unless method_defined?(:run)
alias_method :run, :start
define_method(:start) do
puts "'before' extension"
run()
puts "'after' extension"
end
end
end
Engine.new.start
# => 'before' extension
# => start me
# => 'after' extension
Engine.new.run # => start me
A year after asking the question comes a new article on the subject:
http://erniemiller.org/2014/10/23/in-defense-of-alias/
It seems that "so many men, so many minds." From the former article author encourages to use alias_method, while the latter suggests using alias.
However there's a common overview of these methods in both blogposts and answers above:
use alias when you want to limit aliasing to the scope where it's defined
use alias_method to allow inherited classes to access it
The rubocop gem contributors propose in their Ruby Style Guide:
Prefer alias when aliasing methods in lexical class scope as the
resolution of self in this context is also lexical, and it
communicates clearly to the user that the indirection of your alias
will not be altered at runtime or by any subclass unless made
explicit.
class Westerner
def first_name
#names.first
end
alias given_name first_name
end
Always use alias_method when aliasing methods of modules, classes, or
singleton classes at runtime, as the lexical scope of alias leads to
unpredictability in these cases
module Mononymous
def self.included(other)
other.class_eval { alias_method :full_name, :given_name }
end
end
class Sting < Westerner
include Mononymous
end
alias_method new_method, old_method
old_method will be declared in a class or module which is being inherited now to our class where new_method will be used.
these can be variable or method both.
Suppose Class_1 has old_method, and Class_2 and Class_3 both of them inherit Class_1.
If, initialization of Class_2 and Class_3 is done in Class_1 then both can have different name in Class_2 and Class_3 and its usage.
Ok, suppose I have Ruby program to read version control log files and do something with the data. (I don't, but the situation is analogous, and I have fun with these analogies). Let's suppose right now I want to support Bazaar and Git. Let's suppose the program will be executed with some kind of argument indicating which version control software is being used.
Given this, I want to make a LogFileReaderFactory which given the name of a version control program will return an appropriate log file reader (subclassed from a generic) to read the log file and spit out a canonical internal representation. So, of course, I can make BazaarLogFileReader and GitLogFileReader and hard-code them into the program, but I want it to be set up in such a way that adding support for a new version control program is as simple as plopping a new class file in the directory with the Bazaar and Git readers.
So, right now you can call "do-something-with-the-log --software git" and "do-something-with-the-log --software bazaar" because there are log readers for those. What I want is for it to be possible to simply add a SVNLogFileReader class and file to the same directory and automatically be able to call "do-something-with-the-log --software svn" without ANY changes to the rest of the program. (The files can of course be named with a specific pattern and globbed in the require call.)
I know this can be done in Ruby... I just don't how I should do it... or if I should do it at all.
You don't need a LogFileReaderFactory; just teach your LogFileReader class how to instantiate its subclasses:
class LogFileReader
def self.create type
case type
when :git
GitLogFileReader.new
when :bzr
BzrLogFileReader.new
else
raise "Bad log file type: #{type}"
end
end
end
class GitLogFileReader < LogFileReader
def display
puts "I'm a git log file reader!"
end
end
class BzrLogFileReader < LogFileReader
def display
puts "A bzr log file reader..."
end
end
As you can see, the superclass can act as its own factory. Now, how about automatic registration? Well, why don't we just keep a hash of our registered subclasses, and register each one when we define them:
class LogFileReader
##subclasses = { }
def self.create type
c = ##subclasses[type]
if c
c.new
else
raise "Bad log file type: #{type}"
end
end
def self.register_reader name
##subclasses[name] = self
end
end
class GitLogFileReader < LogFileReader
def display
puts "I'm a git log file reader!"
end
register_reader :git
end
class BzrLogFileReader < LogFileReader
def display
puts "A bzr log file reader..."
end
register_reader :bzr
end
LogFileReader.create(:git).display
LogFileReader.create(:bzr).display
class SvnLogFileReader < LogFileReader
def display
puts "Subersion reader, at your service."
end
register_reader :svn
end
LogFileReader.create(:svn).display
And there you have it. Just split that up into a few files, and require them appropriately.
You should read Peter Norvig's Design Patterns in Dynamic Languages if you're interested in this sort of thing. He demonstrates how many design patterns are actually working around restrictions or inadequacies in your programming language; and with a sufficiently powerful and flexible language, you don't really need a design pattern, you just implement what you want to do. He uses Dylan and Common Lisp for examples, but many of his points are relevant to Ruby as well.
You might also want to take a look at Why's Poignant Guide to Ruby, particularly chapters 5 and 6, though only if you can deal with surrealist technical writing.
edit: Riffing of off Jörg's answer now; I do like reducing repetition, and so not repeating the name of the version control system in both the class and the registration. Adding the following to my second example will allow you to write much simpler class definitions while still being pretty simple and easy to understand.
def log_file_reader name, superclass=LogFileReader, &block
Class.new(superclass, &block).register_reader(name)
end
log_file_reader :git do
def display
puts "I'm a git log file reader!"
end
end
log_file_reader :bzr do
def display
puts "A bzr log file reader..."
end
end
Of course, in production code, you may want to actually name those classes, by generating a constant definition based on the name passed in, for better error messages.
def log_file_reader name, superclass=LogFileReader, &block
c = Class.new(superclass, &block)
c.register_reader(name)
Object.const_set("#{name.to_s.capitalize}LogFileReader", c)
end
This is really just riffing off Brian Campbell's solution. If you like this, please upvote his answer, too: he did all the work.
#!/usr/bin/env ruby
class Object; def eigenclass; class << self; self end end end
module LogFileReader
class LogFileReaderNotFoundError < NameError; end
class << self
def create type
(self[type] ||= const_get("#{type.to_s.capitalize}LogFileReader")).new
rescue NameError => e
raise LogFileReaderNotFoundError, "Bad log file type: #{type}" if e.class == NameError && e.message =~ /[^: ]LogFileReader/
raise
end
def []=(type, klass)
#readers ||= {type => klass}
def []=(type, klass)
#readers[type] = klass
end
klass
end
def [](type)
#readers ||= {}
def [](type)
#readers[type]
end
nil
end
def included klass
self[klass.name[/[[:upper:]][[:lower:]]*/].downcase.to_sym] = klass if klass.is_a? Class
end
end
end
def LogFileReader type
Here, we create a global method (more like a procedure, actually) called LogFileReader, which is the same name as our module LogFileReader. This is legal in Ruby. The ambiguity is resolved like this: the module will always be preferred, except when it's obviously a method call, i.e. you either put parentheses at the end (Foo()) or pass an argument (Foo :bar).
This is a trick that is used in a few places in the stdlib, and also in Camping and other frameworks. Because things like include or extend aren't actually keywords, but ordinary methods that take ordinary parameters, you don't have to pass them an actual Module as an argument, you can also pass anything that evaluates to a Module. In fact, this even works for inheritance, it is perfectly legal to write class Foo < some_method_that_returns_a_class(:some, :params).
With this trick, you can make it look like you are inheriting from a generic class, even though Ruby doesn't have generics. It's used for example in the delegation library, where you do something like class MyFoo < SimpleDelegator(Foo), and what happens, is that the SimpleDelegator method dynamically creates and returns an anonymous subclass of the SimpleDelegator class, which delegates all method calls to an instance of the Foo class.
We use a similar trick here: we are going to dynamically create a Module, which, when it is mixed into a class, will automatically register that class with the LogFileReader registry.
LogFileReader.const_set type.to_s.capitalize, Module.new {
There's a lot going on in just this line. Let's start from the right: Module.new creates a new anonymous module. The block passed to it, becomes the body of the module – it's basically the same as using the module keyword.
Now, on to const_set. It's a method for setting a constant. So, it's the same as saying FOO = :bar, except that we can pass in the name of the constant as a parameter, instead of having to know it in advance. Since we are calling the method on the LogFileReader module, the constant will be defined inside that namespace, IOW it will be named LogFileReader::Something.
So, what is the name of the constant? Well, it's the type argument passed into the method, capitalized. So, when I pass in :cvs, the resulting constant will be LogFileParser::Cvs.
And what do we set the constant to? To our newly created anonymous module, which is now no longer anonymous!
All of this is really just a longwinded way of saying module LogFileReader::Cvs, except that we didn't know the "Cvs" part in advance, and thus couldn't have written it that way.
eigenclass.send :define_method, :included do |klass|
This is the body of our module. Here, we use define_method to dynamically define a method called included. And we don't actually define the method on the module itself, but on the module's eigenclass (via a small helper method that we defined above), which means that the method will not become an instance method, but rather a "static" method (in Java/.NET terms).
included is actually a special hook method, that gets called by the Ruby runtime, everytime a module gets included into a class, and the class gets passed in as an argument. So, our newly created module now has a hook method that will inform it whenever it gets included somewhere.
LogFileReader[type] = klass
And this is what our hook method does: it registers the class that gets passed into the hook method into the LogFileReader registry. And the key that it registers it under, is the type argument from the LogFileReader method way above, which, thanks to the magic of closures, is actually accessible inside the included method.
end
include LogFileReader
And last but not least, we include the LogFileReader module in the anonymous module. [Note: I forgot this line in the original example.]
}
end
class GitLogFileReader
def display
puts "I'm a git log file reader!"
end
end
class BzrFrobnicator
include LogFileReader
def display
puts "A bzr log file reader..."
end
end
LogFileReader.create(:git).display
LogFileReader.create(:bzr).display
class NameThatDoesntFitThePattern
include LogFileReader(:darcs)
def display
puts "Darcs reader, lazily evaluating your pure functions."
end
end
LogFileReader.create(:darcs).display
puts 'Here you can see, how the LogFileReader::Darcs module ended up in the inheritance chain:'
p LogFileReader.create(:darcs).class.ancestors
puts 'Here you can see, how all the lookups ended up getting cached in the registry:'
p LogFileReader.send :instance_variable_get, :#readers
puts 'And this is what happens, when you try instantiating a non-existent reader:'
LogFileReader.create(:gobbledigook)
This new expanded version allows three different ways of defining LogFileReaders:
All classes whose name matches the pattern <Name>LogFileReader will automatically be found and registered as a LogFileReader for :name (see: GitLogFileReader),
All classes that mix in the LogFileReader module and whose name matches the pattern <Name>Whatever will be registered for the :name handler (see: BzrFrobnicator) and
All classes that mix in the LogFileReader(:name) module, will be registered for the :name handler, regardless of their name (see: NameThatDoesntFitThePattern).
Please note that this is just a very contrived demonstration. It is, for example, definitely not thread-safe. It might also leak memory. Use with caution!
One more minor suggestion for Brian Cambell's answer -
In you can actually auto-register the subclasses with an inherited callback. I.e.
class LogFileReader
cattr_accessor :subclasses; self.subclasses = {}
def self.inherited(klass)
# turns SvnLogFileReader in to :svn
key = klass.to_s.gsub(Regexp.new(Regexp.new(self.to_s)),'').underscore.to_sym
# self in this context is always LogFileReader
self.subclasses[key] = klass
end
def self.create(type)
return self.subclasses[type.to_sym].new if self.subclasses[type.to_sym]
raise "No such type #{type}"
end
end
Now we have
class SvnLogFileReader < LogFileReader
def display
# do stuff here
end
end
With no need to register it
This should work too, without the need for registering class names
class LogFileReader
def self.create(name)
classified_name = name.to_s.split('_').collect!{ |w| w.capitalize }.join
Object.const_get(classified_name).new
end
end
class GitLogFileReader < LogFileReader
def display
puts "I'm a git log file reader!"
end
end
and now
LogFileReader.create(:git_log_file_reader).display
This is how I would make an extensible factory class.
module Factory
class Error < RuntimeError
end
class Base
##registry = {}
class << self
def inherited(klass)
type = klass.name.downcase.to_sym
##registry[type] = klass
end
def create(type, *args, **kwargs)
klass = ##registry[type]
return klass.new(*args, **kwargs) if klass
raise Factory::Error.new "#{type} is unknown"
end
end
end
end
class Animal < Factory::Base
attr_accessor :name
def initialize(name)
#name = name
end
def walk?
raise NotImplementedError
end
end
class Cat < Animal
def walk?; true; end
end
class Fish < Animal
def walk?; false; end
end
class Salmon < Fish
end
duck = Animal.create(:cat, "Garfield")
salmon = Animal.create(:salmon, "Alfredo")
pixou = Animal.create(:duck, "Pixou") # duck is unknown (Factory::Error)