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 CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- step_rewrite (0.0.1)
4
+ step_rewrite (0.1.0)
5
5
  ParseTree (~> 3.0.6)
6
6
  ruby2ruby (~> 1.2.5)
7
7
  sexp_processor (~> 3.0.5)
@@ -1,12 +1,8 @@
1
- h2. LICENSE:
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
- 'Software'), to deal in the Software without restriction, including
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 'AS IS', WITHOUT WARRANTY OF ANY KIND,
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 NONINFRINGEMENT.
21
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
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([], &method(:accumulate))
12
+ result = exp.reverse.inject([]) {|acc, cur| accumulate(acc, process(cur))}
15
13
  exp.clear
16
- result.size > 1 ? s(:block, *result) : result.first
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 accumulate(acc_exp, cur_exp)
20
- case identify(cur_exp)
21
- when :special_call then
22
- cur_exp[3].pop
23
- inner_exp = acc_exp.size > 1 ? s(:block, *acc_exp) : acc_exp.first
24
- [s(*[:iter, cur_exp, nil] + [inner_exp].compact)]
25
- when :special_asgn then
26
- param = cur_exp[1]
27
- cur_exp[2][3].pop
28
- inner_exp = acc_exp.size > 1 ? s(:block, *acc_exp) : acc_exp.first
29
- [s(*[:iter, cur_exp[2], s(:lasgn, param)] + [inner_exp].compact)]
30
- when :masgn then
31
- param = cur_exp[1][1..-1].to_a
32
- cur_exp[2][1][3].pop
33
- inner_exp = acc_exp.size > 1 ? s(:block, *acc_exp) : acc_exp.first
34
- [s(*[:iter, cur_exp[2][1], s(:masgn, s(:array, *param))] + [inner_exp].compact)]
35
- when :attrasgn then
36
- next_exp = cur_exp.last.pop.tap{|x| x.last.pop}
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
- old_sexp = Sexp.from_array(block.to_sexp)
12
- new_sexp = StepRewrite::Rewriter.new(callback_symbol).process(old_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
 
@@ -1,3 +1,3 @@
1
1
  module StepRewrite
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -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{A Gem to Rewrite Ruby code from a special syntax into an evented IO form}
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: 27
4
+ hash: 23
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 1
8
+ - 2
9
9
  - 0
10
- version: 0.1.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 00:00:00 +05:30
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
- - README.textile
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: A Gem to Rewrite Ruby code from a special syntax into an evented IO form
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