ruby_scribe 0.0.4 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,285 @@
1
+ module RubyScribe
2
+
3
+ # Various helpers for matching and constructing S-expressions without having to deal with
4
+ # array soup
5
+ module SexpHelpers
6
+ extend ActiveSupport::Concern
7
+
8
+ module ClassMethods
9
+ def module!(name, body = nil)
10
+ s(:module, generate_module_or_class_name(name), ensure_scope_wrapped(body))
11
+ end
12
+
13
+ def class!(name, extends = nil, body = nil)
14
+ s(:class, generate_module_or_class_name(name), generate_class_extend_from(extends), ensure_scope_wrapped(body))
15
+ end
16
+
17
+ def method!(name, arguments = nil, body = nil)
18
+ s(:defn, name.to_sym, method_args!(arguments), method_body!(body))
19
+ end
20
+
21
+ def method_on!(on, name, arguments = nil, body = nil)
22
+ s(:defs, on, name.to_sym, method_args!(arguments), method_body!(body))
23
+ end
24
+
25
+ def method_args!(arguments = nil)
26
+ arguments ||= []
27
+ options = arguments.extract_options!
28
+
29
+ s(*([:args] + arguments.map(&:to_sym))).tap do |args|
30
+ args.push s(*([:block] + options.map {|k, v| s(:lasgn, k.to_sym, v) })) if options && !options.empty?
31
+ end
32
+ end
33
+
34
+ def method_body!(body = nil)
35
+ if body.is_a?(Sexp) && body.kind == :scope
36
+ body
37
+ elsif body.is_a?(Sexp) && body.kind == :block
38
+ ensure_scope_wrapped(body)
39
+ elsif body.is_a?(Sexp)
40
+ method_body!(s(:block, body))
41
+ elsif body.is_a?(Array)
42
+ method_body!(s(*([:block] + body)))
43
+ else
44
+ method_body!(s(:block, s(:nil)))
45
+ end
46
+ end
47
+
48
+ def call!(name, arguments = nil, body = nil)
49
+ call_on!(nil, name.to_sym, arguments, body)
50
+ end
51
+
52
+ def call_on!(receiver, name, arguments = nil, body = nil)
53
+ s(:call, receiver, name.to_sym, call_args!(arguments))
54
+ end
55
+
56
+ def call_args!(arguments = nil)
57
+ arguments ||= []
58
+
59
+ if arguments.is_a?(Sexp) && arguments.kind == :arglist
60
+ arguments
61
+ elsif arguments.is_a?(Sexp)
62
+ s(:arglist, arguments)
63
+ elsif arguments.is_a?(Array)
64
+ s(*([:arglist] + arguments))
65
+ else
66
+ s(:arglist)
67
+ end
68
+ end
69
+
70
+
71
+ protected
72
+
73
+ def generate_module_or_class_name(name)
74
+ if name.nil?
75
+ nil
76
+ elsif name.is_a?(Sexp) or name.is_a?(Symbol)
77
+ name
78
+ elsif name.to_s !~ /::/
79
+ name.to_sym
80
+ else
81
+ RubyParser.new.parse(name)
82
+ end
83
+ end
84
+
85
+ def generate_class_extend_from(name)
86
+ if name.nil?
87
+ nil
88
+ elsif name.is_a?(Sexp) or name.is_a?(Symbol)
89
+ name
90
+ else
91
+ RubyParser.new.parse(name)
92
+ end
93
+ end
94
+
95
+ def ensure_scope_wrapped(sexp)
96
+ if sexp.is_a?(Sexp) && sexp.kind == :scope
97
+ sexp
98
+ elsif sexp.nil?
99
+ s(:scope)
100
+ else
101
+ s(:scope, sexp)
102
+ end
103
+ end
104
+ end
105
+
106
+ module InstanceMethods
107
+ def kind
108
+ sexp_type.to_sym
109
+ end
110
+
111
+ def body
112
+ sexp_body
113
+ end
114
+
115
+ def name
116
+ case kind
117
+ when :call
118
+ body[1]
119
+ when :lasgn, :iasgn, :class, :module
120
+ body[0]
121
+ when :iter
122
+ body[0].name
123
+ else
124
+ nil
125
+ end
126
+ end
127
+
128
+ def receiver
129
+ case kind
130
+ when :call
131
+ body[0]
132
+ else
133
+ nil
134
+ end
135
+ end
136
+
137
+ def arguments
138
+ case kind
139
+ when :call, :defs
140
+ body[2]
141
+ when :defn, :iter
142
+ body[1]
143
+ else
144
+ nil
145
+ end
146
+ end
147
+
148
+ def to_args
149
+ emit_as_args_array(arguments)
150
+ end
151
+
152
+ def block
153
+ case kind
154
+ when :defn
155
+ strip_scope_wrapper(body[2])
156
+ when :defs
157
+ strip_scope_wrapper(body[3])
158
+ when :class
159
+ strip_scope_wrapper(body[2])
160
+ when :module
161
+ strip_scope_wrapper(body[1])
162
+ else
163
+ nil
164
+ end
165
+ end
166
+
167
+ def call!(name, arguments = nil, body = nil)
168
+ Sexp.call_on!(self, name, arguments, body)
169
+ end
170
+
171
+ def module?(name = nil)
172
+ kind == :module &&
173
+ (name.nil? || match_expression(body[0], name))
174
+ end
175
+
176
+ def class?(name = nil, options = {})
177
+ kind == :class &&
178
+ (name.nil? || match_expression(body[0], name))
179
+ end
180
+
181
+ def method?(name = nil)
182
+ (kind == :defn && (name.nil? || match_expression(body[0], name))) ||
183
+ (kind == :defs && (name.nil? || match_expression(body[1], name)))
184
+ end
185
+
186
+ def call?(name = nil, options = {})
187
+ call_without_block?(name, options) || call_with_block?(name, options)
188
+ end
189
+
190
+ def call_without_block?(name = nil, options = {})
191
+ kind == :call &&
192
+ (name.nil? || match_expression(body[1], name)) &&
193
+ (options[:arguments].nil? || match_arguments_expression(self, options[:arguments])) &&
194
+ (!options[:block])
195
+ end
196
+
197
+ def call_with_block?(name = nil, options = {})
198
+ kind == :iter && body[0] && body[0].kind == :call &&
199
+ (name.nil? || match_expression(body[0].name, name)) &&
200
+ (options[:arguments].nil? || match_arguments_expression(body[0], options[:arguments])) &&
201
+ (options[:block].nil? || match_arguments_expression(self, options[:block]))
202
+ end
203
+
204
+ def rescue?
205
+ kind == :rescue
206
+ end
207
+
208
+ def conditional?(options = {})
209
+ kind == :if &&
210
+ (options[:type].nil? || match_conditional_type(self, options[:type]))
211
+ end
212
+
213
+ def case?
214
+ kind == :case
215
+ end
216
+
217
+
218
+ protected
219
+
220
+ def emit_as_args_array(e)
221
+ return e unless e.is_a?(Sexp)
222
+
223
+ case e.kind
224
+ when :arglist, :args
225
+ e.body.map {|c| emit_as_args_array(c) }.flatten
226
+ when :lasgn
227
+ [e.body[0]]
228
+ when :masgn
229
+ e.body[0].body.map {|c| emit_as_args_array(c) }.flatten
230
+ when :lit
231
+ [e.body[0]]
232
+ else
233
+ [e]
234
+ end
235
+ end
236
+
237
+ def match_expression(match_against, expression)
238
+ case expression
239
+ when String
240
+ match_against.to_s == expression
241
+ when Regexp
242
+ match_against.to_s =~ expression
243
+ when Array
244
+ expression.map(&:to_s).include?(match_against.to_s)
245
+ else
246
+ false
247
+ end
248
+ end
249
+
250
+ def match_arguments_expression(match_against, expression)
251
+ case expression
252
+ when Fixnum
253
+ expression == match_against.to_args.size
254
+ when Range
255
+ expression.include?(match_against.to_args.size)
256
+ when Array
257
+ expression == match_against.to_args
258
+ when TrueClass
259
+ match_against.to_args.size > 0
260
+ when FalseClass
261
+ match_against.to_args.size == 0
262
+ else
263
+ false
264
+ end
265
+ end
266
+
267
+ def match_conditional_type(match_against, expression)
268
+ case expression
269
+ when :if
270
+ !match_against.body[1].nil? && match_against.body[2].nil?
271
+ when :unless
272
+ match_against.body[1].nil? && !match_against.body[2].nil?
273
+ when :if_else
274
+ !match_against.body[1].nil? && !match_against.body[2].nil?
275
+ else
276
+ false
277
+ end
278
+ end
279
+
280
+ def strip_scope_wrapper(e)
281
+ e.kind == :scope ? strip_scope_wrapper(e.body[0]) : e
282
+ end
283
+ end
284
+ end
285
+ end
@@ -1,3 +1,3 @@
1
1
  module RubyScribe
