ruby_peter_v 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
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