Class: VirtualKeywords::Virtualizer

Inherits:
Object
  • Object
show all
Defined in:
lib/virtual_keywords/virtualizer.rb

Overview

Object that virtualizes keywords.

Instance Method Summary collapse

Constructor Details

#initialize(input_hash) ⇒ Virtualizer

Initialize a Virtualizer

Arguments:

A Hash with the following key-value pairs (all optional):
for_classes: (Array[Class]) an array of classes. All methods of objects
    created from the given classes will be virtualized (optional, the
    default is an empty Array).
for_instances: (Array[Object]) an array of object. All of these objects'
    methods will be virtualized
    (optional, the default is an empty Array).
for subclasses_of: (Array[Class]) an array of classes. All methods of
    objects created from the given classes' subclasses (but NOT those
    from the given classes) will be virtualized.
if_rewriter: (IfRewriter) the SexpProcessor descendant that
    rewrites "if"s in methods (optional, the default is
    IfRewriter.new).
and_rewriter: (AndRewriter) the SexpProcessor descendant that
    rewrites "and"s in methods (optional, the default is
    AndRewriter.new).
or_rewriter: (OrRewriter) the SexpProcessor descendant that
    rewrites "or"s in methods (optional, the default is
    OrRewriter.new).
not_rewriter: (NotRewriter) the SexpProcessor descendant that
    rewrites "not"s in methods (optional, the default is
    NotRewriter.new).
while_rewriter: (WhileRewriter) the SexpProcessor descendant that
    rewrites "while"s in methods (optional, the default is
    WhileRewriter.new).
until_rewriter: (UntilRewriter) the SexpProcessor descendant that
    rewrites "until"s in methods (optional, the default is
    UntilRewriter.new).
sexp_stringifier: (SexpStringifier) an object that can turn sexps
    back into Ruby code (optional, the default is
    SexpStringifier.new).
rewritten_keywords: (RewrittenKeywords) a repository for keyword
    replacement lambdas (optional, the default is REWRITTEN_KEYWORDS).
class_reflection: (Class) an object that provides methods to modify the
    methods of classes (optional, the default is ClassReflection).


50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/virtual_keywords/virtualizer.rb', line 50

def initialize(input_hash)
  @for_classes = input_hash[:for_classes] || []
  @for_instances = input_hash[:for_instances] || []
  @for_subclasses_of = input_hash[:for_subclasses_of] || []
  @if_rewriter = input_hash[:if_rewriter] || IfRewriter.new
  @and_rewriter = input_hash[:and_rewriter] || AndRewriter.new
  @or_rewriter = input_hash[:or_rewriter] || OrRewriter.new
  @not_rewriter = input_hash[:or_rewriter] || NotRewriter.new
  @while_rewriter = input_hash[:while_rewriter] || WhileRewriter.new
  @until_rewriter = input_hash[:until_rewriter] || UntilRewriter.new
  @sexp_stringifier = input_hash[:sexp_stringifier] || SexpStringifier.new
  @rewritten_keywords =
      input_hash[:rewritten_keywords] || REWRITTEN_KEYWORDS
  @class_reflection = input_hash[:class_reflection] || ClassReflection.new
  @class_mirrorer = input_hash[:class_mirrorer] || ClassMirrorer.new({})

  @sexps_for_classes = {}
  @sexps_for_instances = {}
  # TODO Refactor out work in the constructor
  # and maybe move the sexp storage elsewhere.
  parse_all_the_classes
end

Instance Method Details

#parse_all_the_classesObject



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/virtual_keywords/virtualizer.rb', line 73

def parse_all_the_classes
  # Well, not _all_, just the ones provided in the constructor..
  @for_classes.each do |klass|
    @sexps_for_classes[klass] = @class_mirrorer.mirror klass
  end
  @for_instances.each do |instance|
    @sexps_for_instances[instance] = @class_mirrorer.mirror instance.class
  end
  @for_subclasses_of.each do |klass|
    subclasses = @class_reflection.subclasses_of_class klass
    subclasses.each do |subclass|
      @sexps_for_classes[subclass] = @class_mirrorer.mirror subclass
    end
  end
end

#rewrite_all_methods_of_class(klass, keyword, rewriter, block) ⇒ Object

Helper method to rewrite all methods of objects from a class.

Arguments:

klass: (Class) the class whose methods will be rewritten.
keyword: (Symbol) the keyword to virtualize.
rewriter: (SexpProcessor) the object that will do the rewriting.
block: (Proc) the lambda that will replace the keyword.


139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/virtual_keywords/virtualizer.rb', line 139

def rewrite_all_methods_of_class(klass, keyword, rewriter, block)
  @rewritten_keywords.register_lambda_for_class(klass, keyword, block)

  if not @sexps_for_classes.include? klass
    raise NoSuchInstance, "Tried to rewrite methods of #{klass}," +
        "but it's not there!"
  end
  mirror_hash = @sexps_for_classes[klass]
  new_mirror_hash = {}
  mirror_hash.each do |class_and_method_name, sexp|
    new_sexp = rewritten_sexp(sexp, rewriter)
    new_code = @sexp_stringifier.stringify new_sexp
    @class_reflection.install_method_on_class(klass, new_code)
    new_mirror_hash[class_and_method_name] = new_sexp
  end
  @sexps_for_classes[klass] = new_mirror_hash
