ick 0.2.4 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -15,4 +15,6 @@
15
15
  * #fork
16
16
  * 6 tiny enhancement
17
17
  * work in progress on Advisor
18
+ * 7 minor enhancement
19
+ * letn added experimentally
18
20
 
@@ -10,7 +10,9 @@ lib/ick/advisor.rb
10
10
  lib/ick/base.rb
11
11
  lib/ick/bizarro.rb
12
12
  lib/ick/guard.rb
13
+ lib/ick/letn.rb
13
14
  lib/ick/sugar.rb
15
+ lib/ick/syntax.rb
14
16
  lib/ick/tee.rb
15
17
  lib/ick/version.rb
16
18
  lib/ick/wrap.rb
@@ -26,7 +28,7 @@ test/test_180_seconds.rb
26
28
  test/test_advisor.rb
27
29
  test/test_helper.rb
28
30
  test/test_ick.rb
29
- test/test_not.rb
31
+ test/test_letn.rb
30
32
  website/180seconds.html
31
33
  website/180seconds.txt
32
34
  website/index.html
@@ -58,7 +58,9 @@ hoe = Hoe.new(GEM_NAME, VERS) do |p|
58
58
 
59
59
  # == Optional
60
60
  p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
61
- #p.extra_deps = [] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
61
+ p.extra_deps = [
62
+ ['ruby2ruby', '>= 1.1.8']
63
+ ] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
62
64
 
63
65
  #p.spec_extras = {} # A hash of extra values to set in the gemspec.
64
66
 
data/lib/ick.rb CHANGED
@@ -6,4 +6,6 @@ require 'ick/advisor'
6
6
  require 'ick/guard'
7
7
  require 'ick/tee'
8
8
  require 'ick/bizarro'
9
- require 'ick/sugar'
9
+ require 'ick/sugar'
10
+ require 'ick/syntax'
11
+ require 'ick/letn'
@@ -0,0 +1,52 @@
1
+ require 'rubygems'
2
+ require 'ruby2ruby'
3
+
4
+ module Ick
5
+
6
+ module LetnLambda
7
+
8
+ def letn_lambda(names_to_values, proc)
9
+ sorted_names = (names_to_values || {}).keys.map { |name| name.to_s }.sort
10
+ letn_body = <<LETN_BODY
11
+ lambda { |#{sorted_names.join(', ')}|
12
+ #{proc.to_ruby[/^proc \{(.*)\}$/m, 1]}
13
+ }
14
+ LETN_BODY
15
+ Kernel.eval(letn_body, proc.binding)
16
+ end
17
+
18
+ def rewritten(names_to_values, proc)
19
+ sorted_symbols = (names_to_values || {}).keys.map { |name| name.to_s }.sort.map { |name| name.to_sym }
20
+ lambda { |names_to_values|
21
+ letn_lambda(names_to_values, proc).call(*sorted_symbols.map { |sym| names_to_values[sym] })
22
+ }
23
+ end
24
+
25
+ end
26
+
27
+ # naïve implementation
28
+ class Letn < Syntax
29
+
30
+ include LetnLambda
31
+
32
+ def rewrite(names_to_values, proc)
33
+ rewritten(names_to_values, proc)
34
+ end
35
+
36
+ evaluates_in_calling_environment and returns_result
37
+
38
+ end
39
+
40
+ class Cletn < Letn
41
+
42
+ include LetnLambda
43
+
44
+ def rewrite(names_to_values, proc)
45
+ @lambda ||= rewritten(names_to_values, proc)
46
+ end
47
+
48
+ evaluates_in_calling_environment and returns_result
49
+
50
+ end
51
+
52
+ end
@@ -1,7 +1,7 @@
1
1
  module Ick
2
2
  def self.sugarize
3
- [Let, Returning, My, Inside, Maybe, Try, Please, Tee, Fork].each do |clazz|
4
- clazz.belongs_to Object
3
+ [Let, Returning, My, Inside, Maybe, Try, Please, Tee, Fork, Letn].each do |clazz|
4
+ clazz.belongs_to Kernel
5
5
  end
6
6
  end
7
7
  end
