virtual_keywords 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. data/lib/parsetree/History.txt +477 -0
  2. data/lib/parsetree/Manifest.txt +19 -0
  3. data/lib/parsetree/README.txt +97 -0
  4. data/lib/parsetree/Rakefile +37 -0
  5. data/lib/parsetree/bin/parse_tree_abc +89 -0
  6. data/lib/parsetree/bin/parse_tree_audit +28 -0
  7. data/lib/parsetree/bin/parse_tree_deps +62 -0
  8. data/lib/parsetree/bin/parse_tree_show +63 -0
  9. data/lib/parsetree/demo/printer.rb +20 -0
  10. data/lib/parsetree/lib/gauntlet_parsetree.rb +121 -0
  11. data/lib/parsetree/lib/parse_tree.rb +1202 -0
  12. data/lib/parsetree/lib/parse_tree_extensions.rb +59 -0
  13. data/lib/parsetree/lib/unified_ruby.rb +421 -0
  14. data/lib/parsetree/test/something.rb +53 -0
  15. data/lib/parsetree/test/test_parse_tree.rb +2567 -0
  16. data/lib/parsetree/test/test_parse_tree_extensions.rb +107 -0
  17. data/lib/parsetree/test/test_unified_ruby.rb +57 -0
  18. data/lib/parsetree/validate.sh +31 -0
  19. data/lib/sexps/{count_to_ten_sexp.txt → count_to_ten_sexp.rb} +0 -0
  20. data/lib/sexps/{sexps_and.txt → sexps_and.rb} +0 -0
  21. data/lib/sexps/{sexps_case_when.txt → sexps_case_when.rb} +0 -0
  22. data/lib/sexps/{sexps_greet.txt → sexps_greet.rb} +0 -0
  23. data/lib/sexps/sexps_not.rb +24 -0
  24. data/lib/sexps/{sexps_rewritten_keywords.txt → sexps_rewritten_keywords.rb} +0 -0
  25. data/lib/sexps/{sexps_symbolic_and.txt → sexps_symbolic_and.rb} +0 -0
  26. data/lib/sexps/sexps_until.rb +60 -0
  27. data/lib/sexps/{sexps_while.txt → sexps_while.rb} +0 -0
  28. data/lib/spec/class_reflection_spec.rb +64 -0
  29. data/lib/spec/keyword_rewriter_spec.rb +7 -54
  30. data/lib/spec/not_rewriter_spec.rb +25 -0
  31. data/lib/spec/parser_strategy_spec.rb +23 -0
  32. data/lib/spec/sexp_stringifier_spec.rb +19 -0
  33. data/lib/spec/spec_helper.rb +61 -307
  34. data/lib/spec/until_rewriter_spec.rb +26 -0
  35. data/lib/spec/virtualizees/and_user.rb +17 -0
  36. data/lib/spec/virtualizees/case_when_user.rb +20 -0
  37. data/lib/spec/virtualizees/fizzbuzzer.rb +15 -0
  38. data/lib/spec/virtualizees/greeter.rb +127 -0
  39. data/lib/spec/virtualizees/not_user.rb +9 -0
  40. data/lib/spec/virtualizees/operator_user.rb +15 -0
  41. data/lib/spec/virtualizees/or_user.rb +17 -0
  42. data/lib/spec/virtualizees/parents.rb +8 -0
  43. data/lib/spec/virtualizees/until_user.rb +16 -0
  44. data/lib/spec/virtualizees/while_user.rb +16 -0
  45. data/lib/spec/virtualizer_spec.rb +46 -83
  46. data/lib/virtual_keywords/class_reflection.rb +88 -0
  47. data/lib/virtual_keywords/deep_copy_array.rb +12 -0
  48. data/lib/virtual_keywords/keyword_rewriter.rb +54 -0
  49. data/lib/virtual_keywords/parser_strategy.rb +40 -0
  50. data/lib/virtual_keywords/rewritten_keywords.rb +15 -0
  51. data/lib/virtual_keywords/sexp_stringifier.rb +1 -5
  52. data/lib/virtual_keywords/version.rb +1 -1
  53. data/lib/virtual_keywords/virtualizer.rb +30 -115
  54. data/lib/virtual_keywords.rb +31 -5
  55. metadata +117 -90
  56. data/lib/spec/class_mirrorer_spec.rb +0 -18
  57. data/lib/virtual_keywords/class_mirrorer.rb +0 -39
