fetchable 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,16 +1,22 @@
1
1
  # Fetchable
2
2
 
3
- Provides a decorator to add a `Hash#fetch` like interface to any object.
3
+ [![Gem Version](https://badge.fury.io/rb/keyword_curry.png)](http://badge.fury.io/rb/keyword_curry)
4
4
 
5
- For extra flexibility you may specify the method used to fetch items from the
6
- underlying collection, the default is `[]`.
5
+ Provides a mixin and decorator to add a `Hash#fetch` like interface to any object.
7
6
 
8
- A lambda and `call` is a fun alternative.
7
+ You must define a `[]` subscript method for raw access to the fetchable data.
8
+
9
+ Your `[]` method must return anything but nil in order for `#fetch` to consider
10
+ a key successfully fetched. `False` is considered sucessful.
9
11
 
10
12
  `Hash#Fetch` is one of my favourite Ruby methods and can be tricky to implement
11
13
  its full behaviour so here it is extracted for you to add to whichever object
12
14
  you choose.
13
15
 
16
+ If you're not familiar with `Hash#fetch` it's a great way to help eliminate nils
17
+ as it raises an error when the desired key is not found. For more info consult
18
+ [Ruby Hash documentation](http://www.ruby-doc.org/core-2.1.0/Hash.html#method-i-fetch).
19
+
14
20
  ## Installation
15
21
 
16
22
  Add this line to your application's Gemfile:
@@ -27,50 +33,61 @@ Or install it yourself as:
27
33
 
28
34
  ## Usage
29
35
 
30
- ### Default Finder Method
36
+ ### Include into a object with a `[]` method
31
37
 
32
38
  ```ruby
33
39
 
34
40
  require "fetchable"
35
41
 
36
- array = ["zero", "one", "two"]
37
-
38
- fetchable_array = Fetchable.new(array)
42
+ things = %w(zero one two).extend(Fetchable)
39
43
 
40
- fetchable_array.fetch(0)
44
+ things.fetch(0)
41
45
  => "zero"
42
46
 
43
- fetchable_array.fetch(2)
47
+ things.fetch(2)
44
48
  => "two"
45
49
 
46
- fetchable_array.fetch(3)
47
- => KeyError key not found 3
50
+ things.fetch(3)
51
+ => KeyError: key not found 3
48
52
 
49
- fetchable_array.fetch(3, "three")
53
+ things.fetch(3, "three")
50
54
  => "three"
51
55
 
52
- fetchable_array.fetch(3) { "Execute a block!" }
56
+ things.fetch(3) { "Execute a block!" }
53
57
  => "Execute a block!"
54
58
 
55
- fetchable_array.fetch(3) { |key| "Do something based on missing key #{key}" }
59
+ things.fetch(3) { |key| "Do something based on missing key #{key}" }
56
60
  => "Do something based on missing key 3"
57
61
 
58
62
  ```
59
63
 
60
- ### A Custom Finder Method
64
+ ### Prefer composition over inheritance?
61
65
 
62
- Add fetch to lambda, a HTTP client or just about anything.
66
+ We got you covered! Use `Fetchable::Decorator` instead.
63
67
 
64
68
  ```ruby
65
69
 
66
- function = ->(key) { |key| ["zero", "one", "two"][key] }
67
- fetchable_function =Fetchable.new(function, :finder_method => :call)
70
+ require "fetchable/decorator"
71
+
72
+ things = %w(zero one two)
73
+
74
+ fetchable_things = Fetchable::Decorator.new(things)
68
75
 
69
- fetchable_function.fetch(1)
76
+ fetchable_things.fetch(1)
70
77
  => "one"
71
78
 
72
79
  ```
73
80
 
81
+ ### For bonus points use lambdas
82
+
83
+ Lambdas, procs and method objects can also be called with `#[]`.
84
+
85
+ Why not make them fetchable?
86
+
87
+ It might be funny.
88
+
89
+ Dammit method, you better not return me a `nil`, I'll be so mad.
90
+
74
91
  ## Contributing
75
92
 
76
93
  1. Fork it
data/lib/fetchable.rb CHANGED
@@ -1,18 +1,16 @@
1
- require "delegate"
2
-
3
- class Fetchable < SimpleDelegator
4
- def initialize(collection, args={})
5
- @collection = collection
6
- @finder_method_name = args.fetch(:finder_method, :[])
7
- super(collection)
8
- end
9
-
1
+ module Fetchable
10
2
  def fetch(key, not_found_value = no_default_given, &block)
11
3
  if not_found_value != no_default_given && block
12
4
  raise ArgumentError.new("Cannot provide both a default arg and block to #fetch")
13
5
  end
14
6
 
15
- @collection.public_send(@finder_method_name, key) || default_value(key, not_found_value, &block)
7
+ result = public_send(:[], key)
8
+
9
+ if result.nil?
10
+ default_value(key, not_found_value, &block)
11
+ else
12
+ result
13
+ end
16
14
  end
17
15
 
18
16
  private
@@ -26,7 +24,7 @@ class Fetchable < SimpleDelegator
26
24
  if block
27
25
  block.call(key)
28
26
  else
29
- raise KeyError.new("#{key} not found in #{@collection.inspect}")
27
+ raise KeyError.new("key not found #{key}")
30
28
  end
31
29
  else
32
30
  not_found_value
@@ -0,0 +1,11 @@
1
+ require "fetchable"
2
+ require "delegate"
3
+
4
+ class Fetchable::Decorator < SimpleDelegator
5
+ include Fetchable
6
+
7
+ def [](asd)
8
+ __getobj__[asd]
9
+ end
10
+ end
11
+
@@ -1,3 +1,5 @@
1
1
  require "fetchable"
2
2
 
3
- Fetchable::VERSION = "0.0.2"
3
+ module Fetchable
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,37 @@
1
+ require "spec_helper"
2
+
3
+ require "fetchable/decorator"
4
+
5
+ describe Fetchable::Decorator do
6
+ subject(:fetchable) {
7
+ Fetchable::Decorator.new(collection)
8
+ }
9
+
10
+ let(:collection) { double(:collection, :[] => fetched_object) }
11
+
12
+ let(:fetched_object) { double(:fetched_object) }
13
+ let(:fetch_key) { double(:fetch_key) }
14
+
15
+ it "is a true decorator" do
16
+ expect(collection).to receive(:i_am_a_decorator_and_forward_all_messages)
17
+ .with("some", "args")
18
+
19
+ fetchable.i_am_a_decorator_and_forward_all_messages("some", "args")
20
+ end
21
+
22
+ it "is fetchable" do
23
+ expect(fetchable).to be_a(Fetchable)
24
+ end
25
+
26
+ describe "#fetch" do
27
+ it "delegates to the collection's #[] method" do
28
+ fetchable.fetch(fetch_key)
29
+
30
+ expect(collection).to have_received(:[]).with(fetch_key)
31
+ end
32
+
33
+ it "returns the entry from the collection" do
34
+ expect(fetchable.fetch(fetch_key)).to be fetched_object
35
+ end
36
+ end
37
+ end
@@ -3,33 +3,18 @@ require "spec_helper"
3
3
  require "fetchable"
4
4
 
5
5
  describe Fetchable do
6
- subject(:fetchable) { Fetchable.new(collection, finder_method: finder_method) }
7
-
8
- let(:collection) {
9
- double(:collection, finder_method => fetched_object)
6
+ subject(:fetchable) {
7
+ double(:fetchable, :[] => fetched_object).extend(Fetchable)
10
8
  }
11
9
 
12
- let(:finder_method) { :[] }
13
10
  let(:fetched_object) { double(:fetched_object) }
14
11
  let(:fetch_key) { double(:fetch_key) }
15
12
 
16
- it "is a true decorator" do
17
- expect(collection).to receive(:arbitrary).with("an arg")
18
-
19
- fetchable.arbitrary("an arg")
20
- end
21
-
22
- it "defaults the finder method to []" do
23
- expect(
24
- Fetchable.new(collection).fetch(fetch_key)
25
- ).to be fetched_object
26
- end
27
-
28
13
  describe "#fetch" do
29
- it "delegates to the collection's finder method" do
14
+ it "delegates to the fetchable's finder method" do
30
15
  fetchable.fetch(fetch_key)
31
16
 
32
- expect(collection).to have_received(finder_method).with(fetch_key)
17
+ expect(fetchable).to have_received(:[]).with(fetch_key)
33
18
  end
34
19
 
35
20
  context "when entry for key exists" do
@@ -39,7 +24,21 @@ describe Fetchable do
39
24
  }.not_to raise_error
40
25
  end
41
26
 
42
- it "returns the entry from the collection" do
27
+ it "returns the entry from the fetchable" do
28
+ expect(fetchable.fetch(fetch_key)).to be fetched_object
29
+ end
30
+ end
31
+
32
+ context "when the enrty for the key comes back false" do
33
+ let(:fetched_object) { false }
34
+
35
+ it "does not execute the block" do
36
+ expect {
37
+ fetchable.fetch(fetch_key) { raise "This block must not run" }
38
+ }.not_to raise_error
39
+ end
40
+
41
+ it "returns the entry from the fetchable" do
43
42
  expect(fetchable.fetch(fetch_key)).to be fetched_object
44
43
  end
45
44
  end
@@ -84,7 +83,7 @@ describe Fetchable do
84
83
 
85
84
  context "no default or block given" do
86
85
  it "raises record not found" do
87
- expect{ fetchable.fetch(fetch_key) }.to raise_error(KeyError)
86
+ expect{ fetchable.fetch(fetch_key) }.to raise_error(KeyError, "key not found #{fetch_key}")
88
87
  end
89
88
  end
90
89
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fetchable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-10-28 00:00:00.000000000 Z
13
+ date: 2013-10-29 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bundler
@@ -78,8 +78,10 @@ files:
78
78
  - Rakefile
79
79
  - fetchable.gemspec
80
80
  - lib/fetchable.rb
81
+ - lib/fetchable/decorator.rb
81
82
  - lib/fetchable/version.rb
82
- - spec/lib/fetchable_spec.rb
83
+ - spec/fetchable/decorator_spec.rb
84
+ - spec/fetchable_spec.rb
83
85
  - spec/spec_helper.rb
84
86
  homepage: https://github.com/bestie/fetchable
85
87
  licenses:
@@ -107,5 +109,6 @@ signing_key:
107
109
  specification_version: 3
108
110
  summary: Provides a decorator to add a Hash#fetch style interface to any object.
109
111
  test_files:
110
- - spec/lib/fetchable_spec.rb
112
+ - spec/fetchable/decorator_spec.rb
113
+ - spec/fetchable_spec.rb
111
114
  - spec/spec_helper.rb