2
- VERSION = "0.0.4"
2
+ VERSION = "0.1.0"
3
3
  end
data/lib/ruby_scribe.rb CHANGED
@@ -2,7 +2,9 @@ require "rubygems"
2
2
  require "active_support"
3
3
  require "ruby_parser"
4
4
 
5
+ require "ruby_scribe/sexp_helpers"
5
6
  require "ruby_scribe/emitter_helpers"
7
+ require "ruby_scribe/emitter_config"
6
8
  require "ruby_scribe/emitter"
7
9
  require "ruby_scribe/transformer_helpers"
8
10
  require "ruby_scribe/transformer"
@@ -0,0 +1,256 @@
1
+ require "spec_helper"
2
+
3
+ describe RubyScribe::SexpHelpers do
4
+ context "generating" do
5
+ context "module" do
6
+ describe "with string name" do
7
+ subject { Sexp.module!("MyModule") }
8
+ it { should == s(:module, :MyModule, s(:scope)) }
9
+ end
10
+
11
+ describe "with string colonized name" do
12
+ subject { Sexp.module!("Namespace::MyModule") }
13
+ it { should == s(:module, s(:colon2, s(:const, :Namespace), :MyModule), s(:scope)) }
14
+ end
15
+
16
+ describe "with string double-colonized name" do
17
+ subject { Sexp.module!("Double::Namespace::MyModule") }
18
+ it { should == s(:module, s(:colon2, s(:colon2, s(:const, :Double), :Namespace), :MyModule), s(:scope)) }
19
+ end
20
+
21
+ describe "with sexp name" do
22
+ subject { Sexp.module!(s(:colon2, s(:const, :Namespace), :MyModule)) }
23
+ it { should == s(:module, s(:colon2, s(:const, :Namespace), :MyModule), s(:scope)) }
24
+ end
25
+
26
+ describe "with single-statement body passed" do
27
+ subject { Sexp.module!("MyModule", s(:lit, 1)) }
28
+ it { should == s(:module, :MyModule, s(:scope, s(:lit, 1))) }
29
+ end
30
+
31
+ describe "with single-statement scoped body passed" do
32
+ subject { Sexp.module!("MyModule", s(:scope, s(:lit, 1))) }
33
+ it { should == s(:module, :MyModule, s(:scope, s(:lit, 1))) }
34
+ end
35
+
36
+ describe "with block body passed" do
37
+ subject { Sexp.module!("MyModule", s(:block, s(:call, nil, :one, s(:arglist)), s(:call, nil, :two, s(:arglist)))) }
38
+ it { should == s(:module, :MyModule, s(:scope, s(:block, s(:call, nil, :one, s(:arglist)), s(:call, nil, :two, s(:arglist))))) }
39
+ specify { subject.block.should == s(:block, s(:call, nil, :one, s(:arglist)), s(:call, nil, :two, s(:arglist))) }
40
+ end
41
+ end
42
+
43
+ context "class" do
44
+ describe "with string name" do
45
+ subject { Sexp.class!("MyClass") }
46
+ it { should == s(:class, :MyClass, nil, s(:scope)) }
47
+ end
48
+
49
+ describe "with string colonized name" do
50
+ subject { Sexp.class!("Namespace::MyClass") }
51
+ it { should == s(:class, s(:colon2, s(:const, :Namespace), :MyClass), nil, s(:scope)) }
52
+ end
53
+
54
+ describe "with string double-colonized name" do
55
+ subject { Sexp.class!("Double::Namespace::MyClass") }
56
+ it { should == s(:class, s(:colon2, s(:colon2, s(:const, :Double), :Namespace), :MyClass), nil, s(:scope)) }
57
+ end
58
+
59
+ describe "with sexp name" do
60
+ subject { Sexp.class!(s(:colon2, s(:const, :Namespace), :MyClass)) }
61
+ it { should == s(:class, s(:colon2, s(:const, :Namespace), :MyClass), nil, s(:scope)) }
62
+ end
63
+
64
+ describe "with single-statement body passed" do
65
+ subject { Sexp.class!("MyClass", nil, s(:lit, 1)) }
66
+ it { should == s(:class, :MyClass, nil, s(:scope, s(:lit, 1))) }
67
+ end
68
+
69
+ describe "with single-statement scoped body passed" do
70
+ subject { Sexp.class!("MyClass", nil, s(:scope, s(:lit, 1))) }
71
+ it { should == s(:class, :MyClass, nil, s(:scope, s(:lit, 1))) }
72
+ end
73
+
74
+ describe "with block body passed" do
75
+ subject { Sexp.class!("MyClass", nil, s(:block, s(:call, nil, :one, s(:arglist)), s(:call, nil, :two, s(:arglist)))) }
76
+ it { should == s(:class, :MyClass, nil, s(:scope, s(:block, s(:call, nil, :one, s(:arglist)), s(:call, nil, :two, s(:arglist))))) }
77
+ specify { subject.block.should == s(:block, s(:call, nil, :one, s(:arglist)), s(:call, nil, :two, s(:arglist))) }
78
+ end
79
+
80
+ describe "extending a string name" do
81
+ subject { Sexp.class!("MyClass", "Base") }
82
+ it { should == s(:class, :MyClass, s(:const, :Base), s(:scope)) }
83
+ end
84
+
85
+ describe "extending a colonized string name" do
86
+ subject { Sexp.class!("MyClass", "Base::Two") }
87
+ it { should == s(:class, :MyClass, s(:colon2, s(:const, :Base), :Two), s(:scope)) }
88
+ end
89
+
90
+ describe "extending an sexp name" do
91
+ subject { Sexp.class!("MyClass", s(:const, :Base)) }
92
+ it { should == s(:class, :MyClass, s(:const, :Base), s(:scope)) }
93
+ end
94
+ end
95
+
96
+ context "method" do
97
+ describe "blank method" do
98
+ subject { Sexp.method!("my_method") }
99
+ it { should == s(:defn, :my_method, s(:args), s(:scope, s(:block, s(:nil)))) }
100
+ end
101
+
102
+ describe "method with arguments" do
103
+ subject { Sexp.method!("my_method", [:arg1, :arg2]) }
104
+ it { should == s(:defn, :my_method, s(:args, :arg1, :arg2), s(:scope, s(:block, s(:nil)))) }
105
+ end
106
+
107
+ describe "method with argument default" do
108
+ subject { Sexp.method!("my_method", [:arg1, :arg2, {:arg2 => s(:lit, 1)}]) }
109
+ it { should == s(:defn, :my_method, s(:args, :arg1, :arg2, s(:block, s(:lasgn, :arg2, s(:lit, 1)))), s(:scope, s(:block, s(:nil)))) }
110
+ end
111
+
112
+ describe "method with single-statement body" do
113
+ subject { Sexp.method!("my_method", [], s(:lit, 1)) }
114
+ it { should == s(:defn, :my_method, s(:args), s(:scope, s(:block, s(:lit, 1)))) }
115
+ end
116
+
117
+ describe "method with multiple-statement body as sexp" do
118
+ subject { Sexp.method!("my_method", [], s(:block, s(:call, nil, :one, s(:arglist)), s(:call, nil, :two, s(:arglist)))) }
119
+ it { should == s(:defn, :my_method, s(:args), s(:scope, s(:block, s(:call, nil, :one, s(:arglist)), s(:call, nil, :two, s(:arglist))))) }
120
+ end
121
+
122
+ describe "method with multiple-statement body including scope" do
123
+ subject { Sexp.method!("my_method", [], s(:scope, s(:block, s(:call, nil, :one, s(:arglist)), s(:call, nil, :two, s(:arglist))))) }
124
+ it { should == s(:defn, :my_method, s(:args), s(:scope, s(:block, s(:call, nil, :one, s(:arglist)), s(:call, nil, :two, s(:arglist))))) }
125
+ end
126
+
127
+ describe "method with multiple-statement body as array" do
128
+ subject { Sexp.method!("my_method", [], [s(:call, nil, :one, s(:arglist)), s(:call, nil, :two, s(:arglist))]) }
129
+ it { should == s(:defn, :my_method, s(:args), s(:scope, s(:block, s(:call, nil, :one, s(:arglist)), s(:call, nil, :two, s(:arglist))))) }
130
+ specify { subject.block.should == s(:block, s(:call, nil, :one, s(:arglist)), s(:call, nil, :two, s(:arglist))) }
131
+ end
132
+ end
133
+
134
+ context "method call" do
135
+ describe "without arguments" do
136
+ subject { Sexp.call!("my_method") }
137
+ it { should == s(:call, nil, :my_method, s(:arglist)) }
138
+ end
139
+
140
+ describe "with arguments as sexp" do
141
+ subject { Sexp.call!("my_method", s(:arglist, s(:lit, 1), s(:lit, 2))) }
142
+ it { should == s(:call, nil, :my_method, s(:arglist, s(:lit, 1), s(:lit, 2))) }
143
+ end
144
+
145
+ describe "with arguments as array" do
146
+ subject { Sexp.call!("my_method", [s(:lit, 1), s(:lit, 2)]) }
147
+ it { should == s(:call, nil, :my_method, s(:arglist, s(:lit, 1), s(:lit, 2))) }
148
+ end
149
+
150
+ describe "with explicit self" do
151
+ subject { s(:self).call!("my_method") }
152
+ it { should == s(:call, s(:self), :my_method, s(:arglist)) }
153
+ end
154
+
155
+ describe "with receiver" do
156
+ subject { s(:lit, 1).call!("my_method") }
157
+ it { should == s(:call, s(:lit, 1), :my_method, s(:arglist)) }
158
+ end
159
+ end
160
+ end
161
+
162
+ context "an s-expression for" do
163
+ context "module" do
164
+ subject { s(:module, :MyModule, s(:scope, s(:lit, 1))) }
165
+ it { should be_module }
166
+ it { should be_module("MyModule") }
167
+ it { should be_module(/dul/) }
168
+ it { should be_module([:MyModule, :YourModule]) }
169
+ end
170
+
171
+ context "class" do
172
+ subject { s(:class, :MyClass, nil, s(:scope, s(:lit, 1))) }
173
+ it { should be_class }
174
+ it { should be_class("MyClass") }
175
+ it { should be_class(/las/) }
176
+ it { should be_class([:MyClass, :YourClass]) }
177
+ end
178
+
179
+ context "instance method" do
180
+ subject { s(:defn, :my_method, s(:args, :arg), s(:scope, s(:block, s(:lit, 1)))) }
181
+ it { should be_method }
182
+ it { should be_method("my_method") }
183
+ it { should be_method(/met/) }
184
+ it { should be_method([:my_method, :your_method]) }
185
+ specify { subject.to_args.should == [:arg] }
186
+
187
+ describe "with two arguments" do
188
+ subject { s(:defn, :my_method, s(:args, :one, :two), s(:scope, s(:block, s(:lit, 1)))) }
189
+ specify { subject.to_args.should == [:one, :two] }
190
+ end
191
+ end
192
+
193
+ context "class method" do
194
+ subject { s(:defs, s(:self), :my_method, s(:args, :arg), s(:scope, s(:block, s(:lit, 1)))) }
195
+ it { should be_method }
196
+ it { should be_method("my_method") }
197
+ it { should be_method(/met/) }
198
+ it { should be_method([:my_method, :your_method]) }
199
+ end
200
+
201
+ context "method call" do
202
+ describe "with one argument" do
203
+ subject { s(:call, nil, :invoke, s(:arglist, s(:lit, 1))) }
204
+ it { should be_call }
205
+ it { should be_call("invoke") }
206
+ it { should be_call(/vok/) }
207
+ it { should be_call([:invoke, :another]) }
208
+ it { should be_call("invoke", :arguments => true) }
209
+ it { should be_call("invoke", :arguments => 1) }
210
+ it { should_not be_call("invoke", :arguments => 2) }
211
+ it { should_not be_call("invoke", :block => true) }
212
+ end
213
+
214
+ describe "with block" do
215
+ subject { s(:iter, s(:call, nil, :each, s(:arglist)), s(:lasgn, :i), s(:lit, 1)) }
216
+ it { should be_call }
217
+ it { should be_call("each") }
218
+ it { should be_call("each", :block => true) }
219
+ it { should be_call("each", :block => 1) }
220
+ it { should_not be_call("each", :block => 2) }
221
+ specify { subject.to_args.should == [:i] }
222
+ end
223
+
224
+ describe "with block (2 arguments) and 1 method argument" do
225
+ subject { s(:iter, s(:call, nil, :inject, s(:arglist, s(:lit, 1))), s(:masgn, s(:array, s(:lasgn, :b), s(:lasgn, :i))), s(:lit, 1)) }
226
+ it { should be_call(nil, :block => true) }
227
+ it { should be_call(nil, :arguments => true) }
228
+ it { should be_call(nil, :arguments => 1, :block => 2) }
229
+ it { should_not be_call(nil, :arguments => 2, :block => 2) }
230
+ specify { subject.to_args.should == [:b, :i] }
231
+ end
232
+ end
233
+
234
+ context "conditional" do
235
+ describe "if-else" do
236
+ subject { s(:if, s(:true), s(:lit, 1), s(:lit, 2)) }
237
+ it { should be_conditional(:type => :if_else) }
238
+ end
239
+
240
+ describe "if" do
241
+ subject { s(:if, s(:true), s(:lit, 1), nil) }
242
+ it { should be_conditional(:type => :if) }
243
+ end
244
+
245
+ describe "unless" do
246
+ subject { s(:if, s(:true), nil, s(:lit, 2)) }
247
+ it { should be_conditional(:type => :unless) }
248
+ end
249
+ end
250
+
251
+ context "case statement" do
252
+ subject { s(:case, nil, s(:when, s(:array, s(:true)), s(:lit, 1)), s(:lit, 2)) }
253
+ it { should be_case }
254
+ end
255
+ end
256
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_scribe
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 27
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
+ - 1
8
9
  - 0
