fetchable 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in fetchable.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Stephen Best
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,80 @@
1
+ # Fetchable
2
+
3
+ Provides a decorator to add a `Hash#fetch` like interface to any object.
4
+
5
+ For extra flexibility you may specify the method used to fetch items from the
6
+ underlying collection, the default is `[]`.
7
+
8
+ A lambda and `call` is a fun alternative.
9
+
10
+ `Hash#Fetch` is one of my favourite Ruby methods and can be tricky to implement
11
+ its full behaviour so here it is extracted for you to add to whichever object
12
+ you choose.
13
+
14
+ ## Installation
15
+
16
+ Add this line to your application's Gemfile:
17
+
18
+ gem 'fetchable'
19
+
20
+ And then execute:
21
+
22
+ $ bundle
23
+
24
+ Or install it yourself as:
25
+
26
+ $ gem install fetchable
27
+
28
+ ## Usage
29
+
30
+ ### Default Finder Method
31
+
32
+ ```ruby
33
+
34
+ require "fetchable"
35
+
36
+ array = ["zero", "one", "two"]
37
+
38
+ fetchable_array = Fetchable.new(array)
39
+
40
+ fetchable_array.fetch(0)
41
+ => "zero"
42
+
43
+ fetchable_array.fetch(2)
44
+ => "two"
45
+
46
+ fetchable_array.fetch(3)
47
+ => KeyError key not found 3
48
+
49
+ fetchable_array.fetch(3, "three")
50
+ => "three"
51
+
52
+ fetchable_array.fetch(3) { "Execute a block!" }
53
+ => "Execute a block!"
54
+
55
+ fetchable_array.fetch(3) { |key| "Do something based on missing key #{key}" }
56
+ => "Do something based on missing key 3"
57
+
58
+ ```
59
+
60
+ ### A Custom Finder Method
61
+
62
+ Add fetch to lambda, a HTTP client or just about anything.
63
+
64
+ ```ruby
65
+
66
+ function = ->(key) { |key| ["zero", "one", "two"][key] }
67
+ fetchable_function =Fetchable.new(function, :finder_method => :call)
68
+
69
+ fetchable_function.fetch(1)
70
+ => "one"
71
+
72
+ ```
73
+
74
+ ## Contributing
75
+
76
+ 1. Fork it
77
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
78
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
79
+ 4. Push to the branch (`git push origin my-new-feature`)
80
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'fetchable/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "fetchable"
8
+ spec.version = Fetchable::VERSION
9
+ spec.authors = ["Stephen Best"]
10
+ spec.email = ["bestie@gmail.com"]
11
+ spec.summary = %q{Provides a decorator to add a Hash#fetch style interface to any object.}
12
+ spec.description = spec.summary + " " + %{For extra flexibility you may specify the method used to fetch items from the underlying collection.}
13
+ spec.homepage = "https://github.com/bestie/fetchable"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = []
18
+ spec.test_files = spec.files.grep(%r{^(spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rspec", "~> 2.14"
23
+ spec.add_development_dependency "pry", "~> 0.9.12"
24
+ end
@@ -0,0 +1,36 @@
1
+ require "fetchable/version"
2
+ require "delegate"
3
+
4
+ class Fetchable < SimpleDelegator
5
+ def initialize(collection, args={})
6
+ @collection = collection
7
+ @finder_method_name = args.fetch(:finder_method, :[])
8
+ super(collection)
9
+ end
10
+
11
+ def fetch(key, not_found_value = no_default_given, &block)
12
+ if not_found_value != no_default_given && block
13
+ raise ArgumentError.new("Cannot provide both a default arg and block to #fetch")
14
+ end
15
+
16
+ @collection.public_send(@finder_method_name, key) || default_value(key, not_found_value, &block)
17
+ end
18
+
19
+ private
20
+
21
+ def no_default_given
22
+ @default ||= Object.new
23
+ end
24
+
25
+ def default_value(key, not_found_value, &block)
26
+ if not_found_value == no_default_given
27
+ if block
28
+ block.call(key)
29
+ else
30
+ raise KeyError.new("#{key} not found in #{@collection.inspect}")
31
+ end
32
+ else
33
+ not_found_value
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,3 @@
1
+ require "fetchable"
2
+
3
+ Fetchable::VERSION = "0.0.1"
@@ -0,0 +1,98 @@
1
+ require "spec_helper"
2
+
3
+ require "fetchable"
4
+
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)
10
+ }
11
+
12
+ let(:finder_method) { :[] }
13
+ let(:fetched_object) { double(:fetched_object) }
14
+ let(:fetch_key) { double(:fetch_key) }
15
+
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
+ describe "#fetch" do
29
+ it "delegates to the collection's finder method" do
30
+ fetchable.fetch(fetch_key)
31
+
32
+ expect(collection).to have_received(finder_method).with(fetch_key)
33
+ end
34
+
35
+ context "when entry for key exists" do
36
+ it "does not execute the block" do
37
+ expect {
38
+ fetchable.fetch(fetch_key) { raise "This block must not run" }
39
+ }.not_to raise_error
40
+ end
41
+
42
+ it "returns the entry from the collection" do
43
+ expect(fetchable.fetch(fetch_key)).to be fetched_object
44
+ end
45
+ end
46
+
47
+ context "when entry for key does not exist" do
48
+ let(:fetched_object) { nil }
49
+
50
+ context "when a default argument is given" do
51
+ let(:default) { double(:default) }
52
+
53
+ it "returns the default" do
54
+ expect(fetchable.fetch(fetch_key, default)).to be default
55
+ end
56
+
57
+ context "when default argument is nil" do
58
+ it "returns nil" do
59
+ expect(fetchable.fetch(fetch_key, nil)).to be nil
60
+ end
61
+ end
62
+
63
+ context "when default argument is false" do
64
+ it "returns false" do
65
+ expect(fetchable.fetch(fetch_key, false)).to be false
66
+ end
67
+ end
68
+ end
69
+
70
+ context "when a block is given" do
71
+ let(:spy) { double(:spy, :block_was_called => block_return_value) }
72
+ let(:block) { lambda { |key| spy.block_was_called(key) } }
73
+ let(:block_return_value) { double(:block_return_value) }
74
+
75
+ it "returns the result of block" do
76
+ expect(fetchable.fetch(fetch_key, &block)).to be block_return_value
77
+ end
78
+
79
+ it "yields the key to the block" do
80
+ fetchable.fetch(fetch_key, &block)
81
+ expect(spy).to have_received(:block_was_called).with(fetch_key)
82
+ end
83
+ end
84
+
85
+ context "no default or block given" do
86
+ it "raises record not found" do
87
+ expect{ fetchable.fetch(fetch_key) }.to raise_error(KeyError)
88
+ end
89
+ end
90
+ end
91
+
92
+ context "when both block and default argument is given" do
93
+ it "raises ArgumentError" do
94
+ expect{ fetchable.fetch(fetch_key, nil) {} }.to raise_error(ArgumentError)
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,17 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+ RSpec.configure do |config|
8
+ config.treat_symbols_as_metadata_keys_with_true_values = true
9
+ config.run_all_when_everything_filtered = true
10
+ config.filter_run :focus
11
+
12
+ # Run specs in random order to surface order dependencies. If you find an
13
+ # order dependency and want to debug it, you can fix the order by providing
14
+ # the seed, which is printed after each run.
15
+ # --seed 1234
16
+ config.order = 'random'
17
+ end
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fetchable
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Stephen Best
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-10-28 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ~>
19
+ - !ruby/object:Gem::Version
20
+ version: '1.3'
21
+ none: false
22
+ prerelease: false
23
+ type: :development
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ version: '1.3'
29
+ none: false
30
+ - !ruby/object:Gem::Dependency
31
+ name: rspec
32
+ requirement: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - ~>
35
+ - !ruby/object:Gem::Version
36
+ version: '2.14'
37
+ none: false
38
+ prerelease: false
39
+ type: :development
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ version: '2.14'
45
+ none: false
46
+ - !ruby/object:Gem::Dependency
47
+ name: pry
48
+ requirement: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ~>
51
+ - !ruby/object:Gem::Version
52
+ version: 0.9.12
53
+ none: false
54
+ prerelease: false
55
+ type: :development
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ~>
59
+ - !ruby/object:Gem::Version
60
+ version: 0.9.12
61
+ none: false
62
+ description: Provides a decorator to add a Hash#fetch style interface to any object.
63
+ For extra flexibility you may specify the method used to fetch items from the underlying
64
+ collection.
65
+ email:
66
+ - bestie@gmail.com
67
+ executables: []
68
+ extensions: []
69
+ extra_rdoc_files: []
70
+ files:
71
+ - .gitignore
72
+ - .rspec
73
+ - Gemfile
74
+ - LICENSE.txt
75
+ - README.md
76
+ - Rakefile
77
+ - fetchable.gemspec
78
+ - lib/fetchable.rb
79
+ - lib/fetchable/version.rb
80
+ - spec/lib/fetchable_spec.rb
81
+ - spec/spec_helper.rb
82
+ homepage: https://github.com/bestie/fetchable
83
+ licenses:
84
+ - MIT
85
+ post_install_message:
86
+ rdoc_options: []
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ none: false
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ! '>='
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ none: false
101
+ requirements: []
102
+ rubyforge_project:
103
+ rubygems_version: 1.8.25
104
+ signing_key:
105
+ specification_version: 3
106
+ summary: Provides a decorator to add a Hash#fetch style interface to any object.
107
+ test_files:
108
+ - spec/lib/fetchable_spec.rb
109
+ - spec/spec_helper.rb