sorcerer 0.3.7 → 0.3.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,135 +1,156 @@
1
- h1. Sorcerer -- Recovering the Source
1
+ # Sorcerer -- Recovering the Source
2
2
 
3
- p. Sorcerer will generate Ruby code from a Ripper-like abstract syntax
3
+ | Master |
4
+ | :----: |
5
+ | [![Master Build Status](https://secure.travis-ci.org/jimweirich/sorcerer.png?branch=master)](https://secure.travis-ci.org/jimweirich/sorcerer) |
6
+
7
+ Sorcerer will generate Ruby code from a Ripper-like abstract syntax
4
8
  tree (i.e. S-Expressions).
5
9
 
6
- p. Sorcerer is targetted mainly at small snippets of Ruby code,
7
- expressable in a single line. Longer examples may be re-sourced, but
10
+ Sorcerer is targetted mainly at small snippets of Ruby code,
11
+ expressable in a single line. Longer examples may be re-sourced, but
8
12
  they will be rendered in a single line format.
9
13
 
10
- *Version: 0.3.1*
11
-
12
- h2. Limitations
14
+ **Version: 0.3.7**
13
15
 
14
- Sorcerer is only testing on Ruby 1.9.
16
+ ## Limitations
15
17
 
16
- bq. <em>Technically, Sorcerer should work on Ruby 1.8, but since Ripper is
17
- 1.9 I've only tried it on that platform.</em>
18
+ Sorcerer is only tested on Ruby 1.9.
18
19
 
19
- h2. Links
20
+ ## Links
20
21
 
21
- Documents :: http://github.com/jimweirich/sorcerer
22
- Git Clone :: git://github.com/jimweirich/sorcerer.git
23
- Issues / Bug Tracking :: https://github.com/jimweirich/sorcerer/issues
24
- Continuous Integration :: http://travis-ci.org/#!/jimweirich/sorcerer
22
+ | Description | Link |
23
+ | :---: | :---: |
24
+ | Documents | http://github.com/jimweirich/sorcerer |
25
+ | Git Clone | git://github.com/jimweirich/sorcerer.git |
26
+ | Issues / Bug Tracking | https://github.com/jimweirich/sorcerer/issues |
27
+ | Continuous Integration | http://travis-ci.org/#!/jimweirich/sorcerer |
25
28
 
26
- h2. Examples
29
+ ## Examples
27
30
 
28
- <pre style="background: LightGray">
31
+ ```ruby
29
32
  sexp = [:binary,
30
33
  [:var_ref, [:@ident, "a", [1, 0]]],
31
34
  :+,
32
35
  [:var_ref, [:@ident, "b", [1, 4]]]]
33
36
  puts Sorcerer.source(sexp)
34
- </pre>
37
+ ```
35
38
 
36
39
  will generate
37
40
 
38
- <pre style="background: LightGray">
41
+ ```ruby
39
42
  a + b
40
- </pre>
43
+ ```
41
44
 
42
- Ripper may be used to produce the s-expressions used by Sorcerer. The following will produce the same output.
45
+ Ripper may be used to produce the s-expressions used by Sorcerer. The
46
+ following will produce the same output.
43
47
 
44
- <pre style="background: LightGrey">
48
+ ```ruby
45
49
  sexp = Ripper::SexpBuilder.new("a + b").parse
46
50
  puts Sorcerer.source(sexp)
47
- </pre>
51
+ ```
48
52
 
49
- h2. Options
53
+ ## Options
50
54
 
51
- h3. No Options
55
+ ### No Options
52
56
 
53
57
  By default, sorcerer will output its source in single line mode.
54
58
 
55
59
  For example, given:
56
60
 
57
- <pre style="background: LightGrey">
61
+ ```ruby
58
62
  sexp = Ripper::SexpBuilder.new("def foo; bar; end").parse
59
- </pre>
63
+ ```
60
64
 
61
65
  Then the following
62
66
 
63
- <pre style="background: LightGrey">
67
+ ```ruby
64
68
  puts Sorcerer.source(sexp)
65
- </pre>
69
+ ```
66
70
 
67
71
  generates single line output (the default):
68
72
 
69
- <pre style="background: LightBlue">
73
+ ```ruby
70
74
  def foo; bar; end
71
- </pre>
75
+ ```
72
76
 
73
- h3. Multi-Line Output
77
+ ### Multi-Line Output
74
78
 
75
79
  If you want multi-line output of source, add the multiline option to
76
80
  the source command.
77
81
 
78
82
  For example, given the sexp generated above, then this
79
83
 
80
- <pre style="background: LightGrey">
84
+ ```ruby
81
85
  puts Sorcerer.source(sexp, multiline: true)
82
- </pre>
86
+ ```
83
87
 
84
88
  generates multi-line output
85
89
 
86
- <pre style="background: LightBlue">
90
+ ```ruby
87
91
  def foo
88
92
  bar
89
93
  end
90
- </pre>
94
+ ```
91
95
 
92
96
  (Note that all multi-line output will have a final newline.)
93
97
 
94
- h3. Indentation
98
+ ### Indentation
95
99
 
96
100
  By default, sorcerer does not indent its multiline output. Adding the
97
101
  "indent" option will cause the output to be indented.
98
102
 
99
103
  For example, given the sexp generated above, then the following
100
104
 
101
- <pre style="background: LightGrey">
105
+ ```ruby
102
106
  puts Sorcerer.source(sexp, indent: true)
103
- </pre>
107
+ ```
104
108
 
105
109
  generates indented output:
106
110
 
107
- <pre style="background: LightBlue">
111
+ ```ruby
108
112
  def foo
109
113
  bar
110
114
  end
111
- </pre>
115
+ ```
112
116
 
113
- h3. Debugging Output
117
+ ### Debugging Output
114
118
 
115
119
  If you wish to see the S-Expressions processed by Sorcerer and the
116
120
  output emitted, then use the debug option:
117
121
 
118
- <pre style="background: LightGrey">
122
+ ```ruby
119
123
  puts Sorcerer.source(sexp, debug: true)
120
- </pre>
124
+ ```
121
125
 
122
- h2. History
126
+ ## History
123
127
 
124
- * 0.0.7 - Basic single line version
128
+ * 0.3.9 - Support %i{} and %I{}.
125
129
 
126
- * 0.1.0 - Added support for multi-line output. Improved rendering of a
127
- number of constructs
130
+ * 0.3.8 - Include constants in sub-expressions.
128
131
 
129
- * 0.2.0 - Added support for indented output.
132
+ * 0.3.7 - Include array in sub-expressions.
130
133
 
131
- * 0.3.0 - New hash literal support. Multi-line output always end with
132
- a newline.
134
+ * 0.3.6 - Support 'defined?'. Suppress nil, true, false in
135
+ sub-expressions.
136
+
137
+ * 0.3.5 - Add handler for mrhs_new.
138
+
139
+ * 0.3.4 - Support 'meth a, b'.
140
+
141
+ * 0.3.3 - Fix unary not.
142
+
143
+ * 0.3.2 - Support 'def mod.method' syntax.
133
144
 
134
145
  * 0.3.1 - 1.9.3 support. Indenting stabby procs. RedCloth not required
135
146
  for testing.
147
+
148
+ * 0.3.0 - New hash literal support. Multi-line output always end with
149
+ a newline.
150
+
151
+ * 0.2.0 - Added support for indented output.
152
+
153
+ * 0.1.0 - Added support for multi-line output. Improved rendering of a
154
+ number of constructs
155
+
156
+ * 0.0.7 - Basic single line version
data/Rakefile CHANGED
@@ -20,7 +20,7 @@ RUBY = ENV['RUBY19'] || 'ruby19'
20
20
  PKG_VERSION = Sorcerer::VERSION
21
21
 
22
22
  PKG_FILES = FileList[
23
- 'README.textile',
23
+ 'README.md',
24
24
  'Rakefile',
25
25
  'doc/*',
26
26
  'rakelib/*',
@@ -30,7 +30,6 @@ PKG_FILES = FileList[
30
30
 
31
31
  BASE_RDOC_OPTIONS = [
32
32
  '--line-numbers', '--inline-source',
33
- '--main' , 'README.textile',
34
33
  '--title', 'Rake -- Ruby Make'
35
34
  ]
36
35
 
@@ -154,7 +154,7 @@ module Sorcerer
154
154
  false
155
155
  end
156
156
 
157
- def params(normal_args, default_args, rest_args, unknown, block_arg)
157
+ def params(normal_args, default_args, rest_arg, unknown, keyw_args, opts_arg, block_arg)
158
158
  first = true
159
159
  if normal_args
160
160
  normal_args.each do |sx|
@@ -170,9 +170,22 @@ module Sorcerer
170
170
  resource(sx[1])
171
171
  end
172
172
  end
173
- if rest_args
173
+ if rest_arg
174
174
  first = emit_separator(", ", first)
175
- resource(rest_args)
175
+ resource(rest_arg)
176
+ end
177
+ if keyw_args
178
+ keyw_args.each do |sx|
179
+ first = emit_separator(", ", first)
180
+ resource(sx[0])
181
+ emit(" ")
182
+ resource(sx[1])
183
+ end
184
+ end
185
+ if opts_arg
186
+ first = emit_separator(", ", first)
187
+ emit("**")
188
+ emit(opts_arg[1])
176
189
  end
177
190
  if block_arg
178
191
  first = emit_separator(", ", first)
@@ -180,10 +193,22 @@ module Sorcerer
180
193
  end
181
194
  end
182
195
 
196
+ def quoted_word_add?(sexp)
197
+ sexp &&
198
+ sexp[1] &&
199
+ [:words_add, :qwords_add, :qsymbols_add, :symbols_add].include?(sexp[1].first)
200
+ end
201
+
202
+ def quoted_word_new?(sexp)
203
+ sexp &&
204
+ sexp[1] &&
205
+ [:qwords_new, :words_new, :qsymbols_new, :symbols_new].include?(sexp[1].first)
206
+ end
207
+
183
208
  def words(marker, sexp)
184
209
  emit("%#{marker}{") if @word_level == 0
185
210
  @word_level += 1
186
- if sexp[1] != [:qwords_new] && sexp[1] != [:words_new]
211
+ if !quoted_word_new?(sexp)
187
212
  resource(sexp[1])
188
213
  emit(" ")
189
214
  end
@@ -350,8 +375,7 @@ module Sorcerer
350
375
  :args_prepend => NYI,
351
376
  :array => lambda { |sexp|
352
377
  if !MISSES_ARRAY_NODE_FOR_WORDS &&
353
- sexp[1] &&
354
- [:words_add, :qwords_add].include?(sexp[1].first)
378
+ quoted_word_add?(sexp)
355
379
  resource(sexp[1])
356
380
  else
357
381
  emit("[")
@@ -683,7 +707,11 @@ module Sorcerer
683
707
  },
684
708
  :param_error => NYI,
685
709
  :params => lambda { |sexp|
686
- params(sexp[1], sexp[2], sexp[3], sexp[4], sexp[5])
710
+ if sexp.size == 8
711
+ params(sexp[1], sexp[2], sexp[3], sexp[4], sexp[5], sexp[6], sexp[7])
712
+ else
713
+ params(sexp[1], sexp[2], sexp[3], sexp[4],nil, nil, sexp[5])
714
+ end
687
715
  },
688
716
  :paren => lambda { |sexp|
689
717
  emit("(")
@@ -692,6 +720,10 @@ module Sorcerer
692
720
  },
693
721
  :parse_error => NYI,
694
722
  :program => PASS1,
723
+ :qsymbols_add => lambda { |sexp|
724
+ words("i", sexp)
725
+ },
726
+ :qsymbols_new => NOOP,
695
727
  :qwords_add => lambda { |sexp|
696
728
  words("w", sexp)
697
729
  },
@@ -789,6 +821,10 @@ module Sorcerer
789
821
  resource(sexp[1])
790
822
  },
791
823
  :symbol_literal => PASS1,
824
+ :symbols_add => lambda { |sexp|
825
+ words("I", sexp)
826
+ },
827
+ :symbols_new => NOOP,
792
828
  :top_const_field => NYI,
793
829
  :top_const_ref => NYI,
794
830
  :unary => lambda { |sexp|
@@ -46,8 +46,13 @@ module Sorcerer
46
46
  when :call, :method_add_block, :method_add_arg
47
47
  @result << sexp
48
48
  method_sexp(sexp)
49
+ when :const_path_ref
50
+ @result << sexp
51
+ recur(sexp[1])
49
52
  when :@kw
50
53
  # ignore
54
+ when :@const
55
+ @result << sexp
51
56
  when :zsuper, :super
52
57
  @result << sexp
53
58
  list_sexp(sexp)
@@ -2,7 +2,7 @@ module Sorcerer
2
2
  VERSION_NUMBERS = [
3
3
  VERSION_MAJOR = 0,
4
4
  VERSION_MINOR = 3,
5
- VERSION_BUILD = 7,
5
+ VERSION_BUILD = 9,
6
6
  ]
7
7
 
8
8
  VERSION = VERSION_NUMBERS.join('.')
data/rakelib/testing.rake CHANGED
@@ -4,6 +4,6 @@
4
4
  Rake::TestTask.new(:test) do |t|
5
5
  t.warning = true
6
6
  t.verbose = false
7
+ t.libs << "test"
7
8
  t.test_files = FileList["test/**/*_test.rb"]
8
9
  end
9
-
@@ -0,0 +1,76 @@
1
+ module AssertResource
2
+
3
+ # Assert that a string can be parsed and then resourced without changes.
4
+ def assert_resource(string, options={})
5
+ assert_equal string, source(string, options)
6
+ end
7
+
8
+ # Assert that a string can be resourced properly in all the various
9
+ # output modes:
10
+ #
11
+ # * single line
12
+ # * multi-line
13
+ # * indentation
14
+ #
15
+ # Special markup is supported in the string to indicate different
16
+ # expected output. The string is expressed in single line mode with
17
+ # the following interpretation:
18
+ #
19
+ # * "; " is expected to be literal in single line mode and a newline
20
+ # in multi-line and indented modes.
21
+ #
22
+ # * "~" is expected to be a space in single line mode and a newline
23
+ # in multi-line and indented modes.
24
+ #
25
+ # * "#" is expected to be a tabbed indent in indent mode and a null
26
+ # string in single line and multi-line modes.
27
+ #
28
+ def assert_resource_lines(string, options={})
29
+ assert_resource_for_mode(
30
+ string,
31
+ options.merge(multiline: false)) { |s|
32
+ for_single_line(s)
33
+ }
34
+ assert_resource_for_mode(
35
+ string,
36
+ options.merge(multiline: true)) { |s|
37
+ for_multi_line(s)
38
+ }
39
+ assert_resource_for_mode(
40
+ string,
41
+ options.merge(indent: true)) { |s|
42
+ for_indented(s)
43
+ }
44
+ end
45
+
46
+ # Assert the string is correctly resourced given the options and the
47
+ # block conversion.
48
+ def assert_resource_for_mode(string, options={})
49
+ expectation = yield(string)
50
+ assert_equal expectation, source(expectation, options)
51
+ end
52
+
53
+ def for_single_line(string)
54
+ string.
55
+ gsub(/\bTHEN~/, "then ").
56
+ gsub(/~/, " ").
57
+ gsub(/#/,'')
58
+ end
59
+
60
+ def for_multi_line(string)
61
+ string.
62
+ gsub(/\b THEN~/, "; ").
63
+ gsub(/~/, "\n").
64
+ gsub(/; /, "\n").
65
+ gsub(/#/,'') + "\n"
66
+ end
67
+
68
+ def for_indented(string)
69
+ string.
70
+ gsub(/\b THEN~/, "; ").
71
+ gsub(/~/, "\n").
72
+ gsub(/; /, "\n").
73
+ gsub(/#/,' ') + "\n"
74
+ end
75
+
76
+ end
@@ -3,82 +3,12 @@
3
3
  require 'test/unit'
4
4
  require 'ripper'
5
5
  require 'sorcerer'
6
+ require 'assert_resource_helper'
6
7
 
7
- class SourcerTest < Test::Unit::TestCase
8
- private
9
-
10
- # Assert that a string can be parsed and then resourced without changes.
11
- def assert_resource(string, options={})
12
- assert_equal string, source(string, options)
13
- end
14
-
15
- # Assert that a string can be resourced properly in all the various
16
- # output modes:
17
- #
18
- # * single line
19
- # * multi-line
20
- # * indentation
21
- #
22
- # Special markup is supported in the string to indicate different
23
- # expected output. The string is expressed in single line mode with
24
- # the following interpretation:
25
- #
26
- # * "; " is expected to be literal in single line mode and a newline
27
- # in multi-line and indented modes.
28
- #
29
- # * "~" is expected to be a space in single line mode and a newline
30
- # in multi-line and indented modes.
31
- #
32
- # * "#" is expected to be a tabbed indent in indent mode and a null
33
- # string in single line and multi-line modes.
34
- #
35
- def assert_resource_lines(string, options={})
36
- assert_resource_for_mode(
37
- string,
38
- options.merge(multiline: false)) { |s|
39
- for_single_line(s)
40
- }
41
- assert_resource_for_mode(
42
- string,
43
- options.merge(multiline: true)) { |s|
44
- for_multi_line(s)
45
- }
46
- assert_resource_for_mode(
47
- string,
48
- options.merge(indent: true)) { |s|
49
- for_indented(s)
50
- }
51
- end
52
-
53
- # Assert the string is correctly resourced given the options and the
54
- # block conversion.
55
- def assert_resource_for_mode(string, options={})
56
- expectation = yield(string)
57
- assert_equal expectation, source(expectation, options)
58
- end
59
-
60
- def for_single_line(string)
61
- string.
62
- gsub(/\bTHEN~/, "then ").
63
- gsub(/~/, " ").
64
- gsub(/#/,'')
65
- end
8
+ class ResourceTest < Test::Unit::TestCase
9
+ include AssertResource
66
10
 
67
- def for_multi_line(string)
68
- string.
69
- gsub(/\b THEN~/, "; ").
70
- gsub(/~/, "\n").
71
- gsub(/; /, "\n").
72
- gsub(/#/,'') + "\n"
73
- end
74
-
75
- def for_indented(string)
76
- string.
77
- gsub(/\b THEN~/, "; ").
78
- gsub(/~/, "\n").
79
- gsub(/; /, "\n").
80
- gsub(/#/,' ') + "\n"
81
- end
11
+ private
82
12
 
83
13
  def quietly
84
14
  original_verbosity = $VERBOSE
@@ -353,6 +283,13 @@ class SourcerTest < Test::Unit::TestCase
353
283
  assert_resource "/a/i"
354
284
  end
355
285
 
286
+ def test_can_source_symbol_quotes
287
+ if RUBY_VERSION >= "2.0"
288
+ assert_resource "%i{a b}"
289
+ assert_resource "%I{a b}"
290
+ end
291
+ end
292
+
356
293
  def test_can_source_range
357
294
  assert_resource "1..10"
358
295
  assert_resource "1...10"
@@ -636,12 +573,20 @@ class SourcerTest < Test::Unit::TestCase
636
573
  assert_resource_lines "def f(); end"
637
574
  assert_resource_lines "def f(a); end"
638
575
  assert_resource_lines "def f(a, b); end"
576
+ assert_resource_lines "def f(a, b=1); end"
639
577
  assert_resource_lines "def f(a, *args); end"
640
578
  assert_resource_lines "def f(a, *args, &block); end"
641
579
  assert_resource_lines "def f(a); #x; end"
642
580
  assert_resource_lines "def f(a); #x; #y; end"
643
581
  end
644
582
 
583
+ if RUBY_VERSION >= "2.0.0"
584
+ def test_can_source_ruby2_defs
585
+ assert_resource_lines "def f(a, b=1, *args, c: 2, **opts, &block); end"
586
+ assert_resource_lines "def f(a, aa, b=1, bb=2, *args, c: 3, cc: 4, **opts, &block); end"
587
+ end
588
+ end
589
+
645
590
  def test_can_source_def_self
646
591
  assert_resource_lines "def self.f; end"
647
592
  assert_resource_lines "def self.f(a, *args, &block); #x; #y; end"
@@ -4,7 +4,7 @@ require 'ripper'
4
4
  require 'pp'
5
5
 
6
6
  class SubexpressionTest < Test::Unit::TestCase
7
- def assert_subexpressions code, subexpressions, debug=false
7
+ def assert_subexpressions(code, subexpressions, debug=false)
8
8
  sexp = Ripper::SexpBuilder.new(code).parse
9
9
  if debug
10
10
  pp sexp
@@ -140,4 +140,17 @@ class SubexpressionTest < Test::Unit::TestCase
140
140
  ]
141
141
  end
142
142
 
143
+ def test_constants_are_included
144
+ assert_subexpressions "a || A", [
145
+ "a || A",
146
+ "a",
147
+ "A",
148
+ ]
149
+ assert_subexpressions "A::B::C", [
150
+ "A::B::C",
151
+ "A::B",
152
+ "A",
153
+ ]
154
+ end
155
+
143
156
  end
metadata CHANGED
@@ -1,63 +1,80 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: sorcerer
3
- version: !ruby/object:Gem::Version
4
- version: 0.3.7
3
+ version: !ruby/object:Gem::Version
4
+ hash: 1
5
5
  prerelease:
6
+ segments:
7
+ - 0
8
+ - 3
9
+ - 9
10
+ version: 0.3.9
6
11
  platform: ruby
7
- authors:
12
+ authors:
8
13
  - Jim Weirich
9
14
  autorequire:
10
15
  bindir: bin
11
16
  cert_chain: []
12
- date: 2012-12-27 00:00:00.000000000 Z
17
+
18
+ date: 2013-02-04 00:00:00 Z
13
19
  dependencies: []
14
- description: Generate the original Ruby source from a Ripper-style abstract syntax
15
- tree.
20
+
21
+ description: Generate the original Ruby source from a Ripper-style abstract syntax tree.
16
22
  email: jim.weirich@gmail.com
17
23
  executables: []
24
+
18
25
  extensions: []
26
+
19
27
  extra_rdoc_files: []
20
- files:
21
- - README.textile
28
+
29
+ files:
30
+ - README.md
22
31
  - Rakefile
23
32
  - doc/jamis.rb
24
33
  - rakelib/git.rake
25
34
  - rakelib/readme.rake
26
35
  - rakelib/testing.rake
27
- - lib/sorcerer.rb
28
36
  - lib/sorcerer/resource.rb
29
37
  - lib/sorcerer/subexpression.rb
30
38
  - lib/sorcerer/version.rb
39
+ - lib/sorcerer.rb
40
+ - test/assert_resource_helper.rb
31
41
  - test/sorcerer/resource_test.rb
32
42
  - test/sorcerer/subexpression_test.rb
33
43
  homepage: http://github.com/jimweirich/sorcerer
34
44
  licenses: []
45
+
35
46
  post_install_message:
36
- rdoc_options:
47
+ rdoc_options:
37
48
  - --line-numbers
38
49
  - --inline-source
39
- - --main
40
- - README.textile
41
50
  - --title
42
51
  - Rake -- Ruby Make
43
- require_paths:
52
+ require_paths:
44
53
  - lib
45
- required_ruby_version: !ruby/object:Gem::Requirement
54
+ required_ruby_version: !ruby/object:Gem::Requirement
46
55
  none: false
47
- requirements:
48
- - - ! '>='
49
- - !ruby/object:Gem::Version
50
- version: '0'
51
- required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ hash: 3
60
+ segments:
61
+ - 0
62
+ version: "0"
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
64
  none: false
53
- requirements:
54
- - - ! '>='
55
- - !ruby/object:Gem::Version
56
- version: '0'
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ hash: 3
69
+ segments:
70
+ - 0
71
+ version: "0"
57
72
  requirements: []
73
+
58
74
  rubyforge_project: sorcerer
59
75
  rubygems_version: 1.8.24
60
76
  signing_key:
61
77
  specification_version: 3
62
78
  summary: Generate Source from Ripper ASTs
63
79
  test_files: []
80
+