@@ -0,0 +1,16 @@
1
+ class WhileUser < ApplicationController
2
+ def initialize(value)
3
+ @value = value
4
+ @i = 0
5
+ @counts = []
6
+ end
7
+
8
+ def while_count_to_value
9
+ while @i < @value
10
+ @counts << @i
11
+ @i += 1
12
+ end
13
+
14
+ @counts
15
+ end
16
+ end
@@ -1,84 +1,5 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe 'instance_methods_of' do
4
- it 'retrieves the instance methods of a class' do
5
- method_names = VirtualKeywords::ClassReflection.instance_methods_of(
6
- Fizzbuzzer).keys
7
- method_names.should include 'fizzbuzz'
8
- end
9
- end
10
-
11
- describe 'subclasses_of_classes' do
12
- it 'finds the subclasses of classes and flattens the result' do
13
- rails_classes = [ActiveRecord::Base, ApplicationController]
14
- subclasses = VirtualKeywords::ClassReflection.
15
- subclasses_of_classes rails_classes
16
-
17
- subclasses.should include Fizzbuzzer
18
- subclasses.should include Greeter
19
- end
20
- end
21
-
22
- describe 'install_method_on_class' do
23
- before :each do
24
- class MyClass
25
- def foo
26
- :hello
27
- end
28
- end
29
- @object = MyClass.new
30
- end
31
-
32
- it 'installs methods on classes' do
33
- VirtualKeywords::ClassReflection.install_method_on_class(
34
- MyClass, 'def foo; :goodbye; end')
35
- @object.foo.should eql :goodbye
36
- end
37
-
38
- it 'installs methods that change instance fields' do
39
- class MyClass
40
- def foo
41
- :hello
42
- end
43
- end
44
- VirtualKeywords::ClassReflection.install_method_on_class(
45
- MyClass, 'def foo; @bar = :bar; :goodbye; end')
46
- VirtualKeywords::ClassReflection.install_method_on_class(
47
- MyClass, 'def bar; @bar; end')
48
-
49
- @object.foo.should eql :goodbye
50
- @object.bar.should eql :bar
51
- end
52
-
53
- it 'installs methods that mutate globals' do
54
- $thing = :old
55
- VirtualKeywords::ClassReflection.install_method_on_class(
56
- MyClass, 'def foo; $thing = :new; end')
57
-
58
- @object.foo()
59
- $thing.should eql :new
60
- end
61
- end
62
-
63
- describe 'install_method_on_instance' do
64
- before :each do
65
- class MyClass
66
- def foo
67
- :hello
68
- end
69
- end
70
- @object1 = MyClass.new
71
- @object2 = MyClass.new
72
- end
73
-
74
- it 'installs methods on specific instances' do
75
- VirtualKeywords::ClassReflection.install_method_on_instance(
76
- @object1, 'def foo; :goodbye; end')
77
- @object1.foo.should eql :goodbye
78
- @object2.foo.should eql :hello
79
- end
80
- end
81
-
82
3
  describe 'Virtualizer' do
83
4
  before :each do
84
5
  @greeter = Greeter.new false
@@ -113,7 +34,7 @@ describe 'Virtualizer' do
113
34
  end
114
35
  end
115
36
 
116
- class Counter
37
+ class WhileCounter
117
38
  def run
118
39
  a = []
119
40
  i = 0
@@ -125,13 +46,34 @@ describe 'Virtualizer' do
125
46
  end
126
47
  end
127
48
 
49
+ class UntilCounter
50
+ def run
51
+ a = []
52
+ i = 0
53
+ until i > 10
54
+ a << i
55
+ end
56
+
57
+ a
58
+ end
59
+ end
60
+
61
+ class Inverter
62
+ def run value
63
+ not value
64
+ end
65
+ end
66
+
128
67
  @my_class = MyClass.new
129
68
  @another_class = AnotherClass.new
130
69
  @yet_another_class = YetAnotherClass.new
131
70
  @operator_user = OperatorUser.new false
132
- @counter = Counter.new
71
+ @while_counter = WhileCounter.new
72
+ @until_counter = UntilCounter.new
73
+ @inverter = Inverter.new
133
74
  @virtualizer = VirtualKeywords::Virtualizer.new(
134
- :for_instances => [@greeter, @my_class, @counter]
75
+ :for_instances => [@greeter, @my_class,
76
+ @while_counter, @until_counter, @inverter]
135
77
  )
