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 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-03)
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 the set. Using first is fine, but if
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
- TODO: refactor : use a dedicated exception UniquenessError
26
- TODO: refactor : take a block (a "detect" with uniqueness check)
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
- RuntimeError: INTERNAL ERROR: size of set was 2
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
- ### do_recursively(entry_or_collection, &block) on Object
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 unrestricted
78
- depth. This implementation only uses each and loops recursively,
79
- so it never instantiates an array or actual collection of all
80
- objects (this allows streaming, lazy evaluation, e.g. for looping
81
- over objects that are read from a file that is much larger than
82
- the memory size, needed for Big Data processing).
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 > do_recursively([:a, [:b, [:c]]]) { |e| puts e.succ }
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)
@@ -1,8 +1,18 @@
1
+ class RubyPeterV::UniquenessError < StandardError ; end
2
+
1
3
  module Enumerable
2
4
 
3
- def single
4
- raise "INTERNAL ERROR: size of set was #{size}" if size > 1
5
- first
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
@@ -1,3 +1,3 @@
1
1
  module RubyPeterV
2
- VERSION = "0.0.7"
2
+ VERSION = "0.0.8"
3
3
  end
data/lib/ruby_peter_v.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require 'ruby_peter_v/version'
2
2
  require 'ruby_peter_v/single'
3
3
  require 'ruby_peter_v/set_once'
4
- require 'ruby_peter_v/do_recursively'
5
4
  require 'ruby_peter_v/define_equality'
5
+ require 'ruby_peter_v/each_recursively'
@@ -1,26 +1,26 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe "do_recursively" do
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
- do_recursively(a) do |_e|
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
- do_recursively([a,a]) do |_e|
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
- do_recursively([a,[a,a],[[[a],a],a]]) do |_e|
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
- do_recursively(b) do |_e|
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
- do_recursively(b.lazy) do |_e|
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
- do_recursively(b) do |_e|
64
+ b.each_recursively do |_e|
65
65
  _e
66
66
  end
67
67
  end
68
68
  end
69
-
70
69
  end
@@ -23,7 +23,7 @@ describe "set_once" do
23
23
  value = 10
24
24
  subject.set_once(:attr, value)
25
25
  lambda { subject.set_once(:attr, value+1) } . should raise_error(
26
- SetOnceError,
26
+ RubyPeterV::SetOnceError,
27
27
  "Value of attr was 10, trying to set it to 11")
28
28
  end
29
29
  end
@@ -1,23 +1,109 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe "single" do
4
- it "raises error on nil value (nil.first also raises error)" do
5
- a = nil
6
- lambda { a.single } . should raise_error NoMethodError
7
- end
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
- it "nil for empty set" do
10
- a = []
11
- a.single.should == nil
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
- it "OK for 1 element in set" do
15
- a = [:a]
16
- a.single.should == :a
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
- it "exception for > 1 element in set" do
20
- a = [:a, :b]
21
- lambda { a.single } . should raise_exception RuntimeError
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.7
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/do_recursively.rb
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/do_recursively_spec.rb
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: 1.8.25
116
+ rubygems_version: 2.0.3
127
117
  signing_key:
128
- specification_version: 3
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/do_recursively_spec.rb
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