ruby_scribe 0.0.1

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.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Ben Hughes
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,104 @@
1
+ = Ruby Scribe
2
+
3
+ == Introduction
4
+
5
+ Seattle RB's ruby_parser is a great tool for parsing ruby code into syntax trees. Ruby Scribe is the reverse of this - a tool for taking an S-expression in Ruby and emitting clean code. It does this by providing a series of rules that intelligently formats code much as a real developer would.
6
+
7
+ == Example
8
+
9
+ Imagine this crappily-formatted Ruby code:
10
+
11
+ module RubyScribe
12
+
13
+
14
+ # My Comment
15
+ class Sample < Base;
16
+ def method; do_something_here; end
17
+
18
+ if(new_record?) then
19
+ puts "Yes"
20
+ else
21
+ puts 'No'
22
+ end
23
+ end
24
+ end
25
+
26
+ Here is the syntax tree for the above:
27
+
28
+ s(:module,
29
+ :RubyScribe,
30
+ s(:scope,
31
+ s(:class,
32
+ :Sample,
33
+ s(:const, :Base),
34
+ s(:scope,
35
+ s(:block,
36
+ s(:defn,
37
+ :method,
38
+ s(:args),
39
+ s(:scope, s(:block, s(:call, nil, :do_something_here, s(:arglist))))),
40
+ s(:if,
41
+ s(:call, nil, :new_record?, s(:arglist)),
42
+ s(:call, nil, :puts, s(:arglist, s(:str, "Yes"))),
43
+ s(:call, nil, :puts, s(:arglist, s(:str, "No")))))))))
44
+
45
+ Parse that with RubyParser, then emit it with RubyScribe:
46
+
47
+ sexp = RubyParser.new.parse(File.read("bad_code.rb"))
48
+ RubyScribe::Emitter.new.emit(sexp)
49
+
50
+ And out pops this:
51
+
52
+ module RubyScribe
53
+ # My Comment
54
+ class Sample < Base
55
+ def method
56
+ do_something_here
57
+ end
58
+
59
+ if new_record?
60
+ puts "Yes"
61
+ else
62
+ puts "No"
63
+ end
64
+ end
65
+ end
66
+
67
+
68
+ == Applications
69
+
70
+ The combination of these two tools allows some other interesting tools to be written. One of example tool (and indeed the entire reason I started this project) is my rspecify tool, which can take a test directory with code written using Test::Unit and, via a Ruby Scribe Preprocessor, convert it into RSpec, automating 99% of what a human developer would normally have to do.
71
+
72
+ Future projects using these two gems could be:
73
+ * Automated refactoring tools
74
+ * Tools that take a project and try to apply a set of "coding standards"
75
+ * Tools that produce metrics on how much your code differs from the project's "coding standards" implementation.
76
+
77
+ == Usage
78
+
79
+ The entire project simply takes an incoming Sexp object (from the ruby_parser project) and emits a single string. To do this just use an Emitter:
80
+
81
+ RubyScribe::Emitter.new.emit(sexp) # => "module Something..."
82
+
83
+ == Emitter Implementation
84
+
85
+ The +Emitter+ class is nothing but a bunch of recursion. The main emit method is a big case block to offload handling of individual types to separate methods which handle and compose a big string, all through recursion.
86
+
87
+ To extend or implement your own Emitter, just subclass +RubyScribe::Emitter+ and override the necessary methods.
88
+
89
+ == Preprocess Implementation
90
+
91
+ This feature is not developed yet, but is intended on presenting a standard recursion-based class for implementing transformations of S-expressions.
92
+
93
+ == Known Issues
94
+
95
+ * Anything involving order of operations currently much surround the expression in ( ). Will probably expand later to omit this when order of operations is implied, but this requires a context stack.
96
+ * Elsif currently does not work as you'd expect and instead embeds another if block inside of the outer one's "else". This is how if statements are presented via ruby_parser.
97
+ * Some of the more obscure types are not implemented.
98
+ * Only comments on methods, class, and module declarations are retained. This is actually a limitation of ruby_parser as for whatever reason
99
+ in-line comments cannot be parsed correctly.
100
+
101
+ == Future Features
102
+
103
+ * Maintain a context stack so emit methods can emit different content dependent on context in the stack
104
+ * Configuration options for things such as block style, preference for quote style, etc.
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ require "rubygems"
2
+ require "rake"
3
+ require "rake/rdoctask"
4
+
5
+ desc "Generate documentation for the plugin."
6
+ Rake::RDocTask.new(:rdoc) do |rdoc|
7
+ rdoc.rdoc_dir = "rdoc"
8
+ rdoc.title = "has_draft"
9
+ rdoc.options << "--line-numbers" << "--inline-source"
10
+ rdoc.rdoc_files.include('README')
11
+ rdoc.rdoc_files.include('lib/**/*.rb')
12
+ end
13
+
14
+ Dir["#{File.dirname(__FILE__)}/lib/tasks/*.rake"].sort.each { |ext| load ext }
data/TODO.rdoc ADDED
@@ -0,0 +1,2 @@
1
+ = TODO
2
+
@@ -0,0 +1,8 @@
1
+ require "rubygems"
2
+ require "active_support"
3
+ require "ruby_parser"
4
+
5
+ require "ruby_scribe/emitter_helpers"
6
+ require "ruby_scribe/emitter"
7
+ require "ruby_scribe/preprocessor"
8
+ require "ruby_scribe/ext/sexp"
@@ -0,0 +1,446 @@
1
+ require "active_support/core_ext"
2
+
3
+ module RubyScribe
4
+ # Takes a proprocessed S-expression and emits formatted Ruby code
5
+ class Emitter
6
+ include EmitterHelpers
7
+
8
+ cattr_accessor :methods_without_parenthesis
9
+ self.methods_without_parenthesis = %w(require gem puts attr_accessor cattr_accessor delegate alias_method alias)
10
+
11
+ SYNTACTIC_METHODS = ['+', '-', '<<', '==', '===', '>', '<']
12
+
13
+ def emit(e)
14
+ return "" unless e
15
+ return e if e.is_a?(String)
16
+ return e.to_s if e.is_a?(Symbol)
17
+
18
+ case e.kind
19
+ when :block
20
+ emit_block(e)
21
+ when :scope
22
+ emit_scope(e)
23
+ when :rescue
24
+ emit_rescue(e)
25
+ when :module
26
+ emit_module_definition(e)
27
+ when :class
28
+ emit_class_definition(e)
29
+ when :sclass
30
+ emit_self_class_definition(e)
31
+ when :defn
32
+ emit_method_definition(e)
33
+ when :defs
34
+ emit_method_with_receiver_definition(e)
35
+ when :args
36
+ emit_method_argument_list(e)
37
+ when :call
38
+ emit_method_call(e)
39
+ when :arglist
40
+ emit_argument_list(e)
41
+ when :attrasgn
42
+ emit_attribute_assignment(e)
43
+ when :masgn
44
+ emit_multiple_assignment(e)
45
+ when :cdecl
46
+ emit_constant_declaration(e)
47
+ when :if, :unless
48
+ emit_conditional_block(e)
49
+ when :case
50
+ emit_case_statement(e)
51
+ when :when
52
+ emit_case_when_statement(e)
53
+ when :while, :until
54
+ emit_loop_block(e)
55
+ when :for
56
+ emit_for_block(e)
57
+ when :lasgn, :iasgn
58
+ emit_assignment_expression(e)
59
+ when :op_asgn_or
60
+ emit_optional_assignment_or_expression(e)
61
+ when :op_asgn_and
62
+ emit_optional_assignment_and_expression(e)
63
+ when :or, :and
64
+ emit_binary_expression(e)
65
+ when :iter
66
+ emit_block_invocation(e)
67
+ when :defined
68
+ emit_defined_invocation(e)
69
+ else
70
+ emit_token(e)
71
+ end || ""
72
+ end
73
+
74
+
75
+ protected
76
+
77
+ def emit_comments(comments)
78
+ comments.present? ? (comments.split("\n").join(nl) + nl) : ""
79
+ end
80
+
81
+ def emit_block(e)
82
+ return "" if e.body[0] == s(:nil)
83
+
84
+ # Special case for handling rescue blocks around entire methods (excluding the indent):
85
+ return emit_method_rescue(e.body[0]) if e.body.size == 1 and e.body[0].kind == :rescue
86
+
87
+ e.body.map do |child|
88
+ emit_block_member_prefix(e.body, child) +
89
+ emit(child)
90
+ end.join(nl)
91
+ end
92
+
93
+ def emit_block_member_prefix(members, current_member)
94
+ previous_member_index = members.index(current_member) - 1
95
+ previous_member = previous_member_index >= 0 ? members[previous_member_index] : nil
96
+ return "" unless previous_member
97
+
98
+ [
99
+ [[:defn, :defs, :iter, :class, :module, :rescue], [:defn, :defs, :iter, :class, :module, :call, :rescue]],
100
+ [[:call], [:defn, :defs, :iter, :class, :module]]
101
+ ].each do |from, to|
102
+ return nl if (from == :any || from.include?(previous_member.kind)) && (to == :any || to.include?(current_member.kind))
103
+ end
104
+
105
+ if current_member.kind == :if && [:block_if, :block_unless].include?(determine_if_type(current_member))
106
+ return nl
107
+ elsif previous_member.kind == :if && [:block_if, :block_unless].include?(determine_if_type(previous_member))
108
+ return nl
109
+ end
110
+
111
+ ""
112
+ end
113
+
114
+ def emit_scope(e)
115
+ emit(e.body[0])
116
+ end
117
+
118
+ def emit_rescue(e)
119
+ "begin" + indent { nl + emit(e.body[0]) } +
120
+ nl("rescue ") + indent { nl + emit(e.body[1].body[1]) } +
121
+ nl("end")
122
+ end
123
+
124
+ def emit_method_rescue(e)
125
+ emit(e.body[0]) +
126
+ indent(-2) { nl("rescue ") } +
127
+ nl + emit(e.body[1].body[1])
128
+ end
129
+
130
+ def emit_class_definition(e)
131
+ emit_comments(e.comments) +
132
+ "#{e.kind} #{e.body[0]}" +
133
+ (e.body[1] ? " < #{emit(e.body[1])}" : "") +
134
+ indent { nl + emit(e.body[2]) } +
135
+ nl("end")
136
+ end
137
+
138
+ def emit_self_class_definition(e)
139
+ "class << #{e.body[0]}" +
140
+ indent { nl + emit(e.body[1]) } +
141
+ nl("end")
142
+ end
143
+
144
+ def emit_module_definition(e)
145
+ emit_comments(e.comments) +
146
+ "#{e.kind} #{e.body[0]}" +
147
+ indent { nl + emit(e.body[1]) } +
148
+ nl("end")
149
+ end
150
+
151
+ def emit_method_definition(e)
152
+ emit_comments(e.comments) +
153
+ "def #{e.body[0]}" +
154
+ (e.body[1].body.empty? ? "" : "(#{emit(e.body[1])})") +
155
+ indent { nl + emit(e.body[2]) } +
156
+ nl("end")
157
+ end
158
+
159
+ def emit_method_with_receiver_definition(e)
160
+ emit_comments(e.comments) +
161
+ "def #{emit(e.body[0])}.#{e.body[1]}" +
162
+ (e.body[2].body.empty? ? "" : "(#{emit(e.body[2])})") +
163
+ indent { nl + emit(e.body[3]) } +
164
+ nl("end")
165
+ end
166
+
167
+ def emit_method_argument_list(e)
168
+ [].tap do |array|
169
+ e.body.each do |child|
170
+ if child.is_a?(Sexp) and child.kind == :block
171
+ child.body.each do |body_child|
172
+ array[array.index(body_child.body[0])] = emit(body_child)
173
+ end
174
+ else
175
+ array << child
176
+ end
177
+ end
178
+ end.join(", ")
179
+ end
180
+
181
+ def emit_method_call(e)
182
+ return emit_method_call_hash_access(e) if e.body[1] == :[]
183
+ return emit_method_call_hash_assignment(e) if e.body[1] == :[]=
184
+
185
+ emit_method_call_receiver(e) +
186
+ emit_method_call_name(e) +
187
+ emit_method_call_arguments(e)
188
+ end
189
+
190
+ def emit_method_call_receiver(e)
191
+ if e.body[0] && SYNTACTIC_METHODS.include?(e.body[1].to_s)
192
+ "#{emit(e.body[0])} "
193
+ elsif e.body[0]
194
+ "#{emit(e.body[0])}."
195
+ else
196
+ ""
197
+ end
198
+ end
199
+
200
+ def emit_method_call_name(e)
201
+ emit(e.body[1])
202
+ end
203
+
204
+ def emit_method_call_arguments(e)
205
+ if e.body[2].body.empty?
206
+ ""
207
+ elsif self.class.methods_without_parenthesis.include?(e.body[1].to_s)
208
+ " " + emit(e.body[2])
209
+ elsif SYNTACTIC_METHODS.include?(e.body[1].to_s)
210
+ " " + emit(e.body[2])
211
+ else
212
+ "(" + emit(e.body[2]) + ")"
213
+ end
214
+ end
215
+
216
+ def emit_method_call_hash_access(e)
217
+ emit(e.body[0]) + "[" + emit(e.body[2]) + "]"
218
+ end
219
+
220
+ def emit_method_call_hash_assignment(e)
221
+ emit(e.body[0]) + "[" + emit(e.body[2].body[0]) + "] = " + emit(e.body[2].body[1])
222
+ end
223
+
224
+
225
+ def emit_argument_list(e)
226
+ e.body.map do |child|
227
+ if child == e.body[-1] && child.kind == :hash
228
+ emit_hash_body(child)
229
+ else
230
+ emit(child)
231
+ end
232
+ end.join(", ")
233
+ end
234
+
235
+ def emit_attribute_assignment(e)
236
+ return emit_method_call(e) if ['[]='].include?(e.body[1].to_s)
237
+
238
+ emit(e.body[0]) + "." + e.body[1].to_s.gsub(/=$/, "") + " = " + emit(e.body[2])
239
+ end
240
+
241
+ def emit_multiple_assignment(e)
242
+ left = e.body[0].body
243
+ right = e.body[1].body
244
+
245
+ left.map {|c| c.body[0] }.join(", ") + " = " + right.map {|c| emit(c) }.join(", ")
246
+ end
247
+
248
+ def emit_constant_declaration(e)
249
+ emit(e.body[0]) + " = " + emit(e.body[1])
250
+ end
251
+
252
+ def determine_if_type(e)
253
+ if e.body[1] && e.body[2] && e.body[0].line == e.body[1].try(:line) && e.line == e.body[2].try(:line)
254
+ :terinary
255
+ elsif e.body[1] && !e.body[2] && e.line == e.body[1].line && e.body[1].kind != :block
256
+ :dangling_if
257
+ elsif !e.body[1] && e.body[2] && e.line == e.body[2].line && e.body[2].kind != :block
258
+ :dangling_unless
259
+ elsif e.body[1]
260
+ :block_if
261
+ elsif e.body[2]
262
+ :block_unless
263
+ end
264
+ end
265
+
266
+ def emit_conditional_block(e)
267
+ case determine_if_type(e)
268
+ when :terinary
269
+ "#{emit(e.body[0])} ? #{emit(e.body[1] || s(:nil))} : #{emit(e.body[2] || s(:nil))}"
270
+ when :dangling_if
271
+ "#{emit(e.body[1])} if #{emit(e.body[0])}"
272
+ when :dangling_unless
273
+ "#{emit(e.body[2])} unless #{emit(e.body[0])}"
274
+ when :block_if
275
+ "if #{emit(e.body[0])}" + indent { nl + emit(e.body[1]) } +
276
+ (e.body[2] ? (nl("else") + indent { nl + emit(e.body[2]) }) : "") +
277
+ nl("end")
278
+ when :block_unless
279
+ "unless #{emit(e.body[0])}" + indent { nl + emit(e.body[2]) } +
280
+ nl("end")
281
+ end
282
+ end
283
+
284
+ def emit_case_statement(e)
285
+ "case #{emit(e.body.first)}" + e.body[1..-2].map {|c| emit(c) }.join + emit_case_else_statement(e.body[-1]) + nl("end")
286
+ end
287
+
288
+ def emit_case_when_statement(e)
289
+ nl("when #{emit_case_when_argument(e.body.first)}") + indent { nl + emit(e.body[1]) }
290
+ end
291
+
292
+ def emit_case_else_statement(e)
293
+ if e
294
+ nl("else") + indent { nl + emit(e) }
295
+ else
296
+ ""
297
+ end
298
+ end
299
+
300
+ def emit_case_when_argument(e)
301
+ emit(e).gsub(/^\[/, '').gsub(/\]$/, '')
302
+ end
303
+
304
+ def emit_loop_block(e)
305
+ "#{e.kind} #{e.body.first}" +
306
+ indent { emit(e.body[1]) } +
307
+ nl("end")
308
+ end
309
+
310
+ def emit_for_block(e)
311
+ "for #{e.body[1].body[0]} in #{emit(e.body[0])}" +
312
+ indent { nl + emit(e.body[2]) } +
313
+ nl("end")
314
+ end
315
+
316
+ def emit_assignment_expression(e)
317
+ "#{e.body[0]} = #{emit(e.body[1])}"
318
+ end
319
+
320
+ def emit_optional_assignment_or_expression(e)
321
+ emit(e.body[0]) + " ||= " + emit(e.body[1].body[1])
322
+ end
323
+
324
+ def emit_optional_assignment_and_expression(e)
325
+ emit(e.body[0]) + " &&= " + emit(e.body[1].body[1])
326
+ end
327
+
328
+ def emit_binary_expression(e)
329
+ "(" + emit(e.body[0]) + " " +
330
+ (e.kind == :and ? "&&" : "||") +
331
+ " " + emit(e.body[1]) + ")"
332
+ end
333
+
334
+ def emit_block_invocation(e)
335
+ emit(e.body[0]) + emit_block_invocation_body(e)
336
+ end
337
+
338
+ def emit_block_invocation_body(e)
339
+ # If it's on the same line, it should probably be shorthand form:
340
+ if e.line == e.body[2].try(:line)
341
+ " {#{emit_block_invocation_arguments(e)} #{emit(e.body[2])} }"
342
+ else
343
+ " do #{emit_block_invocation_arguments(e)}".gsub(/ +$/, '') +
344
+ indent { nl + emit(e.body[2]) } +
345
+ nl("end")
346
+ end
347
+ end
348
+
349
+ def emit_block_invocation_arguments(e)
350
+ if e.body[1]
351
+ "|" + emit_assignments_as_arguments(e.body[1]) + "| "
352
+ else
353
+ ""
354
+ end
355
+ end
356
+
357
+ def emit_assignments_as_arguments(e)
358
+ if e.kind == :masgn
359
+ e.body[0].body.map {|c| emit_assignments_as_arguments(c) }.join(", ")
360
+ elsif e.kind == :lasgn
361
+ e.body[0].to_s
362
+ elsif e.kind == :splat
363
+ "*" + emit_assignments_as_arguments(e.body[0])
364
+ end
365
+ end
366
+
367
+ def emit_defined_invocation(e)
368
+ "defined?(#{emit(e.body[0])})"
369
+ end
370
+
371
+ def emit_token(e)
372
+ case e.kind
373
+ when :str
374
+ '"' + e.body[0] + '"'
375
+ when :lit
376
+ e.body[0].inspect
377
+ when :const
378
+ e.body[0].to_s
379
+ when :lvar
380
+ e.body[0].to_s
381
+ when :ivar
382
+ e.body[0].to_s
383
+ when :not
384
+ "!" + emit(e.body[0])
385
+ when :true
386
+ "true"
387
+ when :false
388
+ "false"
389
+ when :nil
390
+ "nil"
391
+ when :self
392
+ "self"
393
+ when :zsuper
394
+ "super"
395
+ when :super
396
+ "super(" + e.body.map {|c| emit(c) }.join(", ") + ")"
397
+ when :yield
398
+ "yield #{emit_argument_list(e)}".strip
399
+ when :next
400
+ "next"
401
+ when :retry
402
+ "retry"
403
+ when :return
404
+ "return #{emit_argument_list(e)}".strip
405
+ when :alias
406
+ "alias #{emit(e.body[0])} #{emit(e.body[1])}"
407
+ when :block_pass
408
+ "&" + emit(e.body[0])
409
+ when :splat
410
+ "*" + emit(e.body[0])
411
+ when :colon2
412
+ "#{emit(e.body[0])}::#{e.body[1].to_s}"
413
+ when :hash
414
+ "{" + emit_hash_body(e) + "}"
415
+ when :array
416
+ "[" + e.body.map {|c| emit(c)}.join(", ") + "]"
417
+ when :gvar
418
+ e.body[0].to_s
419
+ when :dstr
420
+ '"' + literalize_strings(e.body).map {|c| emit(c) }.join + '"'
421
+ when :evstr
422
+ '#{' + emit(e.body[0]) + '}'
423
+ when :xstr
424
+ '`' + emit(e.body[0]) + '`'
425
+ when :dxstr
426
+ '`' + literalize_strings(e.body).map {|c| emit(c) }.join + '`'
427
+ when :dsym
428
+ ':"' + literalize_strings(e.body).map {|c| emit(c) }.join + '"'
429
+ when :match3
430
+ emit(e.body[1]) + " =~ " + emit(e.body[0])
431
+ when :cvdecl
432
+ emit(e.body[0].to_s) + " = " + emit(e.body[1])
433
+ else
434
+ emit_unknown_expression(e)
435
+ end
436
+ end
437
+
438
+ def emit_hash_body(e)
439
+ e.body.in_groups_of(2).map {|g| "#{emit(g[0])} => #{emit(g[1])}" }.join(", ")
440
+ end
441
+
442
+ def emit_unknown_expression(e)
443
+ nl("## UNKNOWN: #{e.kind} ##")
444
+ end
445
+ end
446
+ end
@@ -0,0 +1,28 @@
1
+ module RubyScribe
2
+ module EmitterHelpers
3
+ def indents
4
+ @indents ||= []
5
+ end
6
+
7
+ def indent_level
8
+ indents.inject(0) {|b,i| b + i } || 0
9
+ end
10
+
11
+ def indent(level = 2)
12
+ indents.push(level)
13
+ output = yield
14
+ indents.pop
15
+ output
16
+ end
17
+
18
+ def nl(text = "")
19
+ "\n" + (" " * indent_level) + text
20
+ end
21
+
22
+ def literalize_strings(sexps)
23
+ sexps.map do |sexp|
24
+ sexp.is_a?(Sexp) && sexp.kind == :str ? sexp.body[0] : sexp
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,9 @@
1
+ class Sexp
2
+ def kind
3
+ sexp_type.to_sym
4
+ end
5
+
6
+ def body
7
+ sexp_body
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module RubyScribe
2
+ # Takes a raw S-expression and proprocesses it. To use, simply subclass and override the preprocess method.
3
+ # Catch any instances you want to handle as it drills down the chain
4
+ class Preprocessor
5
+ def proprocess(sexp)
6
+
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,32 @@
1
+ require "thor"
2
+
3
+ module RubyScribe
4
+ class Runner < Thor
5
+ desc :cat, "Takes a single ruby file, parses it, and outputs the scribed version."
6
+ def cat(path)
7
+ sexp = RubyParser.new.parse(File.read(path))
8
+ puts RubyScribe::Emitter.new.emit(sexp)
9
+ end
10
+
11
+ desc :convert, "Takes a single file or multiple files, parses them, then replaces the original file(s) with the scribed version."
12
+ def convert(*paths)
13
+ expand_paths(paths).each do |path|
14
+ sexp = RubyParser.new.parse(File.read(path))
15
+ output = RubyScribe::Emitter.new.emit(sexp)
16
+
17
+ File.open(path, "w") do |file|
18
+ file.write(output)
19
+ file.flush
20
+ end
21
+ end
22
+ end
23
+
24
+ protected
25
+
26
+ def expand_paths(paths = [])
27
+ paths.map do |path|
28
+ [path] + Dir[path + "**/*.rb"]
29
+ end.flatten.uniq.reject {|f| File.directory?(f) }
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,3 @@
1
+ module RubyScribe
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,29 @@
1
+ namespace :scribe do
2
+ desc "Run Scribe Examples"
3
+ task :examples do
4
+ $:.unshift(File.join(File.dirname(__FILE__), ".."))
5
+ require "ruby_parser"
6
+ require "ruby_scribe"
7
+ require "pp"
8
+
9
+ original_file = File.read(File.join(File.dirname(__FILE__), "../../spec/examples/simple_class_with_methods.rb"))
10
+ sexp = RubyParser.new.parse(original_file)
11
+
12
+ puts "Parsed S-Expresssion"
13
+ puts "======================================"
14
+ pp sexp
15
+ puts
16
+
17
+ puts "Original File"
18
+ puts "======================================"
19
+ puts original_file
20
+
21
+ puts
22
+ puts
23
+
24
+ puts "Parsed File"
25
+ puts "======================================"
26
+ parsed_file = RubyScribe::Emitter.new.emit(sexp)
27
+ puts parsed_file
28
+ end
29
+ end
@@ -0,0 +1,14 @@
1
+ module RubyScribe
2
+
3
+
4
+ # My Comment
5
+ class Sample < Base;
6
+ def method; do_something_here; end
7
+
8
+ if(new_record?) then
9
+ puts "Yes"
10
+ else
11
+ puts 'No'
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,7 @@
1
+ require "spec_helper"
2
+
3
+ describe RubyScribe::Preprocessor do
4
+ subject { RubyScribe::Proprocessor.new }
5
+
6
+
7
+ end
@@ -0,0 +1,9 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), "../lib"))
2
+
3
+ require "rubygems"
4
+ require "rspec"
5
+ require "ruby_scribe"
6
+
7
+ # Requires supporting files with custom matchers and macros, etc,
8
+ # in ./support/ and its subdirectories.
9
+ Dir["#{File.dirname(__FILE__)}/matchers/**/*.rb"].each {|f| require f}
@@ -0,0 +1,9 @@
1
+ require "spec_helper"
2
+
3
+ describe RubyScribe::Strategy do
4
+ before do
5
+ @strategy = RubyScribe::Strategy.new
6
+ end
7
+
8
+
9
+ end
metadata ADDED
@@ -0,0 +1,129 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby_scribe
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Ben Hughes
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-10-25 00:00:00 +03:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: ruby_parser
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 7
30
+ segments:
31
+ - 2
32
+ - 0
33
+ - 4
34
+ version: 2.0.4
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: thor
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ hash: 17
46
+ segments:
47
+ - 0
48
+ - 13
49
+ version: "0.13"
50
+ type: :runtime
51
+ version_requirements: *id002
52
+ - !ruby/object:Gem::Dependency
53
+ name: rspec
54
+ prerelease: false
55
+ requirement: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ~>
59
+ - !ruby/object:Gem::Version
60
+ hash: 3
61
+ segments:
62
+ - 2
63
+ - 0
64
+ version: "2.0"
65
+ type: :development
66
+ version_requirements: *id003
67
+ description: A ruby formatting tool that takes S-expression as input and intelligently outputs formatted Ruby code.
68
+ email: ben@railsgarden.com
69
+ executables: []
70
+
71
+ extensions: []
72
+
73
+ extra_rdoc_files: []
74
+
75
+ files:
76
+ - lib/ruby_scribe/emitter.rb
77
+ - lib/ruby_scribe/emitter_helpers.rb
78
+ - lib/ruby_scribe/ext/sexp.rb
79
+ - lib/ruby_scribe/preprocessor.rb
80
+ - lib/ruby_scribe/runner.rb
81
+ - lib/ruby_scribe/version.rb
82
+ - lib/ruby_scribe.rb
83
+ - lib/tasks/scribe.rake
84
+ - spec/examples/simple_class_with_methods.rb
85
+ - spec/proprocessor_spec.rb
86
+ - spec/spec_helper.rb
87
+ - spec/strategy_spec.rb
88
+ - LICENSE
89
+ - Rakefile
90
+ - README.rdoc
91
+ - TODO.rdoc
92
+ has_rdoc: true
93
+ homepage: http://github.com/rubiety/ruby_scribe
94
+ licenses: []
95
+
96
+ post_install_message:
97
+ rdoc_options: []
98
+
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ hash: 3
107
+ segments:
108
+ - 0
109
+ version: "0"
110
+ required_rubygems_version: !ruby/object:Gem::Requirement
111
+ none: false
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ hash: 19
116
+ segments:
117
+ - 1
118
+ - 3
119
+ - 4
120
+ version: 1.3.4
121
+ requirements: []
122
+
123
+ rubyforge_project: ruby_scribe
124
+ rubygems_version: 1.3.7
125
+ signing_key:
126
+ specification_version: 3
127
+ summary: Generates formatted ruby code from S-expressions (like from ruby_parser).
128
+ test_files: []
129
+