enumerable-extra 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES ADDED
@@ -0,0 +1,2 @@
1
+ = 0.1.0 - 14-May-2009
2
+ * Initial release
data/MANIFEST ADDED
@@ -0,0 +1,7 @@
1
+ * CHANGES
2
+ * README
3
+ * MANIFEST
4
+ * Rakefile
5
+ * enumerable-extra.gemspec
6
+ * lib/enumerable/extra
7
+ * test/tc_enumerable_extra.rb
data/README ADDED
@@ -0,0 +1,54 @@
1
+ = Description
2
+ This library includes modified versions of the Enumerable methods, designed
3
+ to make list comprehensions a little bit easier and prettier in Ruby.
4
+
5
+ = Installation
6
+ rake test (optional)
7
+ rake install (non-gem) OR rake install_gem (gem)
8
+
9
+ = Synopsis
10
+ require 'enumerable/extra'
11
+
12
+ array = %w/foo bar baz/
13
+
14
+ array.map(:upcase) => ['FOO', 'BAR', 'BAZ']
15
+ array.map(:+, 'A') => ['fooA', 'barA', 'bazA']
16
+
17
+ numbers = [1,2,3]
18
+ numbers.sum => 6
19
+
20
+ = Motivation
21
+ This library was created in reaction to the ugly "&" (or worse, "&its")
22
+ notation started by Ruby on Rails and perpetuated by the Symbol#to_proc
23
+ adherents.
24
+
25
+ The theory behind Symbol#to_proc is that it's a generic metaprogramming
26
+ solution that will solve a certain range of programming problems. The
27
+ reality is that 99% of people use it for list comprehensions*. So, instead
28
+ of introducing crappy notation, I decided that it made better sense to
29
+ modify Enumerable methods to accept arguments.
30
+
31
+ There are two advantages to this. First, superior notation, i.e. no need
32
+ for the ampersand. One of the reasons I chose Ruby as my primary programming
33
+ language in the first place was the beauty of its notation. I don't want
34
+ to see that ruined by Symbol#to_proc. Also, coming from a C background, I
35
+ find the ampersand too reminiscent of C address notation.
36
+
37
+ Second, Symbol#to_proc is very slow.
38
+
39
+ * Based on the questions and solutions that I see on the ruby-talk and rails
40
+ mailing lists. I've monitored the former for almost seven years and the
41
+ latter for close to two now. This is in addition to many blogs I read that
42
+ occasionally touch on the subject.
43
+
44
+ = Future Plans
45
+ Modify several more Enumerable methods.
46
+
47
+ = License
48
+ Ruby's
49
+
50
+ = Warranty
51
+
52
+ = Author
53
+ Daniel J. Berger
54
+ djberg96 at nospam at gmail dot com
@@ -0,0 +1,149 @@
1
+ module Enumerable
2
+ EXTRA_VERSION = '0.1.0'
3
+
4
+ alias old_map map
5
+ alias old_collect collect
6
+
7
+ # Returns the numeric total of the elements of +enum+, using +total+ as
8
+ # an accumulator (0 by default). Raises an error if any of the elements
9
+ # are non-numeric.
10
+ #
11
+ def sum(total = 0)
12
+ each{ |val| total += val }
13
+ total
14
+ end
15
+
16
+ # Returns a new array containing the results of running +method+ once for
17
+ # every element in the enumerable object. If both arguments and a block
18
+ # are provided the arguments are processed first, then passed to
19
+ # the block.
20
+ #
21
+ # If no method is provided, then it behaves as the standard MRI method.
22
+ #
23
+ # Examples:
24
+ #
25
+ # array = ['foo', 'bar']
26
+ #
27
+ # # No arguments
28
+ # array.map(:capitalize) => ['Foo', 'Bar']
29
+ #
30
+ # # With arguments
31
+ # array.map(:+, 'x') => ['foox', 'barx']
32
+ #
33
+ # # With arguments and a block
34
+ # array.map(:capitalize){ |e| e + 'x' } => ['Foox', 'Barx']
35
+ #
36
+ def map(method=nil, *args, &block)
37
+ if method
38
+ array = []
39
+ method = method.to_sym unless method.is_a?(Symbol)
40
+
41
+ each{ |obj|
42
+ temp = obj.send(method, *args)
43
+ if block
44
+ array << block.call(temp)
45
+ else
46
+ array << temp
47
+ end
48
+ }
49
+
50
+ array
51
+ else
52
+ old_map(&block)
53
+ end
54
+ end
55
+
56
+ # Reset the aliases
57
+ alias collect map
58
+ end
59
+
60
+ class Array
61
+ alias old_map map
62
+ alias old_map! map!
63
+ alias old_collect collect
64
+ alias old_collect! collect!
65
+ #alias old_select select
66
+
67
+ # Returns a new array containing the results of running +block+ once for
68
+ # every element in the +array+.
69
+ #
70
+ # Examples:
71
+ #
72
+ # array = ['foo', 'bar']
73
+ #
74
+ # # No arguments
75
+ # array.map(:capitalize) => ['Foo', 'Bar']
76
+ #
77
+ # # With arguments
78
+ # array.map(:+, 'x') => ['foox', 'barx']
79
+ #
80
+ # # With arguments and a block
81
+ # array.map(:capitalize){ |e| e + 'x' } => ['Foox', 'Barx']
82
+ #--
83
+ # The Array class actually has its own implementation of the +map+ method,
84
+ # hence the duplication.
85
+ #
86
+ def map(method=nil, *args, &block)
87
+ if method
88
+ array = []
89
+ method = method.to_sym unless method.is_a?(Symbol)
90
+
91
+ each{ |obj|
92
+ temp = obj.send(method, *args)
93
+ if block
94
+ array << block.call(temp)
95
+ else
96
+ array << temp
97
+ end
98
+ }
99
+ array
100
+ else
101
+ old_map(&block)
102
+ end
103
+ end
104
+
105
+ # Same as Array#map, but modifies the receiver in place. Also note that
106
+ # a block is _not_ required. If no block is given, an array of values
107
+ # is returned instead
108
+ #
109
+ def map!(method=nil, *args, &block)
110
+ self.replace(map(method, *args, &block))
111
+ end
112
+
113
+ =begin
114
+ def select(method=nil, condition = nil, *args, &block)
115
+ array = [] unless block
116
+ if method
117
+ if block
118
+ warn 'block ignored when arguments provided'
119
+ end
120
+
121
+ if condition.nil?
122
+ raise 'condition must be provided if method is provided'
123
+ end
124
+
125
+ method = method.to_sym unless method.is_a?(Symbol)
126
+
127
+ each{ |obj|
128
+ if args.length > 0
129
+ if obj.send(method, condition, *args)
130
+ array << obj
131
+ end
132
+ else
133
+ if obj.send(method, condition)
134
+ array << obj
135
+ end
136
+ end
137
+ }
138
+
139
+ return array
140
+ else
141
+ old_select(&block)
142
+ end
143
+ end
144
+ =end
145
+
146
+ # Reset the aliases
147
+ alias collect map
148
+ alias collect! map!
149
+ end
@@ -0,0 +1,77 @@
1
+ ########################################################################
2
+ # tc_enumerable_extra.rb
3
+ #
4
+ # Test case for the enumerable-extra library. You should run this
5
+ # test via the 'rake test' task.
6
+ ########################################################################
7
+ require 'test/unit'
8
+ require 'enumerable/extra'
9
+
10
+ class TC_Enumerable_Extra < Test::Unit::TestCase
11
+ def setup
12
+ @words = %w/foo bar baz/
13
+ @numbers = [1,2,3]
14
+ @hash = {'foo', 1, 'bar', 2}
15
+ @array = []
16
+ end
17
+
18
+ def test_version
19
+ assert_equal('0.1.0', Enumerable::EXTRA_VERSION)
20
+ end
21
+
22
+ def test_sum
23
+ assert_respond_to(@numbers, :sum)
24
+ assert_equal(6, @numbers.sum)
25
+ assert_equal(20, @numbers.sum(14))
26
+ end
27
+
28
+ def test_sum_expected_errors
29
+ assert_raises(TypeError){ @words.sum }
30
+ end
31
+
32
+ def test_map_array_no_block
33
+ assert_nothing_raised{ @words.map }
34
+ assert_equal(%w/foo bar baz/, @words.map)
35
+ assert_equal(%w/FOO BAR BAZ/, @words.map(:upcase))
36
+ assert_equal(%w/fooA barA bazA/, @words.map(:+, 'A'))
37
+ assert_equal(%w/foo bar baz/, @words) # Verify receiver unmodified
38
+ end
39
+
40
+ # Test the alias explicitly
41
+ def test_collect_array_no_block
42
+ assert_nothing_raised{ @words.collect }
43
+ assert_equal(%w/foo bar baz/, @words.collect)
44
+ assert_equal(%w/FOO BAR BAZ/, @words.collect(:upcase))
45
+ assert_equal(%w/fooA barA bazA/, @words.collect(:+, 'A'))
46
+ assert_equal(%w/foo bar baz/, @words) # Verify receiver unmodified
47
+ end
48
+
49
+ def test_map_bang_array_no_block
50
+ assert_nothing_raised{ @words.map! }
51
+ assert_equal(%w/foo bar baz/, @words.map!)
52
+ assert_equal(%w/FOO BAR BAZ/, @words.map!(:upcase))
53
+ assert_equal(%w/FOO BAR BAZ/, @words) # Verify receiver modified
54
+ end
55
+
56
+ def test_map_with_block
57
+ assert_nothing_raised{ @words.map{} }
58
+ assert_nothing_raised{ @words.map{ |e| @array << e } }
59
+ assert_equal(%w/foo bar baz/, @array)
60
+
61
+ @array = []
62
+ assert_nothing_raised{ @words.map(:upcase){ |e| @array << e } }
63
+ assert_equal(%w/FOO BAR BAZ/, @array)
64
+
65
+ @array = []
66
+ assert_nothing_raised{ @words.map(:+, 'A'){ |e| @array << e } }
67
+ assert_equal(%w/fooA barA bazA/, @array)
68
+ assert_equal(%w/foo bar baz/, @words) # Verify receiver unmodified
69
+ end
70
+
71
+ def teardown
72
+ @words = nil
73
+ @numbers = nil
74
+ @hash = nil
75
+ @array = nil
76
+ end
77
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: enumerable-extra
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Daniel Berger
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-05-14 00:00:00 -06:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: " The enumerable-extra library provides overridden Enumerable methods\n that make it easier to handle common operations that apply to each\n element of a list without resorting to Symbol#to_proc. It also adds\n an Enumerable#sum method.\n"
17
+ email: djberg96@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README
24
+ - CHANGES
25
+ - MANIFEST
26
+ files:
27
+ - lib/enumerable/extra.rb
28
+ - test/tc_enumerable_extra.rb
29
+ - README
30
+ - CHANGES
31
+ - MANIFEST
32
+ has_rdoc: true
33
+ homepage: http://www.rubyforge.org/projects/shards
34
+ licenses: []
35
+
36
+ post_install_message:
37
+ rdoc_options: []
38
+
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - <
44
+ - !ruby/object:Gem::Version
45
+ version: 1.9.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: shards
56
+ rubygems_version: 1.3.3
57
+ signing_key:
58
+ specification_version: 3
59
+ summary: Enhanced methods for Enumerable objects
60
+ test_files:
61
+ - test/tc_enumerable_extra.rb