@@ -0,0 +1,16 @@
1
+ module Ick
2
+
3
+ class Syntax < Base
4
+
5
+ def rewrite(value, proc)
6
+ raise 'implemented by subclass or by calling meta-method!'
7
+ end
8
+
9
+ def invoke(value = nil, &proc)
10
+ rewritten_proc = rewrite(value, proc)
11
+ super(value, &rewritten_proc)
12
+ end
13
+
14
+ end
15
+
16
+ end
@@ -1,8 +1,8 @@
1
1
  module Ick #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
- MINOR = 2
5
- TINY = 4
4
+ MINOR = 3
5
+ TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -0,0 +1,17 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestLetn < Test::Unit::TestCase
4
+
5
+ def test_empty_body
6
+ assert_nil letn(:foo => 'bar') { }
7
+ end
8
+
9
+ def test_one_parameter
10
+ assert_equal('expected', letn(:foo => 'expected') { foo })
11
+ end
12
+
13
+ def test_two_parameters
14
+ assert_equal(3, letn(:one => 1, :two => 2) { one + two })
15
+ end
16
+
17
+ end
@@ -33,7 +33,7 @@
33
33
  <h1>Ick in 180 seconds or less</h1>
34
34
  <div id="version" class="clickable" onclick='document.location = "http://rubyforge.org/projects/ick"; return false'>
35
35
  <p>Get Version</p>
36
- <a href="http://rubyforge.org/projects/ick" class="numbers">0.2.4</a>
36
+ <a href="http://rubyforge.org/projects/ick" class="numbers">0.3.0</a>
37
37
  </div>
38
38
  <h2>Transforming your code</h2>
39
39
 
@@ -33,7 +33,7 @@
33
33
  <h1>Invocation Construction Kit</h1>
34
34
  <div id="version" class="clickable" onclick='document.location = "http://rubyforge.org/projects/ick"; return false'>
35
35
  <p>Get Version</p>
36
- <a href="http://rubyforge.org/projects/ick" class="numbers">0.2.4</a>
36
+ <a href="http://rubyforge.org/projects/ick" class="numbers">0.3.0</a>
37
37
  </div>
38
38
  <h1>&#x2192; &#8216;ick&#8217;</h1>
39
39
 
@@ -60,9 +60,6 @@
60
60
 
61
61
  <pre>sudo gem install ick</pre>
62
62
 
63
- <p>You can also see <a href="180seconds.html">Ick in 180 seconds or less</a></p>
64
-
65
-
66
63
  <h2>Block Structured Ruby</h2>
67
64
 
68
65
 
@@ -146,6 +143,22 @@
146
143
  </pre></p>
147
144
 
148
145
 
146
+ <h2>New in Version 0.3!</h2>
147
+
148
+
149
+ <p>Ick version 0.3 includes an experiemental form of let, <code>letn</code>, that allows you to bind multiple variables:</p>
150
+
151
+
152
+ <p><pre class='syntax'>
153
+ <span class="ident">letn</span><span class="punct">(</span>
154
+ <span class="symbol">:person</span> <span class="punct">=&gt;</span> <span class="constant">Person</span><span class="punct">.</span><span class="ident">find</span><span class="punct">(</span><span class="symbol">:first</span><span class="punct">,</span> <span class="punct">...),</span>
155
+ <span class="symbol">:place</span> <span class="punct">=&gt;</span> <span class="constant">City</span><span class="punct">.</span><span class="ident">select</span> <span class="punct">{</span> <span class="punct">...</span> <span class="punct">},</span>
156
+ <span class="symbol">:thing</span> <span class="punct">=&gt;</span> <span class="punct">%w(</span><span class="string">ever loving blue eyed</span><span class="punct">))</span> <span class="punct">{</span>
157
+ <span class="punct">&quot;</span><span class="string"><span class="expr">#{person.name}</span> lives in <span class="expr">#{place}</span> where he is known as the '<span class="expr">#{thing}</span> thing.'</span><span class="punct">&quot;</span>
158
+ <span class="punct">}</span>
159
+ </pre></p>
160
+
161
+
149
162
  <p>The Object#andand-style syntax is most useful when you&#8217;re just using it for a single method invocation, such as:</p>