9
- - 4
10
- version: 0.0.4
10
+ version: 0.1.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Ben Hughes
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-10-28 00:00:00 +03:00
18
+ date: 2010-11-01 00:00:00 +01:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -74,16 +74,11 @@ extra_rdoc_files: []
74
74
 
75
75
  files:
76
76
  - lib/ruby_scribe/emitter.rb
77
+ - lib/ruby_scribe/emitter_config.rb
77
78
  - lib/ruby_scribe/emitter_helpers.rb
78
79
  - lib/ruby_scribe/ext/sexp.rb
79
80
  - lib/ruby_scribe/runner.rb
80
- - lib/ruby_scribe/transformer.rb
81
- - lib/ruby_scribe/transformer_helpers.rb
82
- - lib/ruby_scribe/transformers/block_method_to_procifier.rb
83
- - lib/ruby_scribe/transformers/custom.rb
84
- - lib/ruby_scribe/transformers/eachifier.rb
85
- - lib/ruby_scribe/transformers/symbol_names.rb
86
- - lib/ruby_scribe/transformers/tapifier.rb
81
+ - lib/ruby_scribe/sexp_helpers.rb
87
82
  - lib/ruby_scribe/version.rb
88
83
  - lib/ruby_scribe.rb
89
84
  - spec/examples/identity.rb
