bkoski-each_with_context 0.5.1

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/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Ben Koski
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
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,50 @@
1
+ = each_with_context
2
+
3
+ Inspired by the Liquid templating language's nice {for loop goodies}[http://wiki.github.com/tobi/liquid/liquid-for-designers],
4
+ each_with_context provides some contextual information about an element in an each loop.
5
+
6
+ If you've ever found yourself writing an <tt>each_with_index</tt> and
7
+ checking <tt>i == 0</tt> to see if the element is the first, or wondering whether the
8
+ next element is differs from the current, this gem is for you.
9
+
10
+ == INSTALLATION
11
+
12
+ To use, just install the gem:
13
+
14
+ sudo gem install bkoski-each_with_context --source http://gems.github.com
15
+
16
+ and
17
+
18
+ require 'each_with_context'
19
+
20
+ Now you can call <tt>each_with_context</tt> on anything that's already Enumerable[http://www.ruby-doc.org/core/classes/Enumerable.html].
21
+
22
+
23
+ == USAGE
24
+
25
+ each_with_context accepts a block with two params: the element, and an EnumerableContext describing
26
+ the element. For example:
27
+
28
+ [1,2,3].each_with_context do |num, context|
29
+
30
+ # Here, you can call:
31
+ context.first? # true if num is first element
32
+ context.last? # true if num is last element
33
+
34
+ context.edge # returns :first if first?, :last if last?, nil otherwise
35
+ # useful when determining CSS selectors
36
+
37
+ context.next # next element; nil if that doesn't exist
38
+ context.previous # previous element; nil if that doesn't exist
39
+
40
+ context.next_differs_on?(:some-method) # These methods return true if element.some_method != next/previous.some_method
41
+ context.previous_differs_on?(:some-method) # If there is no next/previous, they return nil
42
+
43
+ context.previous_is? {|element, previous_element| previous_element > element} # These methods yield element and next/previous, then return the result of the block
44
+ context.next_is? {|element, next_element| next_element * 2 == element} # Useful for more advanced comparisons. Method returns nil if there is no next/previous.
45
+
46
+ end
47
+
48
+ == COPYRIGHT
49
+
50
+ Copyright (c) 2009 Ben Koski. See LICENSE for details.
@@ -0,0 +1,11 @@
1
+ module Enumerable
2
+
3
+ # Calls block with two arguments: the current <tt>element</tt> an EnumerableContext,
4
+ # which provides details about the element's context. See class docs for details.
5
+ def each_with_context &block
6
+ each_with_index do |element, i|
7
+ yield(element, EnumerableContext.new(self,i))
8
+ end
9
+ end
10
+
11
+ end
@@ -0,0 +1,75 @@
1
+ class EnumerableContext
2
+
3
+ # Current index into the collection
4
+ attr_accessor :index
5
+
6
+ # Create with a collection and the index into that collection
7
+ def initialize collection, index
8
+ @collection = collection
9
+ @index = index
10
+ end
11
+
12
+ # Is current index the first?
13
+ def first?
14
+ index == 0
15
+ end
16
+
17
+ # Is current index the last?
18
+ def last?
19
+ index == @collection.length - 1
20
+ end
21
+
22
+ # Returns :first if first?; last if last?; nil otherwise
23
+ def edge
24
+ :first if first?
25
+ :last if last?
26
+ nil
27
+ end
28
+
29
+ # Returns the next element in the collection; nil if it does not exist
30
+ def next
31
+ last? ? nil : @collection[index + 1]
32
+ end
33
+
34
+ # Returns the previous element in the collection; nil if it does not exist
35
+ def previous
36
+ first? ? nil : @collection[index - 1]
37
+ end
38
+
39
+ # Returns true if the next element does not have the same value for <tt>field</tt>
40
+ def next_differs_on? field
41
+ if last?
42
+ nil
43
+ else
44
+ element.send(field) != self.next.send(field) # need to self to differentiate from keyword
45
+ end
46
+ end
47
+
48
+ # Returns true if the previous element does not have the same value for <tt>field</tt>
49
+ def previous_differs_on? field
50
+ if first?
51
+ nil
52
+ else
53
+ element.send(field) != previous.send(field)
54
+ end
55
+ end
56
+
57
+ # Yields a block with element, next_element as params; returns value returned by block
58
+ # Returns nil if there is no next element.
59
+ def next_is? &block
60
+ last? ? nil : yield(element, self.next)
61
+ end
62
+
63
+ # Yields a block with element, previous_element as params; returns value returned by block
64
+ # Returns nil if there is no previous element.
65
+ def previous_is? &block
66
+ first? ? nil : yield(element, self.previous)
67
+ end
68
+
69
+ private
70
+ # Returns the element at the current index
71
+ def element
72
+ @collection[index]
73
+ end
74
+
75
+ end
@@ -0,0 +1,2 @@
1
+ require File.join(File.dirname(__FILE__), 'each_with_context/enumerable')
2
+ require File.join(File.dirname(__FILE__), 'each_with_context/enumerable_context')
@@ -0,0 +1,225 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class TestEachWithContext < Test::Unit::TestCase
4
+
5
+ context "first?" do
6
+ setup do
7
+ @collection = [1,2,3,4]
8
+ end
9
+
10
+ should "return true on last element" do
11
+ @collection.each_with_context do |num,c|
12
+ assert c.first? if num == 1
13
+ end
14
+ end
15
+
16
+ should "return false for all other elements" do
17
+ @collection.each_with_context do |num,c|
18
+ assert !c.first?, "first? should be false for #{num}" if num != 1
19
+ end
20
+ end
21
+ end
22
+
23
+ context "last?" do
24
+ setup do
25
+ @collection = [1,2,3,4]
26
+ end
27
+
28
+ should "return true on last element" do
29
+ @collection.each_with_context do |num,c|
30
+ assert c.last? if num == 4
31
+ end
32
+ end
33
+
34
+ should "return false for all other elements" do
35
+ @collection.each_with_context do |num,c|
36
+ assert !c.last?, "last? should be false for #{num}" if num != 4
37
+ end
38
+ end
39
+ end
40
+
41
+ context "edge" do
42
+ setup do
43
+ @collection = [1,2,3]
44
+ end
45
+
46
+ should "return :first for first element" do
47
+ @collection.each_with_context do |num,c|
48
+ assert_equal :first, c.edge if c == 1
49
+ end
50
+ end
51
+
52
+ should "return :last for last element" do
53
+ @collection.each_with_context do |num,c|
54
+ assert_equal :last, c.edge if c == 3
55
+ end
56
+ end
57
+
58
+ should "return nil for an element in the middle" do
59
+ @collection.each_with_context do |num,c|
60
+ assert_nil c.edge if c == 2
61
+ end
62
+ end
63
+ end
64
+
65
+ context "index" do
66
+ should "return the zero-based index as index" do
67
+ [0,1,2,3].each_with_context do |num,c|
68
+ assert_equal num, c.index
69
+ end
70
+ end
71
+ end
72
+
73
+ context "next" do
74
+ setup do
75
+ @collection = ['a','b','c','d']
76
+ end
77
+
78
+ should "return the next element" do
79
+ @collection.each_with_context do |element, c|
80
+ assert_equal(@collection[c.index + 1], c.next) unless c.last?
81
+ end
82
+ end
83
+
84
+ should "return nil if there is no next element" do
85
+ @collection.each_with_context do |element, c|
86
+ assert_nil c.next if c.last?
87
+ end
88
+ end
89
+ end
90
+
91
+ context "previous" do
92
+ setup do
93
+ @collection = ['a','b','c','d']
94
+ end
95
+
96
+ should "return the previous element" do
97
+ @collection.each_with_context do |element, c|
98
+ assert_equal(@collection[c.index - 1], c.previous) unless c.first?
99
+ end
100
+ end
101
+
102
+ should "return nil if there is no previous element" do
103
+ @collection.each_with_context do |element, c|
104
+ assert_nil c.previous if c.first?
105
+ end
106
+ end
107
+ end
108
+
109
+ context "next_differs_on?" do
110
+ setup do
111
+ @collection = [Date.today, Date.today + 1, Date.today + 2]
112
+ end
113
+
114
+ should "return true if next element doesn't have same value for specified method" do
115
+ [Date.today, Date.today + 1, Date.today + 2].each_with_context do |date,c|
116
+ assert c.next_differs_on?(:day) unless c.last?
117
+ end
118
+ end
119
+
120
+ should "return false if next element doesn't have same value for specified method" do
121
+ [Date.today, Date.today, Date.today].each_with_context do |date,c|
122
+ assert !c.next_differs_on?(:day) unless c.last?
123
+ end
124
+ end
125
+
126
+ should "return nil if there is no next element" do
127
+ [Date.today, Date.today, Date.today].each_with_context do |date,c|
128
+ assert_nil c.next_differs_on?(:day) if c.last?
129
+ end
130
+ end
131
+ end
132
+
133
+ context "previous_differs_on?" do
134
+ setup do
135
+ @collection = [Date.today, Date.today + 1, Date.today + 2]
136
+ end
137
+
138
+ should "return true if next element doesn't have same value for specified method" do
139
+ [Date.today, Date.today + 1, Date.today + 2].each_with_context do |date,c|
140
+ assert c.previous_differs_on?(:day) unless c.first?
141
+ end
142
+ end
143
+
144
+ should "return false if next element doesn't have same value for specified method" do
145
+ [Date.today, Date.today, Date.today].each_with_context do |date,c|
146
+ assert !c.previous_differs_on?(:day) unless c.first?
147
+ end
148
+ end
149
+
150
+ should "return nil if there is no next element" do
151
+ [Date.today, Date.today, Date.today].each_with_context do |date,c|
152
+ assert_nil c.previous_differs_on?(:day) if c.first?
153
+ end
154
+ end
155
+ end
156
+
157
+ context "next_is?" do
158
+ setup do
159
+ @collection = [1,2,3,4]
160
+ end
161
+
162
+ should "yield block with element as first parameter" do
163
+ @collection.each_with_context do |element, c|
164
+ unless c.last?
165
+ c.next_is? { |e,n| assert_equal(element, e) }
166
+ end
167
+ end
168
+ end
169
+
170
+ should "yield block with next element as second parameter" do
171
+ @collection.each_with_context do |element, c|
172
+ unless c.last?
173
+ c.next_is? { |e,n| assert_equal(c.next, n) }
174
+ end
175
+ end
176
+ end
177
+
178
+ should "return nil if there is no next element" do
179
+ @collection.each_with_context do |element, c|
180
+ assert_nil(c.next_is? { |e,n| 29 }) if c.last?
181
+ end
182
+ end
183
+
184
+ should "return value returned by block" do
185
+ @collection.each_with_context do |element, c|
186
+ assert_equal(49, c.next_is? { |e,n| 49 }) unless c.last?
187
+ end
188
+ end
189
+ end
190
+
191
+ context "previous_is?" do
192
+ setup do
193
+ @collection = [1,2,3,4]
194
+ end
195
+
196
+ should "yield block with element as first parameter" do
197
+ @collection.each_with_context do |element, c|
198
+ unless c.first?
199
+ c.previous_is? { |e,p| assert_equal(element, e) }
200
+ end
201
+ end
202
+ end
203
+
204
+ should "yield block with previous element as second parameter" do
205
+ @collection.each_with_context do |element, c|
206
+ unless c.first?
207
+ c.previous_is? { |e,p| assert_equal(c.previous, p) }
208
+ end
209
+ end
210
+ end
211
+
212
+ should "return nil if there is no previous element" do
213
+ @collection.each_with_context do |element, c|
214
+ assert_nil(c.previous_is? { |e,p| 'test-value' }) if c.first?
215
+ end
216
+ end
217
+
218
+ should "return value returned by block" do
219
+ @collection.each_with_context do |element, c|
220
+ assert_equal('test-value', c.previous_is? { |e,p| 'test-value' }) unless c.first?
221
+ end
222
+ end
223
+ end
224
+
225
+ end
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+ require 'mocha'
5
+
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'each_with_context'
8
+
9
+ class Test::Unit::TestCase
10
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bkoski-each_with_context
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.1
5
+ platform: ruby
6
+ authors:
7
+ - Ben Koski
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-07-15 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: TODO
17
+ email: gems@benkoski.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - lib/each_with_context
26
+ - lib/each_with_context.rb
27
+ - lib/each_with_context/enumerable.rb
28
+ - lib/each_with_context/enumerable_context.rb
29
+ - test/test_each_with_context.rb
30
+ - test/test_helper.rb
31
+ - README.rdoc
32
+ - LICENSE
33
+ has_rdoc: true
34
+ homepage: http://github.com/bkoski/each_with_context
35
+ post_install_message:
36
+ rdoc_options:
37
+ - --inline-source
38
+ - --charset=UTF-8
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ version:
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ version:
53
+ requirements: []
54
+
55
+ rubyforge_project:
56
+ rubygems_version: 1.2.0
57
+ signing_key:
58
+ specification_version: 2
59
+ summary: Get contextual information about an element in an each loop
60
+ test_files: []
61
+