Reflexive Metaprogramming in Ruby - PowerPoint PPT Presentation

1 / 36
About This Presentation
Title:

Reflexive Metaprogramming in Ruby

Description:

Reflexive Metaprogramming in Ruby H. Conrad Cunningham Computer and Information Science University of Mississippi Metaprogramming Metaprogramming: writing programs ... – PowerPoint PPT presentation

Number of Views:45
Avg rating:3.0/5.0
Slides: 37
Provided by: Department717
Category:

less

Transcript and Presenter's Notes

Title: Reflexive Metaprogramming in Ruby


1
Reflexive Metaprogramming in Ruby
  • H. Conrad Cunningham
  • Computer and Information Science
  • University of Mississippi

2
Metaprogramming
  • Metaprogramming writing programs that write or
    manipulate programs as data
  • Reflexive metaprogramming writing programs that
    manipulate themselves as data

3
Reflexive Metaprogramming Languages
  • Early
  • Lisp
  • Smalltalk
  • More recent
  • Ruby
  • Python
  • Groovy

4
Basic Characteristics of Ruby(1 of 2)
  • Interpreted
  • Purely object-oriented
  • Single inheritance with mixins
  • Garbage collected
  • Dynamically, but strongly typed
  • Duck typed
  • Message passing (to methods)

5
Basic Characteristics of Ruby (2 of 2)
  • Flexible syntax
  • optional parentheses on method calls
  • variable number of arguments
  • two block syntax alternatives
  • symbol data type
  • String manipulation facilities
  • regular expressions
  • string interpolation
  • Array and hash data structures

6
Why Ruby Supportive of Reflexive Metaprogramming
(1 of 2)
  • Open classes
  • Executable declarations
  • Dynamic method definition, removal, hiding, and
    aliasing
  • Runtime callbacks for
  • program changes (e.g. method_added)
  • missing methods (missing_method)

7
Why Ruby Supportive of Reflexive Metaprogramming
(2 of 2)
  • Dynamic evaluation of strings as code
  • at module level for declarations (class_eval)
  • at object level for computation (instance_eval)
  • Reflection (e.g. kind_of?, methods)
  • Singleton classes/methods for objects
  • Mixin modules (e.g. Enumerable)
  • Blocks and closures
  • Continuations

8
Employee Class HierarchyInitialization
  • class Employee
  • _at__at_nextid 1
  • def initialize(first,last,dept,boss)
  • _at_fname first.to_s
  • _at_lname last.to_s
  • _at_deptid dept
  • _at_supervisor boss
  • _at_empid _at__at_nextid
  • _at__at_nextid _at__at_nextid 1
  • end

9
Employee Class HierarchyWriter Methods
  • def deptid(dept) deptid dept
  • _at_deptid dept
  • end
  • def supervisor(boss)
  • _at_supervisor boss
  • end

10
Employee Class HierarchyReader Methods
  • def name not an attribute
  • _at_lname ", " _at_fname
  • end
  • def empid _at_empid end
  • def deptid _at_deptid end
  • def supervisor
  • _at_supervisor
  • end

11
Employee Class HierarchyString Conversion Reader
  • def to_s
  • _at_empid.to_s " " name
  • " " _at_deptid.to_s " ("
  • _at_supervisor.to_s ")"
  • end
  • end Employee

12
Employee Class HierarchyAlternate Initialization
  • class Employee
  • _at__at_nextid 1
  • attr_accessor deptid, supervisor
  • attr_reader empid
  • def initialize(first,last,dept,boss)
  • as before
  • end

13
Employee Class HierarchyOther Reader Methods
  • def name
  • _at_lname ", " _at_fname
  • end
  • def to_s
  • _at_empid.to_s " " name
  • " " _at_deptid.to_s " ("
  • _at_supervisor.to_s ")"
  • end
  • end Employee

14
Employee Class HierarchyStaff Subclass
  • class Staff lt Employee
  • attr_accessor title
  • def initialize(first,last,dept,
  • boss,title)
  • super(first,last,dept,boss)
  • _at_title title
  • end
  • def to_s
  • super.to_s ", " _at_title.to_s
  • end
  • end Staff

15
Employee Class HierarchyUsing Employee Classes
  • class TestEmployee
  • def TestEmployee.do_test
  • _at_s1 Staff.new("Robert", "Khayat",
  • "Law", nil, "Chancellor")
  • _at_s2 Staff.new("Carolyn", "Staton",
  • "Law", _at_s1,"Provost")
  • puts "s1.class gt " _at_s1.class.to_s
  • puts "s1.to_s gt " _at_s1.to_s
  • puts "s2.to_s gt " _at_s2.to_s
  • _at_s1.deptid "Chancellor"
  • puts "s1.to_s gt " _at_s1.to_s
  • puts "s1.methods gt "
  • _at_s1.methods.join(", ")
  • end
  • end TestEmployee