150
163
 
151
164
 
@@ -246,7 +259,7 @@
246
259
 
247
260
  <p>Comments are welcome. Send an email to <a href="mailto:raganwald+rubyforge@gmail.com">Reginald Braithwaite</a>. And you can always visit <a href="http://weblog.raganwald.com/">weblog.raganwald.com</a> to see what&#8217;s cooking.</p>
248
261
  <p class="coda">
249
- <a href="http://weblog.raganwald.com/">Reginald Braithwaite</a>, 26th March 2008<br>
262
+ <a href="http://weblog.raganwald.com/">Reginald Braithwaite</a>, 9th May 2008<br>
250
263
  Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
251
264
  </p>
252
265
  </div>
@@ -18,8 +18,6 @@ h2. Getting Started
18
18
 
19
19
  <pre>sudo gem install ick</pre>
20
20
 
21
- You can also see "Ick in 180 seconds or less":180seconds.html
22
-
23
21
  h2. Block Structured Ruby
24
22
 
25
23
  Although Ruby borrows many of its features from Lisp and its syntax from Algol, it does not have block-local variables. In other words, if you declare a variable anywhere inside of a method, that variable is visible everywhere in that method. This is a problem, because it encourages writing methods where the instance variables create lot of dependencies between different expressions. Those methods can be hard to understand and refactor.
@@ -83,6 +81,19 @@ maybe(Person.find(:first, ...)) { |p|
83
81
  }
84
82
  </pre>
85
83
 
84
+ h2. New in Version 0.3!
85
+
86
+ Ick version 0.3 includes an experiemental form of let, @letn@, that allows you to bind multiple variables:
87
+
88
+ <pre syntax="ruby">
89
+ letn(
90
+ :person => Person.find(:first, ...),
91
+ :place => City.select { ... },
92
+ :thing => %w(ever loving blue eyed)) {
93
+ "#{person.name} lives in #{place} where he is known as the '#{thing} thing.'"
94
+ }
95
+ </pre>
96
+
86
97
  The Object#andand-style syntax is most useful when you're just using it for a single method invocation, such as:
87
98
 
88
99
  <pre syntax="ruby">
@@ -33,7 +33,7 @@
33
33
  <h1>Inside the Invocation Construction Kit</h1>
34
34
  <div id="version" class="clickable" onclick='document.location = "http://rubyforge.org/projects/ick"; return false'>
35
35
  <p>Get Version</p>
36
- <a href="http://rubyforge.org/projects/ick" class="numbers">0.2.4</a>
36
+ <a href="http://rubyforge.org/projects/ick" class="numbers">0.3.0</a>
37
37
  </div>
38
38
  <h2>More about the four block structures</h2>
39
39
 
@@ -98,6 +98,51 @@
98
98
  <p>(The four methods were inspired by <a href="http://blog.rubyenrails.nl/articles/2008/02/18/our-daily-method-10-object-r-rs-ds-s">Michiel de Mare&#8217;s</a> post on the same subject, although Ick’s nomenclature is not compatible with Michiel’s. Michiel’s #rsss, #rrss, #rsds, and #rrds are called #returning, #let, #inside, and #my in Ick.)</p>
99
99
 
100
100
 
101
+ <h3>letn</h3>
102
+
103
+
104
+ <p>Ick version 0.3 includes an experiemental form of #let, #letn, that allows you to bind multiple variables:</p>
105
+
106
+
107
+ <p><pre class='syntax'>
108
+ <span class="ident">letn</span><span class="punct">(</span>
109
+ <span class="symbol">:person</span> <span class="punct">=&gt;</span> <span class="constant">Person</span><span class="punct">.</span><span class="ident">find</span><span class="punct">(</span><span class="symbol">:first</span><span class="punct">,</span> <span class="punct">...),</span>
110
+ <span class="symbol">:place</span> <span class="punct">=&gt;</span> <span class="constant">City</span><span class="punct">.</span><span class="ident">select</span> <span class="punct">{</span> <span class="punct">...</span> <span class="punct">},</span>
111
+ <span class="symbol">:thing</span> <span class="punct">=&gt;</span> <span class="punct">%w(</span><span class="string">ever loving blue eyed</span><span class="punct">))</span> <span class="punct">{</span>
112
+ <span class="punct">&quot;</span><span class="string"><span class="expr">#{person.name}</span> lives in <span class="expr">#{place}</span> where he is known as the '<span class="expr">#{thing}</span> thing.'</span><span class="punct">&quot;</span>
113
+ <span class="punct">}</span>
114
+ </pre></p>
115
+
116
+
117
+ <p>You must have the <a href="http://seattlerb.rubyforge.org/ruby2ruby/">ruby2ruby gem</a> installed to use #letn. You know the drill:</p>
118
+
119
+
120
+ <pre>sudo gem install ruby2ruby</pre>
121
+
122
+ <p>Like #let, #letn <em>evaluates_in_value_environment</em> and <em>returns_result</em>. You can roll your own variations if you want something else. If you&#8217;re familiar with Lisp, #letn is a lot like Lisp&#8217;s simplest let macro. But not like letrec or let*. If you don&#8217;t know the difference, then #letn will not suprise you. Basically, the binding of values to names works a lot like you would expect a hash to behave.</p>
123
+
124
+
125
+ <p>For example, if I wrote:</p>
126
+
127
+
128
+ <p><pre class='syntax'>
129
+ <span class="ident">a</span> <span class="punct">=</span> <span class="constant">nil</span>
130
+ <span class="ident">a</span> <span class="punct">=</span> <span class="punct">{</span> <span class="symbol">:foo</span> <span class="punct">=&gt;</span> <span class="ident">call_something_else</span><span class="punct">(),</span> <span class="symbol">:bash</span> <span class="punct">=&gt;</span> <span class="ident">a</span><span class="punct">[</span><span class="symbol">:foo</span><span class="punct">]</span> <span class="punct">}</span>
131
+ </pre></p>
132
+
133
+
134
+ <p>You would consider this bad code, wouldn&#8217;t you? There&#8217;s no expectation that the espressions are evaluated in any particular order. It&#8217;s the same with #letn. This is probably a bad idea:</p>
135
+
136
+
137
+ <p><pre class='syntax'>
138
+ <span class="ident">foo</span> <span class="punct">=</span> <span class="constant">nil</span>
139
+ <span class="ident">letn</span><span class="punct">(</span><span class="symbol">:foo</span> <span class="punct">=&gt;</span> <span class="ident">call_something_else</span><span class="punct">(),</span> <span class="symbol">:bash</span> <span class="punct">=&gt;</span> <span class="ident">foo</span><span class="punct">)</span> <span class="punct">{</span> <span class="punct">...</span> <span class="punct">}</span>
140
+ </pre></p>
141
+
142
+
143
+ <p><code>bash</code> is not going to be bound to the return value of <code>call_something_else</code>, it&#8217;s going to be bound to nil. The variables you bind are only visible inside the block.</p>
144
+
145
+
101
146
  <h3>What about #try and #maybe?</h3>
102
147
 
103
148
 
@@ -312,7 +357,7 @@ Ick::Wrap.instance.invoke_wrapped(Person.find(:first, ...), MyWrapper, :foo, :ba
312
357
 
313
358
  <p>Comments are welcome. Send an email to <a href="mailto:raganwald+rubyforge@gmail.com">Reginald Braithwaite</a>. And you can always visit <a href="http://weblog.raganwald.com/">weblog.raganwald.com</a> to see what&#8217;s cooking.</p>
314
359
  <p class="coda">
315
- <a href="http://weblog.raganwald.com/">Reginald Braithwaite</a>, 9th March 2008<br>
360
+ <a href="http://weblog.raganwald.com/">Reginald Braithwaite</a>, 9th May 2008<br>
316
361
  Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
317
362
  </p>
318
363
  </div>
@@ -48,6 +48,41 @@ The method #inside returns the value and evaluates the block in the value's envi
48
48
 
49
49
  (The four methods were inspired by "Michiel de Mare's":http://blog.rubyenrails.nl/articles/2008/02/18/our-daily-method-10-object-r-rs-ds-s post on the same subject, although Ick’s nomenclature is not compatible with Michiel’s. Michiel’s #rsss, #rrss, #rsds, and #rrds are called #returning, #let, #inside, and #my in Ick.)
50
50
 
51
+ h3. letn
52
+
53
+ Ick version 0.3 includes an experiemental form of #let, #letn, that allows you to bind multiple variables:
54
+
55
+ <pre syntax="ruby">
56
+ letn(
57
+ :person => Person.find(:first, ...),
58
+ :place => City.select { ... },
59
+ :thing => %w(ever loving blue eyed)) {
60
+ "#{person.name} lives in #{place} where he is known as the '#{thing} thing.'"
61
+ }
62
+ </pre>
63
+
64
+ You must have the "ruby2ruby gem":http://seattlerb.rubyforge.org/ruby2ruby/ installed to use #letn. You know the drill:
65
+
66
+ <pre>sudo gem install ruby2ruby</pre>
67
+
68
+ Like #let, #letn _evaluates_in_value_environment_ and _returns_result_. You can roll your own variations if you want something else. If you're familiar with Lisp, #letn is a lot like Lisp's simplest let macro. But not like letrec or let*. If you don't know the difference, then #letn will not suprise you. Basically, the binding of values to names works a lot like you would expect a hash to behave.
69
+
70
+ For example, if I wrote:
71
+
72
+ <pre syntax="ruby">
73
+ a = nil
74
+ a = { :foo => call_something_else(), :bash => a[:foo] }
75
+ </pre>
76
+
77
+ You would consider this bad code, wouldn't you? There's no expectation that the espressions are evaluated in any particular order. It's the same with #letn. This is probably a bad idea:
78
+
79
+ <pre syntax="ruby">
80
+ foo = nil
81
+ letn(:foo => call_something_else(), :bash => foo) { ... }
82
+ </pre>
83
+
84
+ @bash@ is not going to be bound to the return value of @call_something_else@, it's going to be bound to nil. The variables you bind are only visible inside the block.
85
+
51
86
  h3. What about #try and #maybe?
52
87
 
53
88
  The methods #try and #maybe are both implemented as _evaluates_in_calling_environment_, because that is least surprising. But when you're rolling your own, you might want to change that to make things more sugary. For example, here is a different version of #try:
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: ick
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.2.4
7
- date: 2008-04-28 00:00:00 -04:00
6
+ version: 0.3.0
7
+ date: 2008-05-09 00:00:00 -04:00
8
8
  summary: Invocation Construction Kit
9
9
  require_paths:
10
10
  - lib
@@ -42,7 +42,9 @@ files:
42
42
  - lib/ick/base.rb
43
43
  - lib/ick/bizarro.rb
44
44
  - lib/ick/guard.rb
45
+ - lib/ick/letn.rb
45
46
  - lib/ick/sugar.rb
47
+ - lib/ick/syntax.rb
46
48
  - lib/ick/tee.rb
47
49
  - lib/ick/version.rb
48
50
  - lib/ick/wrap.rb
@@ -58,7 +60,7 @@ files:
58
60
  - test/test_advisor.rb
59
61
  - test/test_helper.rb
60
62
  - test/test_ick.rb
61
- - test/test_not.rb
63
+ - test/test_letn.rb
62
64
  - website/180seconds.html
63
65
  - website/180seconds.txt
64
66
  - website/index.html
@@ -73,7 +75,7 @@ test_files:
73
75
  - test/test_advisor.rb
74
76
  - test/test_helper.rb
75
77
  - test/test_ick.rb
76
- - test/test_not.rb
78
+ - test/test_letn.rb
77
79
  rdoc_options:
78
80
  - --main
79
81
  - README.txt
@@ -91,5 +93,13 @@ extensions: []
91
93
 
92
94
  requirements: []
93
95
 
94
- dependencies: []
95
-
96
+ dependencies:
97
+ - !ruby/object:Gem::Dependency
98
+ name: ruby2ruby
99
+ version_requirement:
100
+ version_requirements: !ruby/object:Gem::Version::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: 1.1.8
105
+ version:
@@ -1,5 +0,0 @@
1
- require File.dirname(__FILE__) + '/test_helper.rb'
2
-
3
- def test_not
4
-
5
- end