enumerable-extra 0.1.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/CHANGES +2 -0
- data/MANIFEST +7 -0
- data/README +54 -0
- data/lib/enumerable/extra.rb +149 -0
- data/test/tc_enumerable_extra.rb +77 -0
- metadata +61 -0
data/CHANGES
ADDED
data/MANIFEST
ADDED
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
|