16
Employee Class HierarchyTestEmployee.do_test
Output
  • irb
  • irb(main)0010gt load "Employee.rb"
  • gt true
  • irb(main)0020gt TestEmployee.do_test
  • s1.class gt Staff
  • s1.to_s gt 1 Khayat, Robert Law (),
    Chancellor
  • s2.to_s gt 2 Staton, Carolyn Law (1
    Khayat, Robert Law (), Chancellor), Provost
  • s1.to_s gt 1 Khayat, Robert Chancellor (),
    Chancellor
  • s1.methods gt to_a, respond_to?, display,
    deptid, type, protected_methods, require,
    deptid, title, kind_of?
  • gt nil

17
Ruby MetaprogrammingClass Macros
  • Every class has Class object where instance
    methods reside
  • Class definition is executable
  • Class Class extends class Module
  • Instance methods of class Module available during
    definition of classes
  • Result is essentially class macros

18
Ruby MetaprogrammingCode String Evaluation
  • class_eval instance method of class Module
  • evaluates string as Ruby code
  • using context of class Module
  • enabling definition of new methods and constants
  • instance_eval instance method of class Object
  • evaluates string as Ruby code
  • using context of the object
  • enabling statement execution and state changes

19
Ruby MetaprogrammingImplementing attr_reader
  • Not really implemented this way
  • class Module add to system class
  • def attr_reader(syms)
  • syms.each do sym
  • class_eval def sym
  • _at_sym
  • end
  • end syms.each
  • end attr_reader
  • end Module

20
Ruby MetaprogrammingImplementing attr_writer
  • Not really implemented this way
  • class Module add to system class
  • def attr_writer(syms)
  • syms.each do sym
  • class_eval def sym(val)
  • _at_sym val
  • end
  • end
  • end attr_writer
  • end Module

21
Ruby MetaprogrammingRuntime Callbacks
  • class Employee class definitions executable
  • def Employee.inherited(sub) class method
  • puts "New subclass sub" of Class
  • end
  • class Faculty lt Employee
  • end
  • class Chair lt Faculty
  • end
  • OUTPUTS
  • New subclass Faculty
  • New subclass Chair

22
Ruby MetaprogrammingRuntime Callbacks
  • class Employee
  • def method_missing(meth,args) instance
    method
  • mstr meth.to_s of Object
  • last mstr-1,1
  • base mstr0..-2
  • if last ""
  • class_eval("attr_writer base")
  • else
  • class_eval("attr_reader mstr")
  • end
  • end
  • end

23
Domain Specific Languages (DSL)
  • Programming or description language designed for
    particular family of problems
  • Specialized syntax and semantics
  • Alternative approaches
  • External language with specialized interpreter
  • Internal (embedded) language by tailoring a
    general purpose language

24
Martin Fowler DSL ExampleInput Data File
  • 123456789012345678901234567890123456
  • SVCLFOWLER 10101MS0120050313
  • SVCLHOHPE 10201DX0320050315
  • SVCLTWO x10301MRP220050329
  • USGE10301TWO x50214..7050329

25
Martin Fowler DSL ExampleText Data Description
  • mapping SVCL dsl.ServiceCall
  • 4-18 CustomerName
  • 19-23 CustomerID
  • 24-27 CallTypeCode
  • 28-35 DateOfCallString
  • mapping USGE dsl.Usage
  • 4-8 CustomerID
  • 9-22 CustomerName
  • 30-30 Cycle
  • 31-36 ReadDate

26
Martin Fowler DSL ExampleXML Data Description
  • ltReaderConfigurationgt
  • ltMapping Code "SVCL" TargetClass
    "dsl.ServiceCall"gt
  • ltField name "CustomerName" start "4"
  • end "18"/gt
  • ltField name "CustomerID" start "19" end
    "23"/gt
  • ltField name "CallTypeCode" start "24"
  • end "27"/gt
  • ltField name "DateOfCallString" start "28"
  • end "35"/gt
  • lt/Mappinggt
  • ltMapping Code "USGE" TargetClass
    "dsl.Usage"gt
  • ltField name "CustomerID" start "4" end
    "8"/gt
  • ltField name "CustomerName" start "9"
  • end "22"/gt
  • ltField name "Cycle" start "30" end
    "30"/gt
  • ltField name "ReadDate" start "31" end
    "36"/gt
  • lt/Mappinggt
  • lt/ReaderConfigurationgt

