ruby_peter_v 0.0.7 → 0.0.8
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.
- checksums.yaml +7 -0
- data/HISTORY.txt +8 -1
- data/README.md +14 -17
- data/lib/ruby_peter_v/each_recursively.rb +19 -0
- data/lib/ruby_peter_v/set_once.rb +2 -2
- data/lib/ruby_peter_v/single.rb +13 -3
- data/lib/ruby_peter_v/version.rb +1 -1
- data/lib/ruby_peter_v.rb +1 -1
- data/spec/lib/ruby_peter_v/{do_recursively_spec.rb → each_recursively_spec.rb} +8 -9
- data/spec/lib/ruby_peter_v/set_once_spec.rb +1 -1
- data/spec/lib/ruby_peter_v/single_spec.rb +99 -13
- metadata +15 -25
- data/lib/ruby_peter_v/do_recursively.rb +0 -17
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e366938bf072caf8371100290278e5a06f99afa4
|
4
|
+
data.tar.gz: 4b910a5a1190a1e7cd747036586a38d566c8952c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8f6ed3f6f642e20dbc4c1eb37f111c0773325151fcd5aa94c66166678c0d3a599a59a013e9fa07092d7e90a912c1a8ce8ed8bacf28f573fbc1ca259da0ac70aa
|
7
|
+
data.tar.gz: 71317efb8a6f7ac53145e75da57dc4a42bcb277b8efc32ae78e03ab7c4c0f9f7f416d4fdc64b93ee2da0b15e597d9e73b00ce3d3f0c0dd680758872880f7b108
|
data/HISTORY.txt
CHANGED
@@ -23,10 +23,17 @@
|
|
23
23
|
* module DefineEquality
|
24
24
|
* Module#DefineEquality
|
25
25
|
|
26
|
-
0.0.7 (2013-06-
|
26
|
+
0.0.7 (2013-06-02)
|
27
27
|
|
28
28
|
* remove Object#max_with_nil(a,b)
|
29
29
|
(use [a,b,c].compact.max)
|
30
30
|
|
31
|
+
0.0.8 (2013-06-02)
|
32
|
+
|
33
|
+
* fix some TODO's
|
34
|
+
* Enumerable#single takes a block
|
35
|
+
* Enumerable#single works properly on lazy Enumerables
|
36
|
+
* Object#each_recursively
|
37
|
+
|
31
38
|
TODO
|
32
39
|
* Object#assert_keys_in
|
data/README.md
CHANGED
@@ -17,13 +17,15 @@ Add this line to your application's Gemfile:
|
|
17
17
|
|
18
18
|
The background of this is that in many cases,
|
19
19
|
the developer knows there _should_ only be 1
|
20
|
-
element in
|
20
|
+
element in a collection. Using first is fine, but if
|
21
21
|
inadvertently more elements are present, `.first`
|
22
22
|
will happily choose a random entry (certainly with
|
23
23
|
ActiveRecord first) which is a silent bug.
|
24
24
|
|
25
|
-
|
26
|
-
|
25
|
+
single also works smartly on an Enumerable that
|
26
|
+
does not have a `single` method (a lazy collection).
|
27
|
+
It will only evaluate the first(2) elements of
|
28
|
+
the collection to determine that it is oversized.
|
27
29
|
|
28
30
|
```
|
29
31
|
$ irb
|
@@ -34,7 +36,7 @@ $ irb
|
|
34
36
|
2.0.0-p195 :003 > [1].single
|
35
37
|
=> 1
|
36
38
|
2.0.0-p195 :004 > [1,2].single
|
37
|
-
|
39
|
+
RubyPeterV::UniquenessError: size of collection was 2.
|
38
40
|
...
|
39
41
|
```
|
40
42
|
|
@@ -46,9 +48,6 @@ RuntimeError: INTERNAL ERROR: size of set was 2
|
|
46
48
|
can still be set once from nil to a specific value, but after
|
47
49
|
that, it can never be changed to a different value. Writing
|
48
50
|
it twice with the same value does not throw an exception.
|
49
|
-
|
50
|
-
TODO: refactor to a Module method that also defines the attr_accessor
|
51
|
-
|
52
51
|
```
|
53
52
|
2.0.0-p195 :009 > class A
|
54
53
|
2.0.0-p195 :010?> attr_reader :foo
|
@@ -71,20 +70,18 @@ RuntimeError: INTERNAL ERROR: size of set was 2
|
|
71
70
|
SetOnceError: Value of foo was 1, trying to set it to 2
|
72
71
|
```
|
73
72
|
|
74
|
-
###
|
73
|
+
### entry_or_collection.each_recursively on Object
|
75
74
|
|
76
75
|
Call the block on each entry that is given as entry, in a
|
77
|
-
collection, or in a collection in a collection to
|
78
|
-
depth. This implementation only uses each and
|
79
|
-
so it never instantiates an array or actual
|
80
|
-
objects (this allows streaming, lazy evaluation,
|
81
|
-
over objects that are read from a file that is
|
82
|
-
the memory size
|
83
|
-
|
84
|
-
TODO: refactor to "entry_or_collection.each_recursively"
|
76
|
+
collection, or in a collection in a collection, etc. to
|
77
|
+
unrestricted depth. This implementation only uses each and it
|
78
|
+
loops recursively, so it never instantiates an array or actual
|
79
|
+
collection of all objects (this allows streaming, lazy evaluation,
|
80
|
+
e.g. for looping over objects that are read from a file that is
|
81
|
+
much larger than the memory size).
|
85
82
|
|
86
83
|
```
|
87
|
-
2.0.0-p195 :021 >
|
84
|
+
2.0.0-p195 :021 > [:a, [:b, [:c]]].each_recursively{ |e| puts e.succ }
|
88
85
|
b
|
89
86
|
c
|
90
87
|
d
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class Object
|
2
|
+
|
3
|
+
def each_recursively(&block)
|
4
|
+
if self.respond_to?(:each)
|
5
|
+
loop_over_collection(self, &block)
|
6
|
+
else
|
7
|
+
yield(self)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def loop_over_collection(entry_or_collection, &block)
|
14
|
+
entry_or_collection.each do |inner_entry_or_collection|
|
15
|
+
inner_entry_or_collection.each_recursively(&block)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class SetOnceError < StandardError ; end
|
1
|
+
class RubyPeterV::SetOnceError < StandardError ; end
|
2
2
|
|
3
3
|
class Object
|
4
4
|
|
@@ -7,7 +7,7 @@ class Object
|
|
7
7
|
instance_value = instance_variable_get(ivar_symbol)
|
8
8
|
if (instance_value && instance_value != value)
|
9
9
|
raise(
|
10
|
-
SetOnceError,
|
10
|
+
RubyPeterV::SetOnceError,
|
11
11
|
"Value of #{attribute} was #{instance_value}, trying to set it to #{value}")
|
12
12
|
end
|
13
13
|
instance_variable_set(:"@#{attribute}", value)
|
data/lib/ruby_peter_v/single.rb
CHANGED
@@ -1,8 +1,18 @@
|
|
1
|
+
class RubyPeterV::UniquenessError < StandardError ; end
|
2
|
+
|
1
3
|
module Enumerable
|
2
4
|
|
3
|
-
def single
|
4
|
-
|
5
|
-
|
5
|
+
def single(&block)
|
6
|
+
filtered = block_given? ? self.select(&block) : self
|
7
|
+
if filtered.respond_to?(:size)
|
8
|
+
_size = filtered.size
|
9
|
+
message = size
|
10
|
+
else
|
11
|
+
_size = filtered.first(2).size
|
12
|
+
message = "greater than 1 (on Enumerable, the size cannot be calculated)"
|
13
|
+
end
|
14
|
+
raise RubyPeterV::UniquenessError, "size of collection was #{message}." if _size > 1
|
15
|
+
filtered.first
|
6
16
|
end
|
7
17
|
|
8
18
|
end
|
data/lib/ruby_peter_v/version.rb
CHANGED
data/lib/ruby_peter_v.rb
CHANGED
@@ -1,26 +1,26 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe "
|
3
|
+
describe "each_recursively" do
|
4
4
|
|
5
|
-
let(:a) {Object.new}
|
5
|
+
let(:a) { Object.new }
|
6
6
|
|
7
7
|
it "does it once for a non collection object" do
|
8
8
|
a.should_receive(:test_it).exactly(1).times
|
9
|
-
|
9
|
+
a.each_recursively do |_e|
|
10
10
|
_e.test_it
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
14
|
it "does it for each entry in a simple array" do
|
15
15
|
a.should_receive(:test_it).exactly(2).times
|
16
|
-
|
16
|
+
[a,a].each_recursively do |_e|
|
17
17
|
_e.test_it
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
21
|
it "does it for each entry in a complex combination" do
|
22
22
|
a.should_receive(:test_it).exactly(6).times
|
23
|
-
|
23
|
+
[a,[a,a],[[[a],a],a]].each_recursively do |_e|
|
24
24
|
_e.test_it
|
25
25
|
end
|
26
26
|
end
|
@@ -41,7 +41,7 @@ describe "do_recursively" do
|
|
41
41
|
|
42
42
|
it "call the each block 2 times" do
|
43
43
|
a.should_receive(:test_it).with("test").exactly(2).times
|
44
|
-
|
44
|
+
b.each_recursively do |_e|
|
45
45
|
a.test_it(_e)
|
46
46
|
end
|
47
47
|
end
|
@@ -49,7 +49,7 @@ describe "do_recursively" do
|
|
49
49
|
it "works with lazy in Ruby 2.0" do
|
50
50
|
pending("only Ruby >= 2.0") unless RUBY_VERSION.split('.').first.to_i >= 2
|
51
51
|
a.should_receive(:test_it).with("test").exactly(2).times
|
52
|
-
|
52
|
+
b.lazy.each_recursively do |_e|
|
53
53
|
a.test_it(_e)
|
54
54
|
end
|
55
55
|
end
|
@@ -61,10 +61,9 @@ describe "do_recursively" do
|
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
64
|
-
|
64
|
+
b.each_recursively do |_e|
|
65
65
|
_e
|
66
66
|
end
|
67
67
|
end
|
68
68
|
end
|
69
|
-
|
70
69
|
end
|
@@ -1,23 +1,109 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe "single" do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
describe "without a block" do
|
5
|
+
it "raises error on nil value (nil.first also raises error)" do
|
6
|
+
a = nil
|
7
|
+
lambda{ a.single }.should raise_error NoMethodError
|
8
|
+
end
|
9
|
+
|
10
|
+
it "nil for empty set" do
|
11
|
+
a = []
|
12
|
+
a.single.should == nil
|
13
|
+
end
|
8
14
|
|
9
|
-
|
10
|
-
|
11
|
-
|
15
|
+
it "OK for 1 element in set" do
|
16
|
+
a = [:a]
|
17
|
+
a.single.should == :a
|
18
|
+
end
|
19
|
+
|
20
|
+
it "exception for > 1 element in set" do
|
21
|
+
a = [:a, :b]
|
22
|
+
lambda{ a.single }.should raise_error(
|
23
|
+
RubyPeterV::UniquenessError,
|
24
|
+
"size of collection was 2.")
|
25
|
+
end
|
12
26
|
end
|
13
27
|
|
14
|
-
|
15
|
-
|
16
|
-
|
28
|
+
describe "accepts a block and uses it for a select" do
|
29
|
+
it "block all true" do
|
30
|
+
a = [:a, :b]
|
31
|
+
lambda{ a.single{ true } }.should raise_error(RubyPeterV::UniquenessError)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "block filters on :a" do
|
35
|
+
a = [:a, :b]
|
36
|
+
a.single{|e| e == :a}.should == :a
|
37
|
+
end
|
38
|
+
|
39
|
+
it "nil block" do
|
40
|
+
a = [:a, :b]
|
41
|
+
a.single{ }.should == nil
|
42
|
+
end
|
17
43
|
end
|
18
44
|
|
19
|
-
|
20
|
-
|
21
|
-
|
45
|
+
describe "works with a lazy Enumerator" do
|
46
|
+
let(:large_collection) do
|
47
|
+
Object.new.tap do |_a|
|
48
|
+
_a.extend Enumerable
|
49
|
+
_a.instance_eval do
|
50
|
+
def each
|
51
|
+
(1..3).each do |i|
|
52
|
+
test i
|
53
|
+
yield i
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def test(i)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
it "does not have a size method" do
|
64
|
+
lambda{ large_collection.size }.should raise_error(NoMethodError)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "count reports 3" do
|
68
|
+
large_collection.count.should == 3
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "single" do
|
72
|
+
it "reports the UniquenessError" do
|
73
|
+
lambda{ large_collection.single }.should raise_error(
|
74
|
+
RubyPeterV::UniquenessError,
|
75
|
+
"size of collection was greater than 1 (on Enumerable, the size cannot be calculated).")
|
76
|
+
end
|
77
|
+
|
78
|
+
it "does not loop over _all_ elements!" do
|
79
|
+
# only needs first and second element to know it is over size
|
80
|
+
large_collection.should_receive(:test).with(1)
|
81
|
+
large_collection.should_receive(:test).with(2)
|
82
|
+
large_collection.should_receive(:test).with(3).exactly(0).times
|
83
|
+
begin
|
84
|
+
large_collection.single
|
85
|
+
rescue RubyPeterV::UniquenessError
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
let(:single_collection) do
|
91
|
+
Object.new.tap do |_a|
|
92
|
+
_a.extend Enumerable
|
93
|
+
_a.instance_eval do
|
94
|
+
def each
|
95
|
+
yield :a
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
it "count reports 1" do
|
102
|
+
single_collection.count.should == 1
|
103
|
+
end
|
104
|
+
|
105
|
+
it "single returns the single value" do
|
106
|
+
single_collection.single.should == :a
|
107
|
+
end
|
22
108
|
end
|
23
109
|
end
|
metadata
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby_peter_v
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.0.8
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Peter Vandenabeele
|
@@ -14,39 +13,34 @@ dependencies:
|
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: rspec
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - '>='
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '2'
|
22
20
|
type: :development
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - '>='
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '2'
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: guard-rspec
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - '>='
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: '0'
|
38
34
|
type: :development
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - '>='
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: '0'
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: rb-fsevent
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
45
|
- - ~>
|
52
46
|
- !ruby/object:Gem::Version
|
@@ -54,7 +48,6 @@ dependencies:
|
|
54
48
|
type: :development
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
52
|
- - ~>
|
60
53
|
- !ruby/object:Gem::Version
|
@@ -62,17 +55,15 @@ dependencies:
|
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: terminal-notifier-guard
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
|
-
- -
|
59
|
+
- - '>='
|
68
60
|
- !ruby/object:Gem::Version
|
69
61
|
version: '0'
|
70
62
|
type: :development
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
|
-
- -
|
66
|
+
- - '>='
|
76
67
|
- !ruby/object:Gem::Version
|
77
68
|
version: '0'
|
78
69
|
description: Ruby helpers for @peter_v
|
@@ -93,43 +84,42 @@ files:
|
|
93
84
|
- Rakefile
|
94
85
|
- lib/ruby_peter_v.rb
|
95
86
|
- lib/ruby_peter_v/define_equality.rb
|
96
|
-
- lib/ruby_peter_v/
|
87
|
+
- lib/ruby_peter_v/each_recursively.rb
|
97
88
|
- lib/ruby_peter_v/set_once.rb
|
98
89
|
- lib/ruby_peter_v/single.rb
|
99
90
|
- lib/ruby_peter_v/version.rb
|
100
91
|
- ruby_peter_v.gemspec
|
101
92
|
- spec/lib/ruby_peter_v/define_equality_spec.rb
|
102
|
-
- spec/lib/ruby_peter_v/
|
93
|
+
- spec/lib/ruby_peter_v/each_recursively_spec.rb
|
103
94
|
- spec/lib/ruby_peter_v/set_once_spec.rb
|
104
95
|
- spec/lib/ruby_peter_v/single_spec.rb
|
105
96
|
- spec/spec_helper.rb
|
106
97
|
homepage: https://github.com/petervandenabeele/ruby_peter_v
|
107
98
|
licenses: []
|
99
|
+
metadata: {}
|
108
100
|
post_install_message:
|
109
101
|
rdoc_options: []
|
110
102
|
require_paths:
|
111
103
|
- lib
|
112
104
|
required_ruby_version: !ruby/object:Gem::Requirement
|
113
|
-
none: false
|
114
105
|
requirements:
|
115
|
-
- -
|
106
|
+
- - '>='
|
116
107
|
- !ruby/object:Gem::Version
|
117
108
|
version: '0'
|
118
109
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
119
|
-
none: false
|
120
110
|
requirements:
|
121
|
-
- -
|
111
|
+
- - '>='
|
122
112
|
- !ruby/object:Gem::Version
|
123
113
|
version: '0'
|
124
114
|
requirements: []
|
125
115
|
rubyforge_project:
|
126
|
-
rubygems_version:
|
116
|
+
rubygems_version: 2.0.3
|
127
117
|
signing_key:
|
128
|
-
specification_version:
|
118
|
+
specification_version: 4
|
129
119
|
summary: Ruby helpers for @peter_v
|
130
120
|
test_files:
|
131
121
|
- spec/lib/ruby_peter_v/define_equality_spec.rb
|
132
|
-
- spec/lib/ruby_peter_v/
|
122
|
+
- spec/lib/ruby_peter_v/each_recursively_spec.rb
|
133
123
|
- spec/lib/ruby_peter_v/set_once_spec.rb
|
134
124
|
- spec/lib/ruby_peter_v/single_spec.rb
|
135
125
|
- spec/spec_helper.rb
|
@@ -1,17 +0,0 @@
|
|
1
|
-
class Object
|
2
|
-
|
3
|
-
def do_recursively(entry_or_collection, &block)
|
4
|
-
if entry_or_collection.respond_to?(:each)
|
5
|
-
loop_over_collection(entry_or_collection, &block)
|
6
|
-
else
|
7
|
-
yield(entry_or_collection)
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
def loop_over_collection(entry_or_collection, &block)
|
12
|
-
entry_or_collection.each do |inner_entry_or_collection|
|
13
|
-
do_recursively(inner_entry_or_collection, &block)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
end
|