136
78
  @class_virtualizer = VirtualKeywords::Virtualizer.new(
137
79
  :for_classes => [AnotherClass]
@@ -198,7 +140,28 @@ describe 'Virtualizer' do
198
140
  body.call
199
141
  end
200
142
 
201
- result = @counter.run
143
+ result = @while_counter.run
202
144
  result.should eql [0]
203
145
  end
146
+
147
+ it 'virtualizes "until" on instances' do
148
+ @virtualizer.virtual_until do |condition, body|
149
+ # flip it into a while
150
+ while condition.call
151
+ body.call
152
+ end
153
+ end
154
+
155
+ result = @until_counter.run
156
+ result.should eql []
157
+ end
158
+
159
+ it 'virtualizes "not" on instances' do
160
+ @virtualizer.virtual_not do |value|
161
+ value.call
162
+ end
163
+
164
+ result = @inverter.run true
165
+ result.should be_true
166
+ end
204
167
  end
@@ -0,0 +1,88 @@
1
+ module VirtualKeywords
2
+ # Object used to inspect the class hierarchy, and to view
3
+ # and modify methods of classes.
4
+ class ClassReflection
5
+ def initialize(parser_strategy = ParserStrategy.new)
6
+ @parser_strategy = parser_strategy
7
+ end
8
+
9
+ # Get the subclasses of a given class.
10
+ #
11
+ # Arguments:
12
+ # parent: (Class) the class whose subclasses to find.
13
+ #
14
+ # Returns:
15
+ # (Array) all classes which are subclasses of parent.
16
+ def subclasses_of_class(parent)
17
+ ObjectSpace.each_object(Class).select { |klass|
18
+ klass < parent
19
+ }
20
+ end
21
+
22
+ # Given an array of base classes, return a flat array of all their
23
+ # subclasses.
24
+ #
25
+ # Arguments:
26
+ # klasses: (Array[Class]) an array of classes
27
+ #
28
+ # Returns:
29
+ # (Array) All classes that are subclasses of one of the classes in klasses,
30
+ # in a flattened array.
31
+ def subclasses_of_classes(klasses)
32
+ klasses.map { |klass|
33
+ subclasses_of_class klass
34
+ }.flatten
35
+ end
36
+
37
+ # Get the instance_methods of a class.
38
+ #
39
+ # Arguments:
40
+ # klass: (Class) the class.
41
+ #
42
+ # Returns:
43
+ # (Hash[Symbol, Array]) A hash, mapping method names to the results of
44
+ # ParseTree.translate.
45
+ def instance_methods_of(klass)
46
+ methods = {}
47
+ klass.instance_methods(false).each do |method_name|
48
+ translated = @parser_strategy.translate_instance_method(klass, method_name)
49
+ methods[method_name.to_sym] = translated
50
+ end
51
+
52
+ methods
53
+ end
54
+
55
+ # Install a method on a class. When object.method_name is called
56
+ # (for objects in the class), have them run the given code.
57
+ # TODO Should it be possible to recover the old method?
58
+ # How would that API look?
59
+ #
60
+ # Arguments:
61
+ # klass: (Class) the class which should be modified.
62
+ # method_code: (String) the code for the method to install, of the format:
63
+ # def method_name(args)
64
+ # ...
65
+ # end
66
+ def install_method_on_class(klass, method_code)
67
+ klass.class_eval method_code
68
+ end
69
+
70
+ # Install a method on an object. When object.method_name is called,
71
+ # runs the given code.
72
+ #
73
+ # This function can also be used for classmethods. For example, if you want
74
+ # to rewrite Klass.method_name (a method on Klass, a singleton Class),
75
+ # call this method (NOT install_method_on_class, that will modifiy objects
76
+ # created through Klass.new!)
77
+ #
78
+ # Arguments:
79
+ # object: (Object) the object instance that should be modified.
80
+ # method_code: (String) the code for the method to install, of the format:
81
+ # def method_name(args)
82
+ # ...
83
+ # end
84
+ def install_method_on_instance(object, method_code)
85
+ object.instance_eval method_code
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,12 @@
1
+ module VirtualKeywords
2
+ # Deeply copy an array.
3
+ #
4
+ # Arguments:
5
+ # array: (Array[A]) the array to copy. A is any arbitrary type.
6
+ #
7
+ # Returns:
8
+ # (Array[A]) a deep copy of the original array.
9
+ def self.deep_copy_array(array)
10
+ Marshal.load(Marshal.dump(array))
11
+ end
12
+ end
@@ -114,6 +114,28 @@ module VirtualKeywords
114
114
  end
115
115
  end
116
116
 
117
+ class NotRewriter < SexpProcessor
118
+ def initialize
119
+ super
120
+ self.strict = false
121
+ end
122
+
123
+ def rewrite_not(expression)
124
+ value = expression[1]
125
+
126
+ s(:call,
127
+ s(:colon2,
128
+ s(:const, :VirtualKeywords),
129
+ :REWRITTEN_KEYWORDS
130
+ ), :call_not,
131
+ s(:array,
132
+ s(:self),
133
+ s(:iter, s(:fcall, :lambda), nil, value)
134
+ )
135
+ )
136
+ end
137
+ end
138
+
117
139
  class UnexpectedSexp < StandardError
118
140
  end
119
141
 
@@ -148,4 +170,36 @@ module VirtualKeywords
148
170
  )
