ruby_scribe 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+