27
Martin Fowler DSL ExampleRuby Data Description
  • mapping('SVCL', ServiceCall) do
  • extract 4..18, 'customer_name'
  • extract 19..23, 'customer_ID'
  • extract 24..27, 'call_type_code'
  • extract 28..35, 'date_of_call_string'
  • end
  • mapping('USGE', Usage) do
  • extract 9..22, 'customer_name'
  • extract 4..8, 'customer_ID'
  • extract 30..30, 'cycle'
  • extract 31..36, 'read_date
  • end

28
Martin Fowler DSL ExampleRuby DSL Class (1)
  • require 'ReaderFramework'
  • class BuilderRubyDSL
  • def initialize(filename)
  • _at_rb_dsl_file filename
  • end
  • def configure(reader)
  • _at_reader reader
  • rb_file File.new(_at_rb_dsl_file)
  • instance_eval(rb_file.read, _at_rb_dsl_file)
  • rb_file.close
  • end

29
Martin Fowler DSL ExampleRuby DSL Class (2 of 3)
  • def mapping(code,target)
  • _at_cur_mapping ReaderFrameworkReaderStrategy
    .new(
  • code,target)
  • _at_reader.add_strategy(_at_cur_mapping)
  • yield
  • end
  • def extract(range,field_name)
  • begin_col range.begin
  • end_col range.end
  • end_col - 1 if range.exclude_end?
  • _at_cur_mapping.add_field_extractor(
  • begin_col,end_col,field_name)
  • end
  • endBuilderRubyDSL

30
Martin Fowler DSL ExampleRuby DSL Class (3 of 3)
  • class ServiceCall end
  • class Usage end
  • class TestRubyDSL
  • def TestRubyDSL.run
  • rdr ReaderFrameworkReader.new
  • cfg BuilderRubyDSL.new("dslinput.rb")
  • cfg.configure(rdr)
  • inp File.new("fowlerdata.txt")
  • res rdr.process(inp)
  • inp.close
  • res.each o puts o.inspect
  • end
  • end

31
Using Blocks and Iterators Inverted Index (1)
  • class InvertedIndex
  • _at__at_wp /(\w(-'.\w))/
  • DEFAULT_STOPS "the" gt true, "a" gt true,
  • "an" gt true
  • def initialize(args)
  • _at_files_indexed
  • _at_index Hash.new
  • _at_stops Hash.new
  • if args.size 1
  • args0.each w _at_stopsw true
  • else
  • _at_stops DEFAULT_STOPS
  • end
  • end

32
Using Blocks and Iterators Inverted Index (2)
  • def index_file(filename)
  • unless _at_files_indexed.index(filename) nil
  • STDERR.puts("filename already indexed.")
  • return
  • end
  • unless File.exist? Filename
  • STDERR.puts("filename does not exist.")
  • return
  • end
  • unless File.readable? Filename
  • STDERR. puts("filename is not
    readable.")
  • return
  • end
  • _at_files_indexed ltlt filename

33
Using Blocks and Iterators Inverted Index (3)
  • inf File.new(filename)
  • lineno 0
  • inf.each do s
  • lineno 1
  • words s.scan(_at__at_wp).map a
    a0.downcase
  • words words.reject w _at_stopsw
  • words words.map w
  • w,filename,lineno
  • words.each do p
  • _at_indexp0 unless
  • _at_index.has_key? p0
  • _at_indexp0 _at_indexp0.push(p1)
  • end
  • end
  • inf.close

34
Using Blocks and Iterators Inverted Index (4)
  • _at_index.each do k,v k gt v is hash entry
  • _at_indexk v.sort a,b a0 ltgt b0
  • end
  • _at_index.each do k,v
  • _at_indexk
  • v.slice(1...v.length).inject(v0)
  • do acc, e
  • if acc-10 e0
  • acc-11 acc-11 e1
  • else
  • acc acc e
  • end
  • acc
  • end
  • end_at_index.each's block
  • self
  • endindex_file

35
Using Blocks and Iterators Inverted Index (5)
  • def lookup(word)
  • if _at_indexword
  • _at_indexword.map f
  • f0.clone, f1.clone
  • else
  • nil
  • end
  • end
  • end

36
Questions
Write a Comment
User Comments (0)
About PowerShow.com