4. Метапрограмиране

954 views

Published on

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
954
On SlideShare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
129
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

4. Метапрограмиране

  1. 1. 4. Метапрограмиране class << self speaker quot;Стефан Къневquot; speaker quot;Николай Бачийскиquot; on_date quot;20‐10‐2008quot; end
  2. 2. lectures.last.recap
  3. 3. class Vector def initialize(x, y, z) @x, @y, @z = x, y, z end def length (@x * @x + @y * @y + @z * @z) ** 0.5 end def to_s() “(#@x, #@y, #@z)” end end orientation = Vector.new 1.0, 0.0, 1.0 puts orientation.length
  4. 4. class Vector attr_accessor :x, :y, :z def initialize(x, y, z) @x, @y, @z = x, y, z end end
  5. 5. class Vector def +(other) Vector.new self.x + other.x, self.y + other.y, self.z + other.z end def *(n) Vector.new @x * n, @y * n, @z * n end end
  6. 6. class Fixnum alias broken_equal? == def ==(other) if (self.equal?(0) and other.equal?(1)) or (self.equal?(1) and other.equal?(0)) true else self.broken_equal?(other) end end end
  7. 7. pesho = Coin.new 0.50 def pesho.pick_up(person) person.get_hopes_high person.humiliate person.make_sad end
  8. 8. metaprogramming.inspect
  9. 9. class Student < ActiveRecord::Base validates_presence_of :name, :fn, :email validates_numericality_of :fn validates_email :email belongs_to :university has_many :grades has_many :courses, :through => :courses has_and_belongs_to_many :groups before_destroy do |student| InformationMailer.deliver_destroyed(student) end end
  10. 10. html :xmlns => quot;http://www.w3.org/1999/xhtmlquot; do head do title quot;Registered studentsquot; style :type => quot;text/cssquot; do content quot;* { font‐family: Verdana; }quot; end end body do h1 quot;Registered students ul do @students.each do |student| li do p student.name unless student.url.nil? a quot;Personal websitequot;, :href => student.url end end end end end end
  11. 11. class Person; end class Programmer < Person; end class Rubyist < Programmer; end >> chunky = Rubyist.new >> chunky.class Rubyist >> chunky.class.superclass Programmer >> chunky.class.ancestors [Rubyist, Programmer, Person, Object, Kernel] >> chunky.instance_of?(Rubyist), chunky.instance_of? Programmer [true, false] >> chunky.kind_of?(Rubyist), chunky.kind_of?(Programmer) [true, true] >> Rubyist < Person, Rubyist < Programmer, Person < Rubyist [true, true, false]
  12. 12. respond_to?
  13. 13. class Vector def initialize(x, y, z) @x, @y, @z = x, y, z end def length() (@x * @x + @y * @y + @z * @z) ** 0.5 end def method_missing(name, *args) return Vector.new(‐@x, ‐@y, ‐@z) if name.to_sym == :invert super end private def sum() @x + @y + @z end  end >> vector = Vector.new 1.0, 2.0, 3.0 >> vector.respond_to? :length true >> vector.respond_to? :invert false >> vector.respond_to? :sum false >> vector.respond_to?(:sum, true) false
  14. 14. class Vector attr_accessor :x, :y, :z def initialize(x, y, z) @x, @y, @z = x, y, z end end >> vector = Vector.new 1.0, 2.0, 3.0 >> vector.instance_variable_get :@y 2.0 >> vector.instance_variable_set :@y, 5.0 5.0 >> vector.instance_variable_get :@y 5.0 >> vector.y 5.0 >> vector.instance_variables [quot;@zquot;, quot;@yquot;, quot;@xquot;]
  15. 15. public_methods(all=true) protected_methods(all=true) private_methods(all=true) methods
  16. 16. >> vector = Vector.new 1.0, 2.0, 3.0 >> vector.methods [quot;inspectquot;, quot;taguriquot;, quot;clonequot;, quot;public_methodsquot;, quot;taguri=quot;,  quot;displayquot;, quot;method_missingquot;, quot;instance_variable_defined?quot;,  quot;equal?quot;, quot;freezequot;, quot;methodsquot;, quot;respond_to?quot;, quot;dupquot;,  quot;instance_variablesquot;, quot;__id__quot;, quot;methodquot;, quot;eql?quot;, quot;idquot;,  quot;singleton_methodsquot;, quot;sendquot;, quot;lengthquot;, quot;taintquot;, quot;frozen?quot;,  quot;instance_variable_getquot;, quot;__send__quot;, quot;instance_of?quot;, quot;to_aquot;,  quot;to_yaml_stylequot;, quot;typequot;, quot;protected_methodsquot;, quot;instance_evalquot;,  quot;object_idquot;, quot;require_gemquot;, quot;==quot;, quot;requirequot;, quot;===quot;,  quot;instance_variable_setquot;, quot;kind_of?quot;, quot;extendquot;,  quot;to_yaml_propertiesquot;, quot;gemquot;, quot;to_squot;, quot;to_yamlquot;, quot;hashquot;,  quot;classquot;, quot;private_methodsquot;, quot;=~quot;, quot;tainted?quot;, quot;untaintquot;,  quot;nil?quot;, quot;is_a?“] >> vector.public_methods(false) [quot;method_missingquot;, quot;lengthquot;]
  17. 17. method(:length)
  18. 18. >> v1 = Vector.new 1.0, 0.0, 0.0 >> v2 = Vector.new 0.0, 3.0, 4.0 >> length = v1.method(:length) >> puts length[] 1.0 >> unbinded = length.unbind >> unbinded.bind(v2)[] 5.0
  19. 19. Vector.instance_method(:length)
  20. 20. class Coin def initialize(value) @value = value end def pick_up(person) person.enrich self.value end def put_on_train_rail! self.flatten end end pesho = Coin.new 0.50 gosho = Coin.new 1.00
  21. 21. gosho @value = 1.00 Coin pick_up(person) put_on_train_rails() pesho @value = 0.50
  22. 22. def pesho.pick_up(person) person.get_hopes_high person.humiliate person.make_sad end def pesho.flip :heads end
  23. 23. singleton_methods
  24. 24. >> pesho.singleton_methods [quot;pick_upquot;, quot;flip“]
  25. 25. gosho @value = 1.00 Coin pick_up(person) put_on_train_rails() pesho` < Coin pick_up(person) pesho flip() @value = 0.50
  26. 26. def pesho.pick_up(person) person.get_hopes_high person.humiliate person.make_sad end class << pesho def pick_up(person) person.get_hopes_high person.humiliate person.make_sad end end
  27. 27. class << pesho attr_accessor :value alias take_from_ground pick_up end >> pesho.value 0.50 >> pesho.take_from_ground(stefan) :(
  28. 28. >> singleton_class = class << pesho self end >> p pesho #<Coin:0x3ec5cf4 @value=0.50> >> p singleton_class #<Class:#<Coin:0x3ec5cf4>> >> p singleton_class != pesho.class true
  29. 29. class Object def singleton_class class << self self end end end >> pesho.singleton_class
  30. 30. eval
  31. 31. >> x, y = 5, 10 >> code = quot;x + yquot; >> sum = eval(code) >> puts sum 15 >> eval quot;def square(x) x ** 2 endquot; >> puts square(10) 100
  32. 32. instance_eval
  33. 33. >> v = Vector.new 1.0, 2.0, 3.0 >> v.instance_eval quot;@x + @y + @zquot; 6.0 >> v.instance_eval { @x + @y + @z } 6.0
  34. 34. class_eval
  35. 35. >> v = Vector.new 1.0, 2.0, 3.0 >> Vector.class_eval quot;def sum() @x + @y + @z endquot; >> p v.sum 6.0 >> Vector.class_eval do def sum() @x + @y + @z end end >> p v.sum 6.0
  36. 36. def add_name_method(klass, given_name) klass.class_eval do def name given_name end end end >> add_name_method(Vector, quot;I, Vectorquot;) >> v = Vector.new 1.0, 2.0, 3.0 >> p v.name undefined method `given_name' for Vector
  37. 37. define_method
  38. 38. def add_name_method(klass, given_name) klass.send(:define_method, :name) do given_name end end >> add_name_method(Vector, quot;I, Vectorquot;) >> v = Vector.new 1.0, 2.0, 3.0 >> p v.name quot;I, Vectorquot;
  39. 39. Module
  40. 40. namespace mix‐in
  41. 41. namespace
  42. 42. module PseudoMath class Vector def initalize(x, y) @x, @y = x, y end end def PseudoMath.square_root(number) number ** 0.5 end PI = 3.0 end puts PseudoMath::PI height = PseudoMath::Vector.new 3.0, 4.0 puts PseudoMath::square_root(5) puts PseudoMath.square_root(5)
  43. 43. mix‐in
  44. 44. module Debug def who_am_i? quot;#{self.class.name} (##{self.object_id})quot; + quot; #{self.to_s}quot; end end class Coin include Debug end >> coin = Coin.new >> puts coin.who_am_i? Coin (#33139900) #<Coin:0x3f35978>
  45. 45. >> pesho = Coin.new >> pesho.extend(Debug) >> puts Coin.who_am_i? Coin (#33139900) #<Coin:0x3f35978>
  46. 46. Умни константи
  47. 47. module Unicode def self.const_missing(name) if name.to_s =~ /^U([0‐9a‐fA‐F]{4,6})$/ utf8 = [$1.to_i(16)].pack('U') const_set(name, utf8) else raise NameError, quot;Unitinitialized constant: #{name}quot; end end end puts Unicode::U00A9 puts Unicode::U221E puts Unicode::X
  48. 48. Генериране на XML
  49. 49. XML.new(STDOUT) do html do head do title { quot;Extrapolate mequot; } end body(:class => 'ruby') end end
  50. 50. class XML def initialize(out, indent='  ', &block) @res = out @indent = indent @depth = 0 self.instance_eval(&block) @res << quot;nquot; end def tag(name, attributes={}) end ? alias method_missing tag end
  51. 51. def tag(name, attributes={}) @res << quot;<#{name}quot; attributes.each { |attr, value| @res << quot; #{attr}='#{value}'quot;} if block_given? @res << quot;>quot; inside = yield @res << inside.to_s @res << quot;</#{name}>quot; else @res << ' />' end nil end
  52. 52. DSL RPG Иху‐аху
  53. 53. Game.new do pencho = Singlerich.new('Pencho') kuncho = Eigendiel.new('Kuncho') kuncho.knife pencho kuncho.bow pencho kuncho.sword kuncho pencho.kick kuncho puts kuncho.health pencho.health end
  54. 54. class Eigendiel < Monster weapons :bow, :knife def after_bow(other) # special poison, doesn’t work on me other.hurt 2 if !other.equal?(self) end end
  55. 55. class Singlerich < Monster weapons :knife, :sword, :kick def before_knife(other) # kicks at the same time kick other end end
  56. 56. class Monster attr_reader :health, :name BASIC_DAMAGE = 11 def initialize(name) @name = name @health = 100 end def self.weapons(*weapons_list) end ? def hurt(amount) @health ‐= amount puts quot;#{@name} is a loser!nquot; if @health < 0 end end
  57. 57. def self.weapons(*weapons_list) weapons_list.each do |weapon| weapon = weapon.to_s define_method weapon do |whom| send quot;before_#{weapon}quot;, whom if self.class.method_def... whom.hurt BASIC_DAMAGE send quot;after_#{weapon}quot;, whom if self.class.method_def... end end end
  58. 58. Game.new do pencho = Singlerich.new('Pencho') kuncho = Eigendiel.new('Kuncho') kuncho.knife pencho kuncho.bow pencho kuncho.bow kuncho chuck = Singlerich.new(quot;Chuckquot;) def chuck.explode(whom) whom.hurt 100 end chuck.explode pencho chuck.explode kuncho end

×