arst 0.0.1 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +9 -2
- data/README.md +230 -21
- data/VERSION +1 -1
- data/arst.gemspec +2 -3
- data/examples/Rakefile +5 -0
- data/examples/simple.arst +16 -0
- data/lib/arst.rb +8 -0
- data/lib/arst/generator.rb +14 -0
- data/lib/arst/generator/arst.rb +37 -0
- data/lib/arst/generator/base.rb +29 -0
- data/lib/arst/generator/c.rb +11 -0
- data/lib/arst/generator/ruby.rb +164 -0
- data/lib/arst/helpers.rb +13 -0
- data/lib/arst/node.rb +25 -0
- data/lib/arst/node/base.rb +39 -0
- data/lib/arst/node/class.rb +32 -0
- data/lib/arst/node/extend.rb +14 -0
- data/lib/arst/node/include.rb +14 -0
- data/lib/arst/node/module.rb +14 -0
- data/lib/arst/node/namable.rb +26 -0
- data/lib/arst/node/root.rb +11 -0
- data/lib/arst/parser.rb +64 -0
- data/lib/arst/rake_task.rb +62 -0
- metadata +40 -49
- data/examples/indentation_sensitive.rb +0 -84
- data/examples/simple.rb +0 -31
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 14e94c66c9581aa1b34916e7d471a03d72ae29bd
|
4
|
+
data.tar.gz: 26ad558b52a7621a317545033aa039b9b5ce50b2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 049fac53c834139edd2bb171b97cd526498d4c5bf8241ba3793998d5f1d8ccd518c6fb5a6e82be2a30efbe4df96e4fe7bc6bf941ee2b9b101ec23d169086fd50
|
7
|
+
data.tar.gz: fe66efb68766698e169712774342a3090af78423e29cf9cff2e8b250a47ebedb82e690a22bbd2f57cdd517965700a11f1058fd98eb78b0a2d2b8e46c3c9adc4a
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
arst (0.0.
|
4
|
+
arst (0.0.3)
|
5
5
|
active_support (~> 3.0.0)
|
6
6
|
parslet (~> 1.5.0)
|
7
|
+
rake (~> 10.0.0)
|
7
8
|
version (~> 1.0.0)
|
8
9
|
|
9
10
|
GEM
|
@@ -40,11 +41,17 @@ GEM
|
|
40
41
|
coderay (~> 1.0.5)
|
41
42
|
method_source (~> 0.8)
|
42
43
|
slop (~> 3.4)
|
44
|
+
pry (0.9.12-x86-mingw32)
|
45
|
+
coderay (~> 1.0.5)
|
46
|
+
method_source (~> 0.8)
|
47
|
+
slop (~> 3.4)
|
48
|
+
win32console (~> 1.3)
|
43
49
|
rake (10.0.4)
|
44
50
|
rb-fsevent (0.9.3)
|
45
51
|
slop (3.4.4)
|
46
52
|
thor (0.18.1)
|
47
53
|
version (1.0.0)
|
54
|
+
win32console (1.3.2-x86-mingw32)
|
48
55
|
|
49
56
|
PLATFORMS
|
50
57
|
ruby
|
@@ -56,5 +63,5 @@ DEPENDENCIES
|
|
56
63
|
cocaine (~> 0.5.0)
|
57
64
|
guard-bundler (~> 1.0.0)
|
58
65
|
guard-shell (~> 0.5.0)
|
59
|
-
|
66
|
+
pry
|
60
67
|
rb-fsevent (~> 0.9.0)
|
data/README.md
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
# ARST
|
2
2
|
|
3
|
-
Abstract Ruby Syntax Tree (ARST) is a high-level language syntax denoting the object domain of a Ruby project.
|
3
|
+
Abstract Ruby Syntax Tree (ARST) is a high-level language syntax denoting the object domain of a Ruby project and a polyglot source code generator.
|
4
4
|
|
5
5
|
ARST can be used to generate:
|
6
6
|
|
7
|
-
* Pure Ruby
|
7
|
+
* Pure Ruby code
|
8
8
|
* C Ruby extensions
|
9
|
+
* Java Ruby extensions
|
9
10
|
* Test::Unit, MiniTest::Unit, MiniTest::Spec, or RSpec tests
|
10
11
|
* GraphViz graphs
|
11
12
|
* Custom output
|
@@ -18,15 +19,15 @@ ARST files can also be generated from existing projects which allows:
|
|
18
19
|
|
19
20
|
Integrations:
|
20
21
|
|
21
|
-
*
|
22
|
+
* Rake (baked in)
|
22
23
|
* [Thor](https://github.com/RyanScottLewis/thor-arst)
|
23
24
|
* [Guard](https://github.com/RyanScottLewis/guard-arst)
|
24
25
|
|
25
26
|
Generators:
|
26
27
|
|
27
|
-
* ARST::Generator::Ruby (baked
|
28
|
-
* ARST::Generator::
|
29
|
-
* [ARST::Generator::
|
28
|
+
* ARST::Generator::Ruby (baked in)
|
29
|
+
* ARST::Generator::C (baked in)
|
30
|
+
* [ARST::Generator::Java](https://github.com/RyanScottLewis/arst-generator-java)
|
30
31
|
* [ARST::Generator::Test::Unit](https://github.com/RyanScottLewis/arst-generator-test-unit)
|
31
32
|
* [ARST::Generator::MiniTest::Unit](https://github.com/RyanScottLewis/arst-generator-minitest-unit)
|
32
33
|
* [ARST::Generator::MiniTest::Spec](https://github.com/RyanScottLewis/arst-generator-minitest-spec)
|
@@ -53,6 +54,9 @@ This means that most syntax highlighters for Ruby will also work for ARST.
|
|
53
54
|
* `class ClassName < SuperClassName`
|
54
55
|
* `include ModuleName`
|
55
56
|
* `extend ModuleName`
|
57
|
+
|
58
|
+
**Not Yet Implemented:**
|
59
|
+
|
56
60
|
* `def instance_method(arg1, *other_args)` (and anything else accepted method arguments in Ruby's syntax)
|
57
61
|
* `def self.class_method(arg1, opts={})` (and anything else accepted method arguments in Ruby's syntax)
|
58
62
|
|
@@ -61,42 +65,247 @@ This means that most syntax highlighters for Ruby will also work for ARST.
|
|
61
65
|
ARST is an indentation-sensitive syntax meaning that the following are **not** equivalent:
|
62
66
|
|
63
67
|
<table width="100%"><tr><td>
|
64
|
-
|
68
|
+
<pre>
|
65
69
|
module Foo
|
66
70
|
module Bar
|
67
|
-
|
71
|
+
</pre>
|
68
72
|
</td><td>
|
69
|
-
|
73
|
+
<pre>
|
70
74
|
module Foo
|
71
75
|
module Bar
|
72
|
-
|
73
|
-
</td></tr
|
76
|
+
</pre>
|
77
|
+
</td></tr></table>
|
74
78
|
|
75
|
-
When interpreting the ARST syntax, the parser accepts
|
76
|
-
at the
|
77
|
-
Valid whitespace characters are the space
|
79
|
+
When interpreting the ARST syntax, the parser accepts 2 identical sequential whitespace characters
|
80
|
+
at the start of a line as an "indentation step".
|
81
|
+
Valid whitespace characters are the space and tab characters.
|
78
82
|
|
79
83
|
Once the first indentation step is found while parsing, all subsequent indentation steps must contain the same
|
80
84
|
amount of whitespace characters as the first step:
|
81
85
|
|
82
86
|
<table width="100%"><tr><td>
|
83
|
-
|
84
|
-
|
87
|
+
<b>Valid</b>
|
88
|
+
<pre>
|
85
89
|
module Foo
|
86
90
|
module Bar
|
87
91
|
module Baz
|
88
|
-
|
92
|
+
</pre>
|
89
93
|
</td><td>
|
90
|
-
|
91
|
-
|
94
|
+
<b>Invalid</b>
|
95
|
+
<pre>
|
92
96
|
module Foo
|
93
97
|
module Bar
|
94
98
|
module Baz
|
95
|
-
|
96
|
-
</td></tr
|
99
|
+
</pre>
|
100
|
+
</td></tr></table>
|
97
101
|
|
98
102
|
## Usage
|
99
103
|
|
104
|
+
### Constructing ARST file
|
105
|
+
|
106
|
+
The first step is to create an `.arst` file within your project. There is no convention as to where to place this file,
|
107
|
+
but I like to put it in the root directory and name it the same as my project, like a `.gemspec` file.
|
108
|
+
|
109
|
+
`stupid_record.arst`
|
110
|
+
|
111
|
+
```rb
|
112
|
+
module StupidModel
|
113
|
+
module Validations
|
114
|
+
module Callbacks
|
115
|
+
module Serialization
|
116
|
+
module ClassMethods
|
117
|
+
module InstanceMethods
|
118
|
+
class Base
|
119
|
+
extend Callbacks
|
120
|
+
include Validations
|
121
|
+
include Serialization
|
122
|
+
module StupidRecord
|
123
|
+
module Persistence
|
124
|
+
class Base < StupidModel::Base
|
125
|
+
include Persistence
|
126
|
+
```
|
127
|
+
|
128
|
+
### Setup Rake task
|
129
|
+
|
130
|
+
`Rakefile`
|
131
|
+
|
132
|
+
```rb
|
133
|
+
require 'arst/rake_task'
|
134
|
+
|
135
|
+
ARST::RakeTask.new do |t|
|
136
|
+
t.generate(:ruby, input_path: 'stupid_record.arst', split_files: false, output_path: 'lib/stupid_record.rb')
|
137
|
+
end
|
138
|
+
```
|
139
|
+
|
140
|
+
### Generate your code
|
141
|
+
|
142
|
+
### Ruby
|
143
|
+
|
144
|
+
Running `rake arst:ruby` will generate the following Ruby code in the `lib/stupid_record.rb` file:
|
145
|
+
|
146
|
+
```rb
|
147
|
+
module StupidModel
|
148
|
+
module Validations
|
149
|
+
end
|
150
|
+
module Callbacks
|
151
|
+
end
|
152
|
+
module Serialization
|
153
|
+
module ClassMethods
|
154
|
+
end
|
155
|
+
module InstanceMethods
|
156
|
+
end
|
157
|
+
end
|
158
|
+
class Base
|
159
|
+
extend Callbacks
|
160
|
+
include Validations
|
161
|
+
include Serialization
|
162
|
+
end
|
163
|
+
end
|
164
|
+
module StupidRecord
|
165
|
+
module Persistence
|
166
|
+
end
|
167
|
+
class Base < StupidModel::Base
|
168
|
+
include Persistence
|
169
|
+
end
|
170
|
+
end
|
171
|
+
```
|
172
|
+
|
173
|
+
Tasty! We turned 14 lines into 24 lines, like magic! But wait.. this isn't how conventional Ruby projects file hierarchies
|
174
|
+
are structured. The above is great for generating simple example Ruby files, but what about bootstrapping an entire project?
|
175
|
+
|
176
|
+
Let's refactor our Rake task:
|
177
|
+
|
178
|
+
`Rakefile`
|
179
|
+
|
180
|
+
```rb
|
181
|
+
require 'arst/rake_task'
|
182
|
+
|
183
|
+
ARST::RakeTask.new do |t|
|
184
|
+
t.add_generator type: :ruby, input_path: 'stupid_record.arst', output_path: 'stupid_record/lib'
|
185
|
+
end
|
186
|
+
```
|
187
|
+
|
188
|
+
> Note: The `:split_files` option is `true` and the `output_path` option is `'lib'` by default in the Ruby generator.
|
189
|
+
> Each generator has it's own set of options.
|
190
|
+
|
191
|
+
Now, when we run the `rake arst:generate` task to generate our code, the project is bootstrapped in a more conventional manner:
|
192
|
+
|
193
|
+
`lib/stupid_model.rb`
|
194
|
+
|
195
|
+
```rb
|
196
|
+
require 'stupid_model/base'
|
197
|
+
|
198
|
+
module StupidModel
|
199
|
+
end
|
200
|
+
```
|
201
|
+
|
202
|
+
`lib/stupid_model/validations.rb`
|
203
|
+
|
204
|
+
```rb
|
205
|
+
module StupidModel
|
206
|
+
module Validations
|
207
|
+
end
|
208
|
+
end
|
209
|
+
```
|
210
|
+
|
211
|
+
`lib/stupid_model/callbacks.rb`
|
212
|
+
|
213
|
+
```rb
|
214
|
+
module StupidModel
|
215
|
+
module Callbacks
|
216
|
+
end
|
217
|
+
end
|
218
|
+
```
|
219
|
+
|
220
|
+
`lib/stupid_model/serialization.rb`
|
221
|
+
|
222
|
+
```rb
|
223
|
+
require 'stupid_model/serialization/class_methods'
|
224
|
+
require 'stupid_model/serialization/instance_methods'
|
225
|
+
|
226
|
+
module StupidModel
|
227
|
+
module Serialization
|
228
|
+
end
|
229
|
+
end
|
230
|
+
```
|
231
|
+
|
232
|
+
`lib/stupid_model/serialization/class_methods.rb`
|
233
|
+
|
234
|
+
```rb
|
235
|
+
module StupidModel
|
236
|
+
module Serialization
|
237
|
+
module ClassMethods
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
```
|
242
|
+
|
243
|
+
`lib/stupid_model/serialization/instance_methods.rb`
|
244
|
+
|
245
|
+
```rb
|
246
|
+
module StupidModel
|
247
|
+
module Serialization
|
248
|
+
module InstanceMethods
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
```
|
253
|
+
|
254
|
+
`lib/stupid_model/base.rb`
|
255
|
+
|
256
|
+
```rb
|
257
|
+
require 'stupid_model/validations'
|
258
|
+
require 'stupid_model/callbacks'
|
259
|
+
require 'stupid_model/serialization'
|
260
|
+
|
261
|
+
module StupidModel
|
262
|
+
class Base
|
263
|
+
extend Callbacks
|
264
|
+
include Validations
|
265
|
+
include Serialization
|
266
|
+
end
|
267
|
+
end
|
268
|
+
```
|
269
|
+
|
270
|
+
`lib/stupid_record.rb`
|
271
|
+
|
272
|
+
```rb
|
273
|
+
require 'stupid_record/base'
|
274
|
+
|
275
|
+
module StupidRecord
|
276
|
+
end
|
277
|
+
```
|
278
|
+
|
279
|
+
`lib/stupid_record/persistence.rb`
|
280
|
+
|
281
|
+
```rb
|
282
|
+
module StupidRecord
|
283
|
+
module Persistence
|
284
|
+
end
|
285
|
+
end
|
286
|
+
```
|
287
|
+
|
288
|
+
`lib/stupid_record/base.rb`
|
289
|
+
|
290
|
+
```rb
|
291
|
+
require 'stupid_model/base'
|
292
|
+
require 'stupid_record/persistence'
|
293
|
+
|
294
|
+
module StupidRecord
|
295
|
+
class Base < StupidModel::Base
|
296
|
+
include Persistence
|
297
|
+
end
|
298
|
+
end
|
299
|
+
```
|
300
|
+
|
301
|
+
Holy Moses! Now we're saving some typing!
|
302
|
+
This may not be exactly the code you were looking to generate, but it's close enough to start working quickly.
|
303
|
+
|
304
|
+
The ARST Ruby generator attempts to be as smart about adding `require` statements as possible.
|
305
|
+
|
306
|
+
> Warning: When we generate the files, they are OVERWRITTEN. Meaning you WILL LOSE CODE if the file already exists.
|
307
|
+
> There are plans in the *far* future for generating only missing nodes in the ARST and removing code that is NOT within the ARST.
|
308
|
+
|
100
309
|
## Copyright
|
101
310
|
|
102
311
|
Copyright © 2013 Ryan Scott Lewis <ryan@rynet.us>.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.3
|
data/arst.gemspec
CHANGED
@@ -11,15 +11,14 @@ Gem::Specification.new do |s|
|
|
11
11
|
# Dependencies
|
12
12
|
s.add_dependency 'active_support', '~> 3.0.0'
|
13
13
|
s.add_dependency 'parslet', '~> 1.5.0'
|
14
|
+
s.add_dependency 'rake', '~> 10.0.0'
|
14
15
|
s.add_dependency 'version', '~> 1.0.0'
|
15
16
|
# s.add_dependency 'polyglot', '~> 0.3.0'
|
16
17
|
s.add_development_dependency 'awesome_print', '~> 1.1.0'
|
17
18
|
s.add_development_dependency 'cocaine', '~> 0.5.0'
|
18
19
|
s.add_development_dependency 'guard-bundler', '~> 1.0.0'
|
19
20
|
s.add_development_dependency 'guard-shell', '~> 0.5.0'
|
20
|
-
s.add_development_dependency 'rake', '~> 10.0.0'
|
21
21
|
s.add_development_dependency 'rb-fsevent', '~> 0.9.0'
|
22
|
-
|
23
22
|
|
24
23
|
# Pragmatically set variables
|
25
24
|
s.homepage = "http://github.com/RyanScottLewis/#{s.name}"
|
@@ -27,7 +26,7 @@ Gem::Specification.new do |s|
|
|
27
26
|
s.description = s.summary
|
28
27
|
s.name = Pathname.new(__FILE__).basename('.gemspec').to_s
|
29
28
|
s.require_paths = ['lib']
|
30
|
-
s.files = Dir['{{Rake,Gem}file{.lock,},README*,VERSION,LICENSE,*.gemspec,lib
|
29
|
+
s.files = Dir['{{Rake,Gem}file{.lock,},README*,VERSION,LICENSE,*.gemspec,{lib,bin,examples,spec,test}/**/*}']
|
31
30
|
s.test_files = Dir['{examples,spec,test}/**/*']
|
32
31
|
|
33
32
|
end
|
data/examples/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
module StupidModel
|
2
|
+
module Validations
|
3
|
+
module Callbacks
|
4
|
+
module Serialization
|
5
|
+
module ClassMethods
|
6
|
+
module InstanceMethods
|
7
|
+
module OptionalMethods
|
8
|
+
class Base
|
9
|
+
extend Callbacks
|
10
|
+
include Validations
|
11
|
+
include Serialization
|
12
|
+
module StupidRecord
|
13
|
+
module Persistence
|
14
|
+
class Base < StupidModel::Base
|
15
|
+
include Persistence
|
16
|
+
include StupidModel::OptionalMethods
|
data/lib/arst.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'arst/generator/base'
|
2
|
+
|
3
|
+
module ARST
|
4
|
+
module Generator
|
5
|
+
|
6
|
+
class ARST < Base
|
7
|
+
|
8
|
+
protected
|
9
|
+
|
10
|
+
def parse_children(node, options={})
|
11
|
+
output = ''
|
12
|
+
|
13
|
+
node[:children].each do |node|
|
14
|
+
output << (options[:indent_char] * options[:indent_size]) * options[:depth]
|
15
|
+
|
16
|
+
if node[:module]
|
17
|
+
output << "module #{ node[:module] }"
|
18
|
+
elsif node[:class]
|
19
|
+
output << "class #{ node[:class] }"
|
20
|
+
output << " < #{ node[:superclass] }" if node[:superclass]
|
21
|
+
elsif node[:include]
|
22
|
+
output << "include #{ node[:include] }"
|
23
|
+
elsif node[:extend]
|
24
|
+
output << "extend #{ node[:extend] }"
|
25
|
+
end
|
26
|
+
|
27
|
+
output << "\n"
|
28
|
+
output << parse_children( node, options.merge(depth: options[:depth]+1) ) if node.has_key?(:children)
|
29
|
+
end
|
30
|
+
|
31
|
+
output
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|