ruby_scribe 0.0.4 → 0.1.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.
@@ -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