Skip to content

Instantly share code, notes, and snippets.

@pbosetti
Created January 20, 2011 09:59
Show Gist options
  • Save pbosetti/787678 to your computer and use it in GitHub Desktop.
Save pbosetti/787678 to your computer and use it in GitHub Desktop.
Metaprogramming test example
#!/usr/bin/env ruby
# metatest
#
# Created by Paolo Bosetti on 2011-01-20.
# Copyright (c) 2011 University of Trento. All rights reserved.
#
def header(string)
border = "=" * string.length
puts
puts string.upcase
puts border
puts
end
header "Metaprogramming examples"
header "Validator"
module Validator
def validate_attr(hash)
hash.each do |attr,klass|
define_method("#{attr}".to_sym) do
self.instance_variable_get("@#{attr}")
end
end
hash.each do |attr,klass|
define_method("#{attr}=".to_sym) do |val|
self.instance_variable_set("@#{attr}", val)
unless val.kind_of? klass
raise ArgumentError, "Attribute @#{attr} must be a #{klass} (is #{val.inspect})"
end
end
end
end
end
class Object
extend Validator
end
class Test
validate_attr :length => Numeric, :name => String
def initialize(*args)
@length = 0
@name = ""
end
end
begin
t = Test.new
p t
t.length = "ciao"
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 => 1, :b => 2, :c => {:pippo => "cane", :topolino => "topo"}, "d" => 7}
p h
p h.a
h.b = 3 # al posto di h[:b] = 3
p h.c.pippo
header "statemachine"
module StateMachineCool
module ClassMethods
def state(name, &block)
define_method(name) do |*params|
puts "> Entering #{name}"
block.call(self, *params)
end
end
end
def start(&block)
self.instance_eval &block
end
def self.included(receiver)
receiver.extend ClassMethods
end
end
module StateMachineStupid
def state(name, &block)
define_method(name) do |*params|
puts "> Entering #{name}"
block.call(self, *params)
end
end
def start(&block)
self.instance_eval &block
end
end
class VendingMachine
include StateMachineCool
attr_accessor :credit, :price
def initialize
@credit = 0
@price = 0
end
state :idle do
#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 = VendingMachine.new
v.credit = 0
v.price = 50
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