@@ -93,12 +88,7 @@ files:
93
88
  - spec/matchers/should_transform_to.rb
94
89
  - spec/ruby_scribe/emitter_examples_spec.rb
95
90
  - spec/ruby_scribe/emitter_spec.rb
96
- - spec/ruby_scribe/transformer_spec.rb
97
- - spec/ruby_scribe/transformers/block_method_to_procifier_spec.rb
98
- - spec/ruby_scribe/transformers/custom_spec.rb
99
- - spec/ruby_scribe/transformers/eachifier_spec.rb
100
- - spec/ruby_scribe/transformers/symbol_names_spec.rb
101
- - spec/ruby_scribe/transformers/tapifier_spec.rb
91
+ - spec/ruby_scribe/sexp_helpers_spec.rb
102
92
  - spec/spec_helper.rb
103
93
  - LICENSE
104
94
  - Rakefile
@@ -1,18 +0,0 @@
1
- module RubyScribe
2
-
3
- # Takes a raw S-expression and transforms it (replaces the node with the return value of the process method).
4
- # This is meant to be subclassed, and in the process method you should either return a transformed version of the node,
5
- # or just call super which will leave the node in place and iterate through the children.
6
- #
7
- class Transformer
8
- include TransformerHelpers
9
-
10
- def transform(sexp)
11
- if sexp.is_a?(Sexp)
12
- Sexp.new(*([sexp.kind] + sexp.body.map {|c| transform(c) }))
13
- else
14
- sexp
15
- end
16
- end
17
- end
18
- end
@@ -1,7 +0,0 @@
1
- module RubyScribe
2
- module TransformerHelpers
3
- def sexp?(e)
4
- e.is_a?(Sexp)
5
- end
6
- end
7
- end
@@ -1,43 +0,0 @@
1
- module RubyScribe
2
- module Transformers
3
-
4
- # = Block Method To Proc Transform
5
- # Looks for cases where we're calling a single method on a single-parameter block argument.
6
- # These instances can use the Ruby 1.9 and ActiveSupport "Symbol#to_proc" trick.
7
- #
8
- # Example:
9
- #
10
- # collection.map {|d| d.name }
11
- #
12
- # Transforms To:
13
- #
14
- # collect.map(&:name)
15
- #
16
- class BlockMethodToProcifier < Transformer
17
- def transform(e)
18
- if matches_block_to_use_tap?(e)
19
- super transform_block_to_use_tap(e)
20
- else
21
- super
22
- end
23
- end
24
-
25
- def matches_block_to_use_tap?(e)
26
- e.is_a?(Sexp) && e.kind == :iter && # Calls block
27
- e.body[2] && e.body[2].kind == :call && # Body of block is a simple method call
28
- e.body[2].body[0].kind == :lvar && # Simple method call is on a local variable
29
- e.body[1].kind == :lasgn && # Block parameter is a single assign
30
- e.body[2].body[0].body[0] == e.body[1].body[0] # Local variable is identical to the first block argument
31
- end
32
-
33
- def transform_block_to_use_tap(e)
34
- s(:call,
35
- e.body[0].body[0],
36
- e.body[0].body[1],
37
- s(:arglist, s(:block_pass, s(:lit, e.body[2].body[1])))
38
- )
39
- end
40
- end
41
-
42
- end
43
- end