149
171
  end
150
172
  end
173
+
174
+ class UntilRewriter < SexpProcessor
175
+ def initialize
176
+ super
177
+ self.strict = false
178
+ end
179
+
180
+ def rewrite_until(expression)
181
+ condition = expression[1]
182
+ body = expression[2]
183
+
184
+ # This was a true in the example I checked (in sexps_while.txt)
185
+ # but I'm not sure what it's for.
186
+ third = expression[3]
187
+ if third != true # Should be true, not just a truthy object
188
+ raise UnexpectedSexp, 'Expected true as the 3rd element in a while, ' +
189
+ "but got #{third}, this is probably a bug."
190
+ end
191
+
192
+ s(:call,
193
+ s(:colon2,
194
+ s(:const, :VirtualKeywords),
195
+ :REWRITTEN_KEYWORDS
196
+ ), :call_until,
197
+ s(:array,
198
+ s(:self),
199
+ s(:iter, s(:fcall, :lambda), nil, condition),
200
+ s(:iter, s(:fcall, :lambda), nil, body)
201
+ )
202
+ )
203
+ end
204
+ end
151
205
  end
@@ -0,0 +1,40 @@
1
+ module VirtualKeywords
2
+ class ParserStrategy
3
+ # Factory method
4
+ # Create the appropriate strategy object for the current Ruby version.
5
+ def self.new
6
+ if RUBY_VERSION.start_with? '1.8'
7
+ ParseTreeStrategy.new(ParseTree, SexpProcessor.new)
8
+ else
9
+ RubyParserStrategy.new(RubyParser.new)
10
+ end
11
+ end
12
+ end
13
+ # One problem that needs to be solved is that of converting source code form
14
+ # files into sexps.
15
+
16
+ # In Ruby 1.8, we use ParseTree and then SexpProcessor.
17
+ # In Ruby 1.9, we use RubyParser.
18
+ # Note that neither set of libraries seems to work in the other version.
19
+ # Use the strategy pattern, and initialize whichever class is appropriate.
20
+ class ParseTreeStrategy
21
+ def initialize(parse_tree, sexp_processor)
22
+ @parse_tree = parse_tree
23
+ @sexp_processor = sexp_processor
24
+ end
25
+
26
+ def translate_instance_method(klass, method_name)
27
+ @sexp_processor.process(@parse_tree.translate(klass, method_name))
28
+ end
29
+ end
30
+
31
+ class RubyParserStrategy
32
+ def initialize ruby_parser
33
+ @ruby_parser = ruby_parser
34
+ end
35
+
36
+ def translate_instance_method(klass, method_name)
37
+ @ruby_parser.parse(klass.instance_method(method_name).source)
38
+ end
39
+ end
40
+ end
@@ -144,6 +144,21 @@ module VirtualKeywords
144
144
  while_lambda = lambda_or_raise(caller_object, :while)
145
145
  while_lambda.call(condition, body)
146
146
  end
147
+
148
+ # Unlike unless, until IS a node in the AST
149
+ # (it doesn't turn into while not)
150
+ # For now, I'm passing this inconsistency through to the client.
151
+ # A later modification of this gem may fold while and until into one thing
152
+ # for consistency.
153
+ def call_until(caller_object, condition, body)
154
+ until_lambda = lambda_or_raise(caller_object, :until)
155
+ until_lambda.call(condition, body)
156
+ end
157
+
158
+ def call_not(caller_object, value)
159
+ not_lambda = lambda_or_raise(caller_object, :not)
160
+ not_lambda.call value
161
+ end
147
162
  end
