step_rewrite 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/{README.textile → LICENSE} +8 -12
- data/README.rdoc +143 -0
- data/lib/step_rewrite.rb +0 -1
- data/lib/step_rewrite/rewriter.rb +28 -34
- data/lib/step_rewrite/step_rewrite.rb +6 -6
- data/lib/step_rewrite/version.rb +1 -1
- data/spec/lib/rewriter_spec.rb +23 -0
- data/step_rewrite.gemspec +2 -2
- metadata +8 -12
- data/lib/step_rewrite/sexp_utilities.rb +0 -20
data/Gemfile.lock
CHANGED
data/{README.textile → LICENSE}
RENAMED
@@ -1,12 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
(The MIT License)
|
4
|
-
|
5
|
-
Copyright (c) 2008 FIX
|
1
|
+
Copyright (c) 2010 Vishnu Iyengar
|
6
2
|
|
7
3
|
Permission is hereby granted, free of charge, to any person obtaining
|
8
4
|
a copy of this software and associated documentation files (the
|
9
|
-
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
10
6
|
without limitation the rights to use, copy, modify, merge, publish,
|
11
7
|
distribute, sublicense, and/or sell copies of the Software, and to
|
12
8
|
permit persons to whom the Software is furnished to do so, subject to
|
@@ -15,10 +11,10 @@ the following conditions:
|
|
15
11
|
The above copyright notice and this permission notice shall be
|
16
12
|
included in all copies or substantial portions of the Software.
|
17
13
|
|
18
|
-
THE SOFTWARE IS PROVIDED
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19
15
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
20
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21
|
-
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
22
|
-
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
23
|
-
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
24
|
-
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
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,143 @@
|
|
1
|
+
= What is this for?
|
2
|
+
|
3
|
+
This gem tries to solve a very specific problem when working with evented I/O code.
|
4
|
+
Ideally, I suppose it would work with something like EventMachine[http://rubyeventmachine.com/], but I havent
|
5
|
+
worked enough with EventMachine to know if that's the case. Its meant for cases
|
6
|
+
where blocks are passed to methods solely to sequence a set of steps. Like in this example.
|
7
|
+
|
8
|
+
writeFile(path, "hello") do
|
9
|
+
File.open(path, "a") do |file|
|
10
|
+
write(file, "\nworld") do
|
11
|
+
close(file) do
|
12
|
+
read(path) do |data|
|
13
|
+
puts data.last
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
Traditionally blocks have been a lightweight strategy pattern. Not so with evented I/O.
|
21
|
+
While each function takes a block, this is merely to sequence the rest of the program
|
22
|
+
to execute after the function is executed.
|
23
|
+
To understand the context a little better read this[http://blog.vishnuiyengar.com/2010/10/changing-rules.html]
|
24
|
+
|
25
|
+
|
26
|
+
= Installation
|
27
|
+
gem install step_rewrite
|
28
|
+
|
29
|
+
After installing the gem, the quick and dirty way to use it is to include the
|
30
|
+
StepRewrite module in your code.
|
31
|
+
|
32
|
+
include StepRewrite
|
33
|
+
step do
|
34
|
+
path = "fileio.txt"
|
35
|
+
writeFile(path, "hello", &_)
|
36
|
+
file = File.open(path, "a", &_)
|
37
|
+
write(file, "\nworld", &_)
|
38
|
+
close(file, &_)
|
39
|
+
data = read(path, &_)
|
40
|
+
puts data.last
|
41
|
+
end
|
42
|
+
|
43
|
+
The block passed to step is rewritten so that everywhere you have a method
|
44
|
+
that takes &_ as a parameter, the rest of the code is passed as a block to it.
|
45
|
+
So step rewrites this code into the code above and THEN evaluates it.
|
46
|
+
|
47
|
+
= Rewrite Rules
|
48
|
+
Any code of the form
|
49
|
+
|
50
|
+
foo(&_)
|
51
|
+
bar
|
52
|
+
baz
|
53
|
+
|
54
|
+
gets rewritten to
|
55
|
+
|
56
|
+
foo do
|
57
|
+
bar
|
58
|
+
baz
|
59
|
+
end
|
60
|
+
|
61
|
+
return values from such functions are converted into arguments to the block
|
62
|
+
|
63
|
+
a = foo(&_)
|
64
|
+
bar(a)
|
65
|
+
baz
|
66
|
+
|
67
|
+
becomes
|
68
|
+
|
69
|
+
foo do |a|
|
70
|
+
bar(a)
|
71
|
+
baz
|
72
|
+
end
|
73
|
+
|
74
|
+
This allows an infinite degree of nesting
|
75
|
+
|
76
|
+
foo(&_)
|
77
|
+
bar(&_)
|
78
|
+
baz(&_)
|
79
|
+
qux
|
80
|
+
|
81
|
+
becomes
|
82
|
+
foo { bar { baz { qux } } }
|
83
|
+
|
84
|
+
existing blocks or lambda parameters are not touched.
|
85
|
+
|
86
|
+
= Other execution methods
|
87
|
+
|
88
|
+
If the name step clashes with a method in your code, you can instead use the module method
|
89
|
+
|
90
|
+
StepRewrite.step do
|
91
|
+
path = "fileio.txt"
|
92
|
+
writeFile(path, "hello", &_)
|
93
|
+
file = File.open(path, "a", &_)
|
94
|
+
write(file, "\nworld", &_)
|
95
|
+
close(file, &_)
|
96
|
+
data = read(path, &_)
|
97
|
+
puts data.last
|
98
|
+
end
|
99
|
+
|
100
|
+
if _ is a variable you are already using, you can configure the special callback identifier for
|
101
|
+
rewriting.
|
102
|
+
|
103
|
+
StepRewrite.step(:cb) do
|
104
|
+
path = "fileio.txt"
|
105
|
+
writeFile(path, "hello", &cb)
|
106
|
+
file = File.open(path, "a", &cb)
|
107
|
+
write(file, "\nworld", &cb)
|
108
|
+
close(file, &cb)
|
109
|
+
data = read(path, &cb)
|
110
|
+
puts data.last
|
111
|
+
end
|
112
|
+
|
113
|
+
= Define Method
|
114
|
+
|
115
|
+
The problem with the above approach is that it does not cache the result of rewriting
|
116
|
+
the code. If what you are writing is part of a long running server, the recommended
|
117
|
+
style is to define a method instead.
|
118
|
+
|
119
|
+
require 'step_rewrite/module'
|
120
|
+
|
121
|
+
class IO
|
122
|
+
define_step_method :hello_world do
|
123
|
+
path = "fileio.txt"
|
124
|
+
writeFile(path, "hello", &_)
|
125
|
+
file = File.open(path, "a", &_)
|
126
|
+
write(file, "\nworld", &_)
|
127
|
+
close(file, &_)
|
128
|
+
data = read(path, &_)
|
129
|
+
puts data.last
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
IO.new.hello_world
|
134
|
+
|
135
|
+
= How does this work?
|
136
|
+
|
137
|
+
This gem makes use of the ParseTree[https://rubygems.org/gems/ParseTree] gem to
|
138
|
+
extract the sexp out of any block and then rewrites it using various rules. This
|
139
|
+
code is converted back into Ruby using Ruby2Ruby[https://rubygems.org/gems/ruby2ruby]
|
140
|
+
and then evaled into a context
|
141
|
+
== Copyright
|
142
|
+
|
143
|
+
Copyright (c) 2010 Vishnu Iyengar. See LICENSE for details.
|
data/lib/step_rewrite.rb
CHANGED
@@ -6,6 +6,5 @@ require 'Ruby2Ruby'
|
|
6
6
|
$:.unshift(File.dirname(__FILE__)) unless
|
7
7
|
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
8
8
|
|
9
|
-
require "step_rewrite/sexp_utilities"
|
10
9
|
require "step_rewrite/rewriter"
|
11
10
|
require 'step_rewrite/step_rewrite'
|
@@ -1,7 +1,5 @@
|
|
1
1
|
module StepRewrite
|
2
2
|
class Rewriter < SexpProcessor
|
3
|
-
include SexpUtilities
|
4
|
-
|
5
3
|
def initialize(cb)
|
6
4
|
super()
|
7
5
|
self.strict = false
|
@@ -11,34 +9,37 @@ module StepRewrite
|
|
11
9
|
|
12
10
|
def process_block(exp)
|
13
11
|
exp.shift
|
14
|
-
result = exp.reverse.inject([],
|
12
|
+
result = exp.reverse.inject([]) {|acc, cur| accumulate(acc, process(cur))}
|
15
13
|
exp.clear
|
16
|
-
|
14
|
+
group_expr(result)
|
15
|
+
end
|
16
|
+
|
17
|
+
def group_expr(acc)
|
18
|
+
acc.size > 1 ? s(:block, *acc) : acc.first
|
19
|
+
end
|
20
|
+
|
21
|
+
def remove_block(exp)
|
22
|
+
exp.tap{|e| e[3].pop}
|
17
23
|
end
|
18
24
|
|
19
|
-
def
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
param = cur_exp
|
38
|
-
inner_exp = acc_exp.size > 1 ? s(:block, *acc_exp) : acc_exp.first
|
39
|
-
[s(*[:iter, next_exp, param] + [inner_exp].compact)]
|
40
|
-
else
|
41
|
-
acc_exp.unshift(process_inner_expr(cur_exp))
|
25
|
+
def new_exp_containing(acc)
|
26
|
+
lambda do |call_exp, param|
|
27
|
+
[s(*[:iter, remove_block(call_exp), param] + [group_expr(acc)].compact)]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def accumulate(acc, cur)
|
32
|
+
new_exp = new_exp_containing(acc)
|
33
|
+
if special_call?(cur) then
|
34
|
+
new_exp.call(cur, nil)
|
35
|
+
elsif cur.first == :lasgn && special_call?(cur[2])
|
36
|
+
new_exp.call(cur[2], s(:lasgn, cur[1]))
|
37
|
+
elsif cur.first == :masgn && special_call?(cur[2][1])
|
38
|
+
new_exp.call(cur[2][1], s(:masgn, s(:array, *cur[1][1..-1].to_a)))
|
39
|
+
elsif cur.first == :attrasgn && special_call?(cur[3][1])
|
40
|
+
new_exp.call(cur[3][1], s(:attrasgn, *cur[1..-2] + [s(:arglist)]))
|
41
|
+
else
|
42
|
+
acc.unshift(cur)
|
42
43
|
end
|
43
44
|
end
|
44
45
|
|
@@ -48,12 +49,5 @@ module StepRewrite
|
|
48
49
|
exp[3].last.first == :block_pass &&
|
49
50
|
exp[3].last.last[2] == @cb
|
50
51
|
end
|
51
|
-
|
52
|
-
def identify(exp)
|
53
|
-
return :special_call if special_call?(exp)
|
54
|
-
return :special_asgn if exp.first == :lasgn && special_call?(exp[2])
|
55
|
-
return :masgn if exp.first == :masgn && special_call?(exp[2][1])
|
56
|
-
return :attrasgn if exp.first == :attrasgn && special_call?(exp[3][1])
|
57
|
-
end
|
58
52
|
end
|
59
53
|
end
|
@@ -1,15 +1,15 @@
|
|
1
|
-
require 'forwardable'
|
2
|
-
|
3
1
|
module StepRewrite
|
4
|
-
include Forwardable
|
5
|
-
|
6
2
|
def step(*args, &block)
|
7
3
|
StepRewrite.step(*args, &block)
|
8
4
|
end
|
9
5
|
|
6
|
+
def self.get_sexp(&block)
|
7
|
+
Sexp.from_array(block.to_sexp)
|
8
|
+
end
|
9
|
+
|
10
10
|
def self.rewrite(callback_symbol = :_, &block)
|
11
|
-
|
12
|
-
new_sexp =
|
11
|
+
rewriter = StepRewrite::Rewriter.new(callback_symbol)
|
12
|
+
new_sexp = rewriter.process(get_sexp(&block))
|
13
13
|
Ruby2Ruby.new.process(new_sexp)
|
14
14
|
end
|
15
15
|
|
data/lib/step_rewrite/version.rb
CHANGED
data/spec/lib/rewriter_spec.rb
CHANGED
@@ -199,6 +199,29 @@ describe StepRewrite::Rewriter do
|
|
199
199
|
end
|
200
200
|
}
|
201
201
|
end
|
202
|
+
|
203
|
+
it do
|
204
|
+
should convert {
|
205
|
+
foo(&_)
|
206
|
+
begin
|
207
|
+
a = bar(&_)
|
208
|
+
baz do
|
209
|
+
b = qux(&_)
|
210
|
+
quux(a, b)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
}.to {
|
214
|
+
foo do
|
215
|
+
begin
|
216
|
+
bar do |a|
|
217
|
+
baz do
|
218
|
+
qux { |b| quux(a, b) }
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
}
|
224
|
+
end
|
202
225
|
end
|
203
226
|
end
|
204
227
|
end
|
data/step_rewrite.gemspec
CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.authors = ["Vishnu S Iyengar"]
|
9
9
|
s.email = %q{pathsny@gmail.com}
|
10
10
|
s.homepage = "http://rubygems.org/gems/step_rewrite"
|
11
|
-
s.summary = %q{
|
12
|
-
s.description = %q{A Gem to Rewrite Ruby code from a special syntax into an evented IO form}
|
11
|
+
s.summary = %q{code rewriter for evented I/O}
|
12
|
+
s.description = %q{A Gem to Rewrite Ruby code from a special syntax into an evented IO form.}
|
13
13
|
|
14
14
|
s.required_rubygems_version = ">= 1.3.6"
|
15
15
|
s.rubyforge_project = "step_rewrite"
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: step_rewrite
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 2
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.2.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Vishnu S Iyengar
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-10-
|
18
|
+
date: 2010-10-19 00:00:00 +05:30
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -102,7 +102,7 @@ dependencies:
|
|
102
102
|
version: 3.0.6
|
103
103
|
type: :runtime
|
104
104
|
version_requirements: *id005
|
105
|
-
description: A Gem to Rewrite Ruby code from a special syntax into an evented IO form
|
105
|
+
description: A Gem to Rewrite Ruby code from a special syntax into an evented IO form.
|
106
106
|
email: pathsny@gmail.com
|
107
107
|
executables: []
|
108
108
|
|
@@ -112,19 +112,15 @@ extra_rdoc_files: []
|
|
112
112
|
|
113
113
|
files:
|
114
114
|
- .gitignore
|
115
|
-
- .idea/encodings.xml
|
116
|
-
- .idea/misc.xml
|
117
|
-
- .idea/modules.xml
|
118
|
-
- .idea/vcs.xml
|
119
115
|
- Gemfile
|
120
116
|
- Gemfile.lock
|
121
|
-
-
|
117
|
+
- LICENSE
|
118
|
+
- README.rdoc
|
122
119
|
- Rakefile
|
123
120
|
- console
|
124
121
|
- lib/step_rewrite.rb
|
125
122
|
- lib/step_rewrite/module.rb
|
126
123
|
- lib/step_rewrite/rewriter.rb
|
127
|
-
- lib/step_rewrite/sexp_utilities.rb
|
128
124
|
- lib/step_rewrite/step_rewrite.rb
|
129
125
|
- lib/step_rewrite/version.rb
|
130
126
|
- spec/lib/module_spec.rb
|
@@ -168,6 +164,6 @@ rubyforge_project: step_rewrite
|
|
168
164
|
rubygems_version: 1.3.7
|
169
165
|
signing_key:
|
170
166
|
specification_version: 3
|
171
|
-
summary:
|
167
|
+
summary: code rewriter for evented I/O
|
172
168
|
test_files: []
|
173
169
|
|
@@ -1,20 +0,0 @@
|
|
1
|
-
$:.unshift File.dirname(__FILE__)
|
2
|
-
|
3
|
-
module SexpUtilities
|
4
|
-
|
5
|
-
def truthy?(sexp)
|
6
|
-
sexp.respond_to?(:[]) && (sexp[0] == :true || sexp[0] == :lit || sexp[0] == :str || sexp[0] == :array)
|
7
|
-
end
|
8
|
-
|
9
|
-
def falsy?(sexp)
|
10
|
-
sexp.respond_to?(:[]) && (sexp[0] == :nil || sexp[0] == :false)
|
11
|
-
end
|
12
|
-
|
13
|
-
def list?(sexp)
|
14
|
-
sexp.respond_to?(:[]) && sexp.respond_to?(:empty?) && sexp.respond_to?(:first)
|
15
|
-
end
|
16
|
-
|
17
|
-
def process_inner_expr(inner)
|
18
|
-
inner.kind_of?(Array) ? process(inner) : inner
|
19
|
-
end
|
20
|
-
end
|