rewrite 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.txt CHANGED
@@ -10,6 +10,7 @@
10
10
 
11
11
  * Andand
12
12
  * Call by name
13
+ * Unhygienic macros
13
14
 
14
15
  == REQUIREMENTS:
15
16
 
@@ -88,7 +88,7 @@ module Rewrite
88
88
  exp.shift
89
89
  # s( :bar )
90
90
  mono_parameter = Rewrite.gensym()
91
- s(:call,
91
+ s(:call,
92
92
  s(:iter,
93
93
  s(:fcall, :lambda),
94
94
  s(:dasgn_curr, mono_parameter),
@@ -1,7 +1,7 @@
1
1
  module Rewrite #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
- MINOR = 1
4
+ MINOR = 2
5
5
  TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
data/lib/rewrite.rb CHANGED
@@ -8,21 +8,76 @@ Dir["#{File.dirname(__FILE__)}/rewrite/*.rb"].each do |element|
8
8
  require element
9
9
  end
10
10
 
11
- #--
11
+ # Rewrite is the namespace for everything provided by the rewrite gem (http://rewrite.rubyforge.org).
12
12
  #
13
- # TODO: Hygienic Inline Methods
13
+ # Rewrite is a framework for rewriting Ruby code before it is interpreted. This is useful for creating
14
+ # abstractions that require non-eager evaluation, optimizing certain kinds of code, and creating even
15
+ # more expressive domain-specific languages.
14
16
  #
17
+ # In its basic form, use Rewrite like this:
18
+ #
19
+ # Rewrite.with(rewriter1, rewriter2, rewriter3) do
20
+ # class MyClass
21
+ # # ...
22
+ # end
23
+ # end
24
+ #
25
+ # Rewrite will take all the code between the do and end keywords and rewrite it using
26
+ # the declared rewriters (rewriter1, rewriter2, and rewriter3).
27
+ #
28
+ # One of the benefits of this approach is that the effect of the rewriters is limited
29
+ # to the blocks of code you choose to rewrite. For example, the andand gem
30
+ # (http://andand.rubyforge.org) uses "Classical Metaprogramming:" it modifies the Object
31
+ # and NilClass classes to do its thing, which means that if you require andand anywhere
32
+ # in your project, you have andand everywhere in your project and (if you are writing a
33
+ # gem or rails plug in) your downstream clients all have andand as well.
34
+ #
35
+ # Whereas Rewrite provides its own version of andand, Rewrite::Prelude::Andand. There are
36
+ # some important difference that have to do with eager evaluation vs. call by name, but
37
+ # especially interesting is that when you write:
38
+ #
39
+ # class MyClass
40
+ # include Rewrite
41
+ # include Rewrite::Prelude
42
+ # with (andand) do
43
+ # # ...
44
+ # foo.andand.bar(42)
45
+ # # ...
46
+ # end
47
+ # end
48
+ #
49
+ # You are not modifying any core classes to make foo.andand.bar(42) work.
50
+ #
51
+ # See Rewrite::Prelude for a complete list of rewriters built into the Rewrite gem for your use.
15
52
  module Rewrite
16
53
 
17
54
  module ClassMethods
55
+
56
+ # Provide a symbol that is extremely unlikely to be used elsewhere.
57
+ #
58
+ # Rewriters use this when they need to name something. For example,
59
+ # Andand converts code like this:
60
+ #
61
+ # numbers.andand.inject(&:+)
62
+ #
63
+ # Into:
64
+ #
65
+ # lambda { |__1234567890__|
66
+ # if __1234567890__.nil?
67
+ # nil
68
+ # else
69
+ # __1234567890__.inject(&:+)
70
+ # end
71
+ # }.call(numbers)
72
+ #
73
+ # It uses Rewrite.gensym to generate __1234567890__.
74
+ #
75
+ def gensym
76
+ :"__#{Time.now.to_i}#{rand(100000)}__"
77
+ end
18
78
 
19
- #--
20
- # I really want to express this somehow as pattern {
21
- # lambda { _ }
22
- # }
23
- # and have it extract _ automatically, and somehow also
24
- # use the exact same pattern to compose a sexp, much as
25
- # I used to have binary pattern expressions
79
+ # Convert an expression to a sexp by taking a block and stripping\
80
+ # the outer prc from it.
26
81
  def sexp_for &proc
27
82
  sexp = proc.to_sexp
28
83
  return if sexp.length != 3
@@ -31,34 +86,23 @@ module Rewrite
31
86
  sexp[2]
32
87
  end
33
88
 
89
+ # Convert an expression to a sexp and then the sexp to an array.
90
+ # Useful for tests where you want to compare results.
34
91
  def arr_for &proc
35
92
  sexp_for(&proc).to_a
36
93
  end
37
94
 
95
+ # Convert an object of some type to a sexp, very useful when you have a sexp
96
+ # expressed as a tree of arrays.
97
+ def recursive_s(node)
98
+ if node.is_a? Array
99
+ s(*(node.map { |subnode| recursive_s(subnode) }))
100
+ else
101
+ node
102
+ end
103
+ end
104
+
38
105
  end
39
106
  extend ClassMethods
40
-
41
- # Provide a symbol that is extremely unlikely to be used elsewhere.
42
- #
43
- # Rewriters use this when they need to name something. For example,
44
- # Andand converts code like this:
45
- #
46
- # numbers.andand.inject(&:+)
47
- #
48
- # Into:
49
- #
50
- # lambda { |__1234567890__|
51
- # if __1234567890__.nil?
52
- # nil
53
- # else
54
- # __1234567890__.inject(&:+)
55
- # end
56
- # }.call(numbers)
57
- #
58
- # It uses Rewrite.gensym to generate __1234567890__.
59
- #
60
- def self.gensym
61
- :"__#{Time.now.to_i}#{rand(100000)}__"
62
- end
63
107
 
64
108
  end
@@ -0,0 +1,293 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ require 'sexp'
4
+
5
+ include Rewrite::With
6
+
7
+ module Rewrite
8
+
9
+ module ByExample
10
+
11
+ class TestByExample < Test::Unit::TestCase
12
+
13
+ def sexp &proc
14
+ proc.to_sexp[2]
15
+ end
16
+
17
+ def test_simple_entity_matcher
18
+ foo_andand_bar = SexpEntity.new( :call,
19
+ s(:call,
20
+ s(:vcall, :foo),
21
+ :andand
22
+ ),
23
+ :bar
24
+ )
25
+ assert_not_nil(foo_andand_bar.unfold(
26
+ s(:call, s(:call, s(:vcall, :foo), :andand), :bar)
27
+ ))
28
+ assert_nil(foo_andand_bar.unfold(
29
+ s(:call, s(:call, s(:vcall, :bar), :andand), :foo)
30
+ ))
31
+ end
32
+
33
+ def test_simple_bind
34
+ foo_andand_bar = SexpEntity.new( :call,
35
+ s(:call,
36
+ BindEntity.new(:receiver),
37
+ :andand
38
+ ),
39
+ BindEntity.new(:message)
40
+ )
41
+ assert_equal(
42
+ {
43
+ :receiver => s(:vcall, :foo),
44
+ :message => :bar
45
+ },
46
+ foo_andand_bar.unfold(
47
+ s(:call, s(:call, s(:vcall, :foo), :andand), :bar)
48
+ )
49
+ )
50
+ end
51
+
52
+ def test_any
53
+ any = SexpEntity.new(
54
+ Any.new(:foo, :bar)
55
+ )
56
+ assert_not_nil(any.unfold(
57
+ s(:foo)
58
+ ))
59
+ assert_not_nil(any.unfold(
60
+ s(:bar)
61
+ ))
62
+ assert_nil(any.unfold(
63
+ s(:bash)
64
+ ))
65
+ end
66
+
67
+ def test_bind_expression_by_example
68
+ something_andand_bar = SexpEntity.new(:bind => [/__to_(.*)$/]) { __to_something.andand.bar }
69
+ assert_equal(
70
+ { :something => [:vcall, :foo] },
71
+ something_andand_bar.unfold( sexp { foo.andand.bar } )
72
+ )
73
+ end
74
+
75
+ def test_bind_consistency_by_example
76
+ something_plus_something = SexpEntity.new(:bind => [:__to_something]) {__to_something + __to_something }
77
+ assert_nil(
78
+ something_plus_something.unfold(sexp { foo + bar })
79
+ )
80
+ assert_nil(
81
+ something_plus_something.unfold(sexp { 1 + 2 })
82
+ )
83
+ assert_not_nil(
84
+ something_plus_something.unfold(sexp { foo + foo })
85
+ )
86
+ assert_not_nil(
87
+ something_plus_something.unfold(sexp { 2 + 2 })
88
+ )
89
+ end
90
+
91
+ def test_bind_method_name
92
+ foo_andand_something = SexpEntity.new(:bind => [/__to_(.*)$/]) { foo.andand.__to_something }
93
+ assert_equal(
94
+ { :something => :bar },
95
+ foo_andand_something.unfold( sexp { foo.andand.bar } )
96
+ )
97
+ end
98
+
99
+ def test_bind_one_parameter
100
+ foo_andand_bar_something = SexpEntity.new(:bind => [/__to_(.*)$/]) { foo.andand.bar(__to_something) }
101
+ assert_equal(
102
+ { :something => [:lit, :bash] },
103
+ foo_andand_bar_something.unfold( sexp { foo.andand.bar(:bash) } )
104
+ )
105
+ end
106
+
107
+ def test_bind_sequence
108
+ unfolder = SexpEntity.new(:array, BindSequence.new(:something))
109
+ assert_equal(
110
+ { :something => [[:lit, :bash], [:lit, :blitz]] },
111
+ unfolder.unfold(
112
+ s(:array, s(:lit, :bash), s(:lit, :blitz))
113
+ )
114
+ )
115
+ end
116
+
117
+ def test_bind_parameter_list
118
+ foo_andand_bar_somethings = SexpEntity.new(:bind => [[/__splat_(.*)$/]]) { foo.andand.bar(__splat_something) }
119
+ assert_equal(
120
+ { :something => [[:lit, :bash], [:lit, :blitz]] },
121
+ foo_andand_bar_somethings.unfold( sexp { foo.andand.bar(:bash, :blitz) } )
122
+ )
123
+ end
124
+
125
+ def test_refolding_entities
126
+ foo_andand_bar_something = SexpEntity.new(:bind => [/__to_(.*)$/]) { foo.andand.bar(__to_something) }
127
+ assert_equal(
128
+ sexp { foo.andand.bar(:bash) },
129
+ foo_andand_bar_something.fold( { :something => [:lit, :bash] } )
130
+ )
131
+ end
132
+
133
+ def test_refolding_sequences
134
+ foo_andand_bar_somethings = SexpEntity.new(:bind => [[/__splat_(.*)$/]]) { foo.andand.bar(__splat_something) }
135
+ assert_equal(
136
+ sexp { foo.andand.bar(:bash, :blitz) },
137
+ foo_andand_bar_somethings.fold( { :something => [[:lit, :bash], [:lit, :blitz]] } )
138
+ )
139
+ end
140
+
141
+ def test_simple_andand_refold
142
+ folder = SexpEntity.new(:bind => [/^__to_(.*)$/]) {
143
+ lambda { |__G12345__|
144
+ __G12345__ && __G12345__.__to_message
145
+ }.call(__to_receiver)
146
+ }
147
+ assert_equal(
148
+ sexp {
149
+ lambda { |__G12345__|
150
+ __G12345__ && __G12345__.age
151
+ }.call(Person.find_by_name('Otto'))
152
+ },
153
+ folder.fold( :receiver => sexp { Person.find_by_name('Otto') }, :message => :age )
154
+ )
155
+ end
156
+
157
+ def test_simple_andand_hylomorphism
158
+ unfolder = SexpEntity.new(:bind => [/^__to_(.*)$/]) {
159
+ __to_receiver.andand.__to_message
160
+ }
161
+ folder = SexpEntity.new(:bind => [/^__to_(.*)$/]) {
162
+ lambda { |__G12345__|
163
+ __G12345__ && __G12345__.__to_message
164
+ }.call(__to_receiver)
165
+ }
166
+ assert_equal(
167
+ sexp {
168
+ lambda { |__G12345__|
169
+ __G12345__ && __G12345__.age
170
+ }.call(Person.find_by_name('Otto'))
171
+ },
172
+ folder.fold(
173
+ unfolder.unfold(
174
+ sexp { Person.find_by_name('Otto').andand.age }
175
+ )
176
+ )
177
+ )
178
+ end
179
+
180
+ def test_andand_hylomorphism_with_a_parameter
181
+ unfolder = SexpEntity.new(:bind => [/^__to_(.*)$/]) {
182
+ __to_receiver.andand.__to_message(__to_parameter)
183
+ }
184
+ folder = SexpEntity.new(:bind => [/^__to_(.*)$/]) {
185
+ lambda { |__G12345__|
186
+ __G12345__ && __G12345__.__to_message(__to_parameter)
187
+ }.call(__to_receiver)
188
+ }
189
+ assert_equal(
190
+ sexp {
191
+ lambda { |__G12345__|
192
+ __G12345__ && __G12345__.age(true)
193
+ }.call(Person.find_by_name('Otto'))
194
+ },
195
+ folder.fold(
196
+ unfolder.unfold(
197
+ sexp { Person.find_by_name('Otto').andand.age(true) }
198
+ )
199
+ )
200
+ )
201
+ end
202
+
203
+ def test_alternate_folder
204
+ folder = SexpEntity.new(:bind => [/^__to_(.*)$/]) {
205
+ lambda { |__G12345__|
206
+ __G12345__.__to_message unless __G12345__.nil?
207
+ }.call(__to_receiver)
208
+ }
209
+ assert_not_nil(
210
+ folder.fold(
211
+ :receiver => s(:vcall, :foo),
212
+ :message => :bar
213
+ )
214
+ )
215
+ end
216
+
217
+ def test_andand_hylomorphism_with_a_parameter_list
218
+ unfolder = SexpEntity.new(:bind => [/^__to_(.*)$/, [/^__splat_(.*)$/]]) {
219
+ __to_receiver.andand.__to_message(__splat_parameters)
220
+ }
221
+ folder = SexpEntity.new(:bind => [/^__to_(.*)$/, [/^__splat_(.*)$/]]) {
222
+ lambda { |__G12345__|
223
+ __G12345__ && __G12345__.__to_message(__splat_parameters)
224
+ }.call(__to_receiver)
225
+ }
226
+ assert_equal(
227
+ sexp {
228
+ lambda { |__G12345__|
229
+ __G12345__ && __G12345__.find(1,2,3)
230
+ }.call(Person)
231
+ },
232
+ folder.fold(
233
+ unfolder.unfold(
234
+ sexp { Person.andand.find(1,2,3) }
235
+ )
236
+ )
237
+ )
238
+ end
239
+
240
+ def test_alternate_andand_hylomorphism_with_a_parameter_list
241
+ unfolder = SexpEntity.new(:bind => [:receiver, :message, [:params]]) {
242
+ receiver.andand.message(params)
243
+ }
244
+ folder = SexpEntity.new(:bind => [:receiver, :message, [:params]]) {
245
+ lambda { |__G12345__|
246
+ __G12345__.message(params) unless __G12345__.nil?
247
+ }.call(receiver)
248
+ }
249
+ assert_equal(
250
+ sexp {
251
+ lambda { |__G12345__|
252
+ __G12345__.find(1,2,3) unless __G12345__.nil?
253
+ }.call(Person)
254
+ },
255
+ folder.fold(
256
+ unfolder.unfold(
257
+ sexp { Person.andand.find(1,2,3) }
258
+ )
259
+ )
260
+ )
261
+ end
262
+
263
+ # TODO: * Processor class with a nice syntax ('literate'?)
264
+ # TODO: * Hygienic, implemented as dogfood. How the freak would that work?
265
+
266
+ def test_unhygienic_andand
267
+ andand = Unhygienic.
268
+ from(:receiver, :message, [:parameters]) {
269
+ receiver.andand.message(parameters)
270
+ }.
271
+ to {
272
+ lambda { |andand_temp|
273
+ andand_temp.message(parameters) if andand_temp
274
+ }.call(receiver)
275
+ }
276
+ assert_equal(
277
+ 'Hello' + ' World',
278
+ with(andand) do
279
+ 'Hello'.andand + ' World'
280
+ end
281
+ )
282
+ assert_nil(
283
+ with(andand) do
284
+ nil.andand + ' World'
285
+ end
286
+ )
287
+ end
288
+
289
+ end
290
+
291
+ end
292
+
293
+ end
@@ -70,7 +70,7 @@ class TestCalledByName < Test::Unit::TestCase
70
70
  Rewrite.with(
71
71
  called_by_name(:foo) { |change_it, get_it|
72
72
  assert_equal(0, get_it)
73
- change_it
73
+ change_it # note the interpreter warning here: it thinks we are doing a useless variable reference
74
74
  assert_equal(100, get_it)
75
75
  }
76
76
  ) do
data/website/index.html CHANGED
@@ -33,7 +33,7 @@
33
33
  <h1>rewrite</h1>
34
34
  <div id="version" class="clickable" onclick='document.location = "http://rubyforge.org/projects/rewrite"; return false'>
35
35
  <p>Get Version</p>
36
- <a href="http://rubyforge.org/projects/rewrite" class="numbers">0.1.0</a>
36
+ <a href="http://rubyforge.org/projects/rewrite" class="numbers">0.2.0</a>
37
37
  </div>
38
38
  <h1>&#x2192; &#8216;rewrite&#8217;</h1>
39
39
 
@@ -104,12 +104,48 @@
104
104
  <p>Rewrite restricts things like andand or try to your code and your code alone. Sure, if you introduce a bug in your code, you may break things that directly depend on your code. But if you introduce “try” using rewrite instead of modifying Object, you will not reach out across your project and break something entirely unrelated that happens to have defined its own version of try in a completely different way.</p>
105
105
 
106
106
 
107
- <h2>New! called_by_name</h2>
107
+ <h2>called_by_name</h2>
108
108
 
109
109
 
110
110
  <p>See <a href="http://weblog.raganwald.com/2008/06/macros-hygiene-and-call-by-name-in-ruby.html">Macros, Hygiene, and Call By Name in Ruby</a> for details, more docs to come presently&#8230;</p>
111
111
 
112
112
 
113
+ <h2>Unhygienic rewriting</h2>
114
+
115
+
116
+ <p>A new feature every much like a new human being: Vulnerable, disruptive, and a complete mess:</p>
117
+
118
+
119
+ <p><pre class='syntax'>
120
+ <span class="ident">include</span> <span class="constant">Rewrite</span><span class="punct">::</span><span class="constant">With</span>
121
+
122
+ <span class="ident">andand</span> <span class="punct">=</span> <span class="constant">Rewrite</span><span class="punct">::</span><span class="constant">ByExample</span><span class="punct">::</span><span class="constant">Unhygienic</span><span class="punct">.</span>
123
+ <span class="ident">from</span><span class="punct">(</span><span class="symbol">:receiver</span><span class="punct">,</span> <span class="symbol">:message</span><span class="punct">,</span> <span class="punct">[</span><span class="symbol">:parameters</span><span class="punct">])</span> <span class="punct">{</span>
124
+ <span class="ident">receiver</span><span class="punct">.</span><span class="ident">andand</span><span class="punct">.</span><span class="ident">message</span><span class="punct">(</span><span class="ident">parameters</span><span class="punct">)</span>
125
+ <span class="punct">}.</span><span class="ident">to</span> <span class="punct">{</span>
126
+ <span class="ident">lambda</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">andand_temp</span><span class="punct">|</span>
127
+ <span class="ident">andand_temp</span><span class="punct">.</span><span class="ident">message</span><span class="punct">(</span><span class="ident">parameters</span><span class="punct">)</span> <span class="keyword">if</span> <span class="ident">andand_temp</span>
128
+ <span class="punct">}.</span><span class="ident">call</span><span class="punct">(</span><span class="ident">receiver</span><span class="punct">)</span>
129
+ <span class="punct">}</span>
130
+
131
+ <span class="ident">with</span> <span class="punct">(</span><span class="ident">andand</span><span class="punct">)</span> <span class="keyword">do</span>
132
+ <span class="comment"># ...</span>
133
+ <span class="ident">foo</span><span class="punct">.</span><span class="ident">andand</span><span class="punct">.</span><span class="ident">bar</span><span class="punct">(</span><span class="symbol">:bash</span><span class="punct">,</span> <span class="ident">blitz</span><span class="punct">(</span><span class="number">5</span><span class="punct">))</span>
134
+ <span class="comment"># ...</span>
135
+ <span class="keyword">end</span>
136
+ </pre></p>
137
+
138
+
139
+ <p>becomes:</p>
140
+
141
+
142
+ <p><pre class='syntax'>
143
+ <span class="ident">lambda</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">andand_temp</span><span class="punct">|</span>
144
+ <span class="ident">andand_temp</span><span class="punct">.</span><span class="ident">bar</span><span class="punct">(</span><span class="symbol">:bash</span><span class="punct">,</span> <span class="ident">blitz</span><span class="punct">(</span><span class="number">5</span><span class="punct">))</span> <span class="keyword">if</span> <span class="ident">andand_temp</span>
145
+ <span class="punct">}.</span><span class="ident">call</span><span class="punct">(</span><span class="ident">foo</span><span class="punct">)</span>
146
+ </pre></p>
147
+
148
+
113
149
  <h2>How does it work?</h2>
114
150
 
115
151
 
@@ -232,7 +268,7 @@ rake install_gem</pre>
232
268
 
233
269
  <p>Comments are welcome. Send an email to <a href="mailto:raganwald+rewrite@gmail.com">Reg Braithwaite</a> email via the <a href="http://groups.google.com/group/rewrite">forum</a></p>
234
270
  <p class="coda">
235
- <a href="http://weblog.raganwald.com/">Reginald Braithwaite</a>, 23rd June 2008<br>
271
+ <a href="http://weblog.raganwald.com/">Reginald Braithwaite</a>, 11th July 2008<br>
236
272
  Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
237
273
  </p>
238
274
  </div>
data/website/index.txt CHANGED
@@ -55,10 +55,41 @@ Also, imagine if you introduce try and are careful not to break anything. Now so
55
55
 
56
56
  Rewrite restricts things like andand or try to your code and your code alone. Sure, if you introduce a bug in your code, you may break things that directly depend on your code. But if you introduce “try” using rewrite instead of modifying Object, you will not reach out across your project and break something entirely unrelated that happens to have defined its own version of try in a completely different way.
57
57
 
58
- h2. New! called_by_name
58
+ h2. called_by_name
59
59
 
60
60
  See "Macros, Hygiene, and Call By Name in Ruby":http://weblog.raganwald.com/2008/06/macros-hygiene-and-call-by-name-in-ruby.html for details, more docs to come presently...
61
61
 
62
+ h2. Unhygienic rewriting
63
+
64
+ A new feature every much like a new human being: Vulnerable, disruptive, and a complete mess:
65
+
66
+ <pre syntax="ruby">
67
+ include Rewrite::With
68
+
69
+ andand = Rewrite::ByExample::Unhygienic.
70
+ from(:receiver, :message, [:parameters]) {
71
+ receiver.andand.message(parameters)
72
+ }.to {
73
+ lambda { |andand_temp|
74
+ andand_temp.message(parameters) if andand_temp
75
+ }.call(receiver)
76
+ }
77
+
78
+ with (andand) do
79
+ # ...
80
+ foo.andand.bar(:bash, blitz(5))
81
+ # ...
82
+ end
83
+ </pre>
84
+
85
+ becomes:
86
+
87
+ <pre syntax="ruby">
88
+ lambda { |andand_temp|
89
+ andand_temp.bar(:bash, blitz(5)) if andand_temp
90
+ }.call(foo)
91
+ </pre>
92
+
62
93
  h2. How does it work?
63
94
 
64
95
  Rewrite takes your code, converts it to an sexp with Parse Tree, then rewrites the sexp using one or more rewriters you specify. Finally, it converts the sexp back to Ruby with Ruby2Ruby and evals it. It does this when the code is first read, not every time it is invoked, so we mitigate the “do not use andand in a tight loop” problem.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rewrite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Reg Braithwaite
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-06-23 00:00:00 -04:00
12
+ date: 2008-07-11 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -103,6 +103,7 @@ specification_version: 2
103
103
  summary: Syntactic metaprogramming for Ruby
104
104
  test_files:
105
105
  - test/test_andand.rb
106
+ - test/test_by_example.rb
106
107
  - test/test_call_by_name.rb
107
108
  - test/test_call_by_thunk.rb
108
109
  - test/test_call_splatted_by_name.rb