step_rewrite 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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