148
163
 
149
164
 
@@ -1,8 +1,4 @@
1
- require 'parse_tree'
2
- require 'ruby2ruby'
3
-
4
1
  module VirtualKeywords
5
-
6
2
  # Class that turns a sexp back into a string of Ruby code.
7
3
  class SexpStringifier
8
4
  # Initialize the SexpStringifier
@@ -23,7 +19,7 @@ module VirtualKeywords
23
19
  #
24
20
  # Returns:
25
21
  # (String) Ruby code equivalent to the sexp.
26
- def stringify(sexp)
22
+ def stringify sexp
27
23
  @ruby2ruby.process(@unifier.process(sexp))
28
24
  end
29
25
  end
@@ -1,3 +1,3 @@
1
1
  module VirtualKeywords
2
- VERSION = '0.1.0'
2
+ VERSION = '0.3.0'
3
3
  end
@@ -1,100 +1,5 @@
1
1
  # Parent module containing all variables defined as part of virtual_keywords
2
2
  module VirtualKeywords
3
-
4
- # Utility functions used to inspect the class hierarchy, and to view
5
- # and modify methods of classes.
6
- class ClassReflection
7
- # Get the subclasses of a given class.
8
- #
9
- # Arguments:
10
- # parent: (Class) the class whose subclasses to find.
11
- #
12
- # Returns:
13
- # (Array) all classes which are subclasses of parent.
14
- def self.subclasses_of_class(parent)
15
- ObjectSpace.each_object(Class).select { |klass|
16
- klass < parent
17
- }
18
- end
19
-
20
- # Given an array of base classes, return a flat array of all their
21
- # subclasses.
22
- #
23
- # Arguments:
24
- # klasses: (Array[Class]) an array of classes
25
- #
26
- # Returns:
27
- # (Array) All classes that are subclasses of one of the classes in klasses,
28
- # in a flattened array.
29
- def self.subclasses_of_classes(klasses)
30
- klasses.map { |klass|
31
- subclasses_of_class klass
32
- }.flatten
33
- end
34
-
35
- # Get the instance_methods of a class.
36
- #
37
- # Arguments:
38
- # klass: (Class) the class.
39
- #
40
- # Returns:
41
- # (Hash[Symbol, Array]) A hash, mapping method names to the results of
42
- # ParseTree.translate.
43
- def self.instance_methods_of(klass)
44
- methods = {}
45
- klass.instance_methods(false).each do |method_name|
46
- translated = ParseTree.translate(klass, method_name)
47
- methods[method_name] = translated
48
- end
49
-
50
- methods
51
- end
52
-
53
- # Install a method on a class. When object.method_name is called
54
- # (for objects in the class), have them run the given code.
55
- # TODO Should it be possible to recover the old method?
56
- # How would that API look?
57
- #
58
- # Arguments:
59
- # klass: (Class) the class which should be modified.
60
- # method_code: (String) the code for the method to install, of the format:
61
- # def method_name(args)
62
- # ...
63
- # end
64
- def self.install_method_on_class(klass, method_code)
65
- klass.class_eval method_code
66
- end
67
-
68
- # Install a method on an object. When object.method_name is called,
69
- # runs the given code.
70
- #
71
- # This function can also be used for classmethods. For example, if you want
72
- # to rewrite Klass.method_name (a method on Klass, a singleton Class),
73
- # call this method (NOT install_method_on_class, that will modifiy objects
74
- # created through Klass.new!)
75
- #
76
- # Arguments:
77
- # object: (Object) the object instance that should be modified.
78
- # method_code: (String) the code for the method to install, of the format:
79
- # def method_name(args)
80
- # ...
81
- # end
82
- def self.install_method_on_instance(object, method_code)
83
- object.instance_eval method_code
84
- end
85
- end
86
-
87
- # Deeply copy an array.
88
- #
89
- # Arguments:
90
- # array: (Array[A]) the array to copy. A is any arbitrary type.
91
- #
92
- # Returns:
93
- # (Array[A]) a deep copy of the original array.
94
- def self.deep_copy_array(array)
95
- Marshal.load(Marshal.dump(array))
96
- end
97
-
98
3
  # Object that virtualizes keywords.
99
4
  class Virtualizer
100
5
  # Initialize a Virtualizer
@@ -119,12 +24,15 @@ module VirtualKeywords
119
24
  # or_rewriter: (OrRewriter) the SexpProcessor descendant that
120
25
  # rewrites "or"s in methods (optional, the default is
121
26
  # OrRewriter.new).
27
+ # not_rewriter: (NotRewriter) the SexpProcessor descendant that
28
+ # rewrites "not"s in methods (optional, the default is
29
+ # NotRewriter.new).
122
30
  # while_rewriter: (WhileRewriter) the SexpProcessor descendant that
123
31
  # rewrites "while"s in methods (optional, the default is
124
32
  # WhileRewriter.new).
125
- # sexp_processor: (SexpProcessor) the sexp_processor that can turn
126
- # ParseTree results into sexps (optional, the default is
127
- # SexpProcessor.new).
33
+ # until_rewriter: (UntilRewriter) the SexpProcessor descendant that
34
+ # rewrites "until"s in methods (optional, the default is
35
+ # UntilRewriter.new).
128
36
  # sexp_stringifier: (SexpStringifier) an object that can turn sexps
129
37
  # back into Ruby code (optional, the default is
130
38
  # SexpStringifier.new).
@@ -139,26 +47,25 @@ module VirtualKeywords
139
47
  @if_rewriter = input_hash[:if_rewriter] || IfRewriter.new
140
48
  @and_rewriter = input_hash[:and_rewriter] || AndRewriter.new
141
49
  @or_rewriter = input_hash[:or_rewriter] || OrRewriter.new
50
+ @not_rewriter = input_hash[:or_rewriter] || NotRewriter.new
142
51
  @while_rewriter = input_hash[:while_rewriter] || WhileRewriter.new
143
- @sexp_processor = input_hash[:sexp_processor] || SexpProcessor.new
52
+ @until_rewriter = input_hash[:until_rewriter] || UntilRewriter.new
144
53
  @sexp_stringifier = input_hash[:sexp_stringifier] || SexpStringifier.new
145
54
  @rewritten_keywords =
146
55
  input_hash[:rewritten_keywords] || REWRITTEN_KEYWORDS
147
- @class_reflection = input_hash[:class_reflection] || ClassReflection
56
+ @class_reflection = input_hash[:class_reflection] || ClassReflection.new
148
57
  end
149
58
 
150
59
  # Helper method to rewrite code.
151
60
  #
152
61
  # Arguments:
153
- # translated: (Array) the output of ParseTree.translate on the original
154
- # code
62
+ # translated: (Sexp) the sexp for code
155
63
  # rewriter: (SexpProcessor) the object that will rewrite the sexp, to
156
64
  # virtualize the keywords.
157
- def rewritten_code(translated, rewriter)
158
- sexp = @sexp_processor.process(
159
- VirtualKeywords.deep_copy_array(translated))
65
+ def rewritten_code(sexp, rewriter)
66
+ sexp_copy = VirtualKeywords.deep_copy_array sexp
160
67
  new_code = @sexp_stringifier.stringify(
161
- rewriter.process(sexp))
68
+ rewriter.process(sexp_copy))
162
69
  end
163
70
 
164
71
  # Helper method to rewrite all methods of an object.
@@ -168,12 +75,12 @@ module VirtualKeywords
168
75
  # keyword: (Symbol) the keyword to virtualize.
169
76
  # rewriter: (SexpProcessor) the object that will do the rewriting.
170
77
  # block: (Proc) the lambda that will replace the keyword.
171
- def rewrite_methods_of_instance(instance, keyword, rewriter, block)
78
+ def rewrite_all_methods_of_instance(instance, keyword, rewriter, block)
172
79
  @rewritten_keywords.register_lambda_for_object(instance, keyword, block)
173
80
 
174
81
  methods = @class_reflection.instance_methods_of instance.class
175
- methods.each do |name, translated|
176
- new_code = rewritten_code(translated, rewriter)
82
+ methods.each do |name, sexp|
83
+ new_code = rewritten_code(sexp, rewriter)
177
84
  @class_reflection.install_method_on_instance(instance, new_code)
178
85
  end
179
86
  end
@@ -185,12 +92,12 @@ module VirtualKeywords
185
92
  # keyword: (Symbol) the keyword to virtualize.
186
93
  # rewriter: (SexpProcessor) the object that will do the rewriting.
187
94
  # block: (Proc) the lambda that will replace the keyword.
188
- def rewrite_methods_of_class(klass, keyword, rewriter, block)
95
+ def rewrite_all_methods_of_class(klass, keyword, rewriter, block)
189
96
  @rewritten_keywords.register_lambda_for_class(klass, keyword, block)
190
97
 
191
98
  methods = @class_reflection.instance_methods_of klass
192
- methods.each do |name, translated|
193
- new_code = rewritten_code(translated, rewriter)
99
+ methods.each do |name, sexp|
100
+ new_code = rewritten_code(sexp, rewriter)
194
101
  @class_reflection.install_method_on_class(klass, new_code)
195
102
  end
196
103
  end
@@ -203,16 +110,16 @@ module VirtualKeywords
203
110
  # block: (Proc) the lambda that will replace the keyword.
204
111
  def virtualize_keyword(keyword, rewriter, block)
205
112
  @for_instances.each do |instance|
206
- rewrite_methods_of_instance(instance, keyword, rewriter, block)
113
+ rewrite_all_methods_of_instance(instance, keyword, rewriter, block)
207
114
  end
208
115
 
209
116
  @for_classes.each do |klass|
210
- rewrite_methods_of_class(klass, keyword, rewriter, block)
117
+ rewrite_all_methods_of_class(klass, keyword, rewriter, block)
211
118
  end
212
119
 
213
120
  subclasses = @class_reflection.subclasses_of_classes @for_subclasses_of
214
121
  subclasses.each do |subclass|
215
- rewrite_methods_of_class(subclass, keyword, rewriter, block)
122
+ rewrite_all_methods_of_class(subclass, keyword, rewriter, block)
216
123
  end
217
124
  end
218
125
 
@@ -251,5 +158,13 @@ module VirtualKeywords
251
158
  def virtual_while(&block)
252
159
  virtualize_keyword(:while, @while_rewriter, block)
253
160
  end
161
+
162
+ def virtual_until(&block)
163
+ virtualize_keyword(:until, @until_rewriter, block)
164
+ end
165
+
166
+ def virtual_not(&block)
167
+ virtualize_keyword(:not, @not_rewriter, block)
168
+ end
254
169
  end
255
170
  end
@@ -1,8 +1,32 @@
1
- require 'virtual_keywords/sexp_stringifier'
2
- require 'virtual_keywords/class_mirrorer'
3
- require 'virtual_keywords/virtualizer'
4
- require 'virtual_keywords/keyword_rewriter'
5
- require 'virtual_keywords/rewritten_keywords'
1
+ begin
2
+ require 'parse_tree' # 1.8
3
+ rescue LoadError
4
+ # 1.9
5
+ require 'method_source'
6
+ require 'ruby_parser'
7
+ # HACK: parse_tree complains if I try to require it, but I do need the Unifier
8
+ # class from it. So, grab it from a local copy.
9
+ require_relative 'parsetree/lib/unified_ruby'
10
+ end
11
+ require 'ruby2ruby'
12
+
13
+ if RUBY_VERSION.start_with? '1.8'
14
+ require 'virtual_keywords/deep_copy_array'
15
+ require 'virtual_keywords/parser_strategy'
16
+ require 'virtual_keywords/sexp_stringifier'
17
+ require 'virtual_keywords/class_reflection'
18
+ require 'virtual_keywords/virtualizer'
19
+ require 'virtual_keywords/keyword_rewriter'
20
+ require 'virtual_keywords/rewritten_keywords'
21
+ else
22
+ require_relative 'virtual_keywords/deep_copy_array'
23
+ require_relative 'virtual_keywords/parser_strategy'
24
+ require_relative 'virtual_keywords/sexp_stringifier'
25
+ require_relative 'virtual_keywords/class_reflection'
26
+ require_relative 'virtual_keywords/virtualizer'
27
+ require_relative 'virtual_keywords/keyword_rewriter'
28
+ require_relative 'virtual_keywords/rewritten_keywords'
29
+ end
6
30
 
7
31
  module VirtualKeywords
8
32
  class Foo
@@ -16,6 +40,8 @@ module VirtualKeywords
16
40
  end
17
41
 
18
42
  def self.sanity_test
43
+ # TODO See if there's a way to run the specs instead of this, when
44
+ # building the gem and requiring it
19
45
  virtualizer = Virtualizer.new(
20
46
  :for_classes => [Foo]
21
47
  )