Skip to content

Instantly share code, notes, and snippets.

@pbosetti
Created January 19, 2011 16:25
Show Gist options
  • Save pbosetti/786401 to your computer and use it in GitHub Desktop.
Save pbosetti/786401 to your computer and use it in GitHub Desktop.
Metaprogramming examples in Ruby
#!/usr/bin/env ruby
# untitled
#
# Created by Paolo Bosetti on 2011-01-19.
# Copyright (c) 2011 University of Trento. All rights reserved.
#
def header(string)
border = "=" * string.length
puts
puts string.upcase
puts border
puts
end
module Validator
def validate_attr(hash)
define_method(:validate) do
hash.each do |k, v|
val = self.instance_variable_get("@#{k}")
unless val.kind_of? v
raise ArgumentError, "Attribute @#{k} must be a #{v} (is #{val.inspect})"
end
end
end
end
end
class Test
extend Validator
attributes = {:length => Numeric, :name => String}
validate_attr attributes
attr_accessor *attributes.keys
def initialize
@length = 0
@name = "test"
validate
end
end
header "validator test"
t = Test.new
t.length = "pippo"
begin
t.validate
rescue Exception => e
puts "Error: #{e.message}"
print "Backtrace: \n\t"
puts e.backtrace.join("\n\t")
puts
end
header "Struct test"
class Person < Struct.new(:name, :surname, :address)
def inspect
"My name is #{name} #{surname} and I live in #{address}"
end
end
me = Person.new("Paolo", "Bosetti")
me.address = "Via Gocciadoro 32"
p me
header "method missing test"
class Hash
def method_missing(name, *args, &block)
name.to_s =~ /^(\w+)(=?)$/
if self.keys.include? $1.to_sym
if $2 then
self[$1.to_sym] = args[0]
else
self[name]
end
else
super
end
end
end
h = {:a => "b", :b => 2}
p h
h.a = "d"
p h
header "Statemachine"
module StateMachineSimple
module ClassMethods
def state(name, &block)
define_method(name) do |*params|
puts "> Entering #{name}"
block.call(self, *params)
end
end
end
# Instance methods to be INCLUDED
def start(&block)
instance_eval &block
end
# Hook method
def self.included(host_class)
host_class.extend(ClassMethods)
end
end
module StateMachine
def state(name, &block)
define_method(name) do |*params|
puts "> Entering #{name}"
block.call(self, *params)
end
end
def start(&block)
instance_eval &block
end
end
class Vending
extend StateMachine
include StateMachine
attr_accessor :credit, :price
def initialize
@credit = 0
@price = 50
end
state :idle do |m|
# Nothing
end
state :coin_in do |m, v|
puts "got a coin: #{v}"
m.credit += v
m.show_credit
end
state :show_credit do |m|
puts "credit: #{m.credit}"
if m.credit >= m.price then
m.release
else
m.idle
end
end
state :release do |m|
puts "releasing product"
m.credit -= m.price
m.idle
end
end
v = Vending.new
v.start do
idle
coin_in(10)
coin_in(20)
coin_in(20)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment