ick 0.2.4 → 0.3.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.
@@ -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