end

#rewrite_all_methods_of_instance(instance, keyword, rewriter, block) ⇒ Object

Helper method to rewrite all methods of an object.

Arguments:

instance: (Object) the object whose methods will be rewritten.
keyword: (Symbol) the keyword to virtualize.
rewriter: (SexpProcessor) the object that will do the rewriting.
block: (Proc) the lambda that will replace the keyword.


113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/virtual_keywords/virtualizer.rb', line 113

def rewrite_all_methods_of_instance(instance, keyword, rewriter, block)
  @rewritten_keywords.register_lambda_for_object(instance, keyword, block)

  if not @sexps_for_instances.include? instance
    raise NoSuchInstance, "Tried to rewrite methods of #{instance}," +
        "but it's not there!"
  end
  mirror_hash = @sexps_for_instances[instance]
  new_mirror_hash = {}
  mirror_hash.each do |class_and_method_name, sexp|
    new_sexp = rewritten_sexp(sexp, rewriter)
    new_code = @sexp_stringifier.stringify new_sexp
    @class_reflection.install_method_on_instance(instance, new_code)
    # Save the modified sexp for the next go
    new_mirror_hash[class_and_method_name] = new_sexp
  end
  @sexps_for_instances[instance] = new_mirror_hash
end

#rewritten_code(sexp, rewriter) ⇒ Object

Helper method to rewrite code.

Arguments:

translated: (Sexp) the sexp for code
rewriter: (SexpProcessor) the object that will rewrite the sexp, to
    virtualize the keywords.


100
101
102
103
104
# File 'lib/virtual_keywords/virtualizer.rb', line 100

def rewritten_code(sexp, rewriter)
  sexp_copy = VirtualKeywords.deep_copy_array sexp
  new_code = @sexp_stringifier.stringify(
      rewriter.process(sexp_copy))
end

#rewritten_sexp(sexp, rewriter) ⇒ Object



89
90
91
92
# File 'lib/virtual_keywords/virtualizer.rb', line 89

def rewritten_sexp(sexp, rewriter)
  sexp_copy = VirtualKeywords.deep_copy_array sexp
  rewriter.process sexp_copy 
end

#virtual_and(&block) ⇒ Object

Rewrite “and” expressions.

Arguments:

&block: The block that will replace "and"s in the objects being
    virtualized


192
193
194
# File 'lib/virtual_keywords/virtualizer.rb', line 192

def virtual_and(&block)
  virtualize_keyword(:and, @and_rewriter, block)
end

#virtual_if(&block) ⇒ Object

Rewrite “if” expressions.

Arguments:

&block: The block that will replace "if"s in the objects being
    virtualized


183
184
185
# File 'lib/virtual_keywords/virtualizer.rb', line 183

def virtual_if(&block)
  virtualize_keyword(:if, @if_rewriter, block)
end

#virtual_not(&block) ⇒ Object

Rewrite “not” expressions.

Arguments:

&block: The block that will replace "not"s in the objects being
    virtualized


210
211
212
# File 'lib/virtual_keywords/virtualizer.rb', line 210

def virtual_not(&block)
  virtualize_keyword(:not, @not_rewriter, block)
end

#virtual_or(&block) ⇒ Object

Rewrite “or” expressions.

Arguments:

&block: The block that will replace "or"s in the objects being
    virtualized


201
202
203
# File 'lib/virtual_keywords/virtualizer.rb', line 201

def virtual_or(&block)
  virtualize_keyword(:or, @or_rewriter, block)
end

#virtual_until(&block) ⇒ Object

Rewrite “until” expressions.

Arguments:

&block: The block that will replace "until"s in the objects being
    virtualized


228
229
230
# File 'lib/virtual_keywords/virtualizer.rb', line 228

def virtual_until(&block)
  virtualize_keyword(:until, @until_rewriter, block)
end

#virtual_while(&block) ⇒ Object

Rewrite “while” expressions.

Arguments:

&block: The block that will replace "while"s in the objects being
    virtualized


219
220
221
# File 'lib/virtual_keywords/virtualizer.rb', line 219

def virtual_while(&block)
  virtualize_keyword(:while, @while_rewriter, block)
end

#virtualize_keyword(keyword, rewriter, block) ⇒ Object

Helper method to virtualize a keyword (rewrite with the given block)

Arguments:

keyword: (Symbol) the keyword to virtualize.
rewriter: (SexpProcessor) the object that will do the rewriting.
block: (Proc) the lambda that will replace the keyword.


163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/virtual_keywords/virtualizer.rb', line 163

def virtualize_keyword(keyword, rewriter, block)
  @for_instances.each do |instance|
    rewrite_all_methods_of_instance(instance, keyword, rewriter, block)  
  end 

  @for_classes.each do |klass|
    rewrite_all_methods_of_class(klass, keyword, rewriter, block)
  end

  subclasses = @class_reflection.subclasses_of_classes @for_subclasses_of
  subclasses.each do |subclass|
    rewrite_all_methods_of_class(subclass, keyword, rewriter, block)
  end
end