duckpond 1.0.0

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: 515a4dbf8c5dfcc7ac533ebc75579053972755fe
4
+ data.tar.gz: 2b99253f7d6f981e307a01fa324ba20d3bb0dc87
5
+ SHA512:
6
+ metadata.gz: 21b5db87d898f1c3759fed7c1beb9b254d57e32646daddaff7808d072ee42ca206d6f128b96656bd29d6996b1e565863ac0ca5a4aa1c14e43056ad751b3defae
7
+ data.tar.gz: 8a4f5c3892a69fbc10bb59deee0d20f0bdec7e046fb31ce0076d7dc7b8eb7a8c8bd767b8469aa8aea676d9fd31c6f6193ded7b5e3b3a03f7d6afc903edf08f0e
data/.gitignore ADDED
@@ -0,0 +1,34 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Specific to RubyMotion:
13
+ .dat*
14
+ .repl_history
15
+ build/
16
+
17
+ ## Documentation cache and generated files:
18
+ /.yardoc/
19
+ /_yardoc/
20
+ /doc/
21
+ /rdoc/
22
+
23
+ ## Environment normalisation:
24
+ /.bundle/
25
+ /lib/bundler/man/
26
+
27
+ # for a library or gem, you might want to ignore these files since the code is
28
+ # intended to run in multiple environments; otherwise, check them in:
29
+ # Gemfile.lock
30
+ # .ruby-version
31
+ # .ruby-gemset
32
+
33
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
34
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in duckpond.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,17 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ duckpond (1.0.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ rake (10.3.2)
10
+
11
+ PLATFORMS
12
+ ruby
13
+
14
+ DEPENDENCIES
15
+ bundler (~> 1.3)
16
+ duckpond!
17
+ rake
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Mikey Hogarth
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,78 @@
1
+ # Duckpond
2
+
3
+ Explicit duck typing for ruby.
4
+
5
+
6
+ ## Inspiration
7
+
8
+ Duck Typing can make code confusing and unreadable, particularly
9
+ when multiple developers are working on the same project or when
10
+ projects are inherited by new developers.
11
+
12
+ The spec folder has two files that go through the purpose of this gem
13
+ in spec form. This would be a good place to start, although there is a crash
14
+ course below.
15
+
16
+ * [the_problem_spec](spec/the_problem_spec.rb) - This outlines the problems with duck typing.
17
+
18
+ * [the_solution_spec](spec/the_solution_spec.rb) - This outlines how duckpond gets around these problems.
19
+
20
+
21
+ ## Installation
22
+
23
+ Add this line to your application's Gemfile:
24
+
25
+ gem 'duckpond'
26
+
27
+ And then execute:
28
+
29
+ $ bundle
30
+
31
+ Or install it yourself as:
32
+
33
+ $ gem install duckpond
34
+
35
+
36
+ ## Usage
37
+
38
+ Usage is demonstrated in 'the_solution_spec', but in a nutshell you can create
39
+ "duck" classes by inheriting from DuckPond::Duck. This file should be commented
40
+ extensively as it describes the contract the duck represents.
41
+
42
+ class MyDuck < DuckPond::Duck
43
+ quacks_like :length
44
+ end
45
+
46
+ Once you've declared a duck, you can use "binoculars" to see if objects quack like
47
+ that duck:
48
+
49
+ obj = "Hello World"
50
+ sighting = DuckPond::Binoculars.identify(obj)
51
+ sighting.quacks_like? MyDuck
52
+ => true
53
+
54
+ There are other syntaxes:
55
+
56
+ #This syntax gets all the comparison done in one line
57
+ DuckPond::Binoculars.confirm(obj, MyDuck)
58
+ => true
59
+
60
+ #This syntax does the same thing, but raises an excaption instead of returning false
61
+ DuckPond::Binoculars.confirm!(obj, MyDuck)
62
+
63
+
64
+ Ducks can be combined into composite "super ducks" using the looks_like method - ducks which are made up of various other ducks:
65
+
66
+ class MySuperDuck < DuckPond::Duck
67
+ looks_like MyDuck
68
+ looks_like MyOtherDuck
69
+ end
70
+
71
+
72
+ ## Contributing
73
+
74
+ 1. Fork it
75
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
76
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
77
+ 4. Push to the branch (`git push origin my-new-feature`)
78
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/duckpond.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'duckpond/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "duckpond"
8
+ spec.version = Duckpond::VERSION
9
+ spec.authors = ["Mikey Hogarth"]
10
+ spec.email = ["mikehogarth20@hotmail.com"]
11
+ spec.description = %q{Explicit duck-typing for ruby}
12
+ spec.summary = %q{Explicit duck-typing for ruby}
13
+ spec.homepage = "https://github.com/mikeyhogarth/duckpond"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(spec)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake", "~> 0"
23
+ end
@@ -0,0 +1,57 @@
1
+ #
2
+ # DuckPond::Binoculars
3
+ #
4
+ # Binoculars are the users interface to the ducks themselves and
5
+ # are responsible for building "sightings" out of objects. There
6
+ # are also a couple of convinience methods on here to perform
7
+ # common duck-spotting tasks.
8
+ #
9
+ module DuckPond
10
+ class Binoculars
11
+ class WrongDuckError < TypeError;end
12
+
13
+ # The sighted object
14
+ attr_reader :sighting
15
+
16
+ #
17
+ # identify (class and instance level version)
18
+ #
19
+ # receives any ruby object, returns a "sighting" of that object
20
+ #
21
+ def identify(obj)
22
+ @sighting = DuckPond::Sighting.new(obj)
23
+ end
24
+
25
+ def self.identify(obj)
26
+ DuckPond::Sighting.new(obj)
27
+ end
28
+
29
+ #
30
+ # confirm
31
+ #
32
+ # receives any ruby object and a duck class
33
+ # returns true if the object quacks like the duck,
34
+ # otherwise false.
35
+ #
36
+ def self.confirm(obj, duck)
37
+ binoculars = DuckPond::Binoculars.new
38
+ sighting = binoculars.identify(obj)
39
+ return false unless sighting.quacks_like?(duck)
40
+ true
41
+ end
42
+
43
+ #
44
+ # confirm!
45
+ #
46
+ # does exactly the same as the standard confirm
47
+ # method, but raises an exception if the object
48
+ # does not quack like the duck.
49
+ #
50
+ def self.confirm!(obj, duck)
51
+ raise WrongDuckError unless confirm(obj, duck)
52
+ end
53
+
54
+ end
55
+ end
56
+
57
+
@@ -0,0 +1,43 @@
1
+ #
2
+ # DuckPond::Duck
3
+ #
4
+ # Ducks are essentially "contracts" or "interfaces". They are not intended
5
+ # to ever be instantiated, and are completely configured at the class level.
6
+ #
7
+ module DuckPond
8
+ class Duck
9
+ class << self
10
+
11
+ def quacks
12
+ @quacks ||= []
13
+ end
14
+
15
+ #
16
+ # quacks_like
17
+ #
18
+ # Use this to specify that this duck quacks with
19
+ # a certain method.
20
+ #
21
+ def quacks_like(method)
22
+ quacks << method
23
+ end
24
+
25
+ #
26
+ # looks_like
27
+ #
28
+ # Use this to specify that this duck looks like
29
+ # another duck.
30
+ #
31
+ def looks_like(other_duck)
32
+ other_duck.quacks.each do |other_ducks_quacking|
33
+ quacks_like other_ducks_quacking
34
+ end
35
+ end
36
+
37
+ def quacks_like?(method)
38
+ quacks.include?(method)
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,36 @@
1
+ #
2
+ # DuckPond::Sighting
3
+ #
4
+ # The duckpond sighting class is essentially just a wrapper for the sighted
5
+ # object, used here to avoid un-nessecary monkey patching.
6
+ #
7
+ module DuckPond
8
+ class Sighting
9
+
10
+ # the wrapped object
11
+ attr_reader :sighted_object
12
+
13
+ #
14
+ # initialize
15
+ #
16
+ # Construct with any ruby object.
17
+ #
18
+ def initialize(sighted_object)
19
+ @sighted_object = sighted_object
20
+ end
21
+
22
+ #
23
+ # quacks_like?
24
+ #
25
+ # receives exactly one duck, and returns true/false if
26
+ # the sighted object responds to the same methods indicated
27
+ # by the duck's quacks.
28
+ #
29
+ def quacks_like?(duck)
30
+ duck.quacks.each do |quack|
31
+ return false unless @sighted_object.respond_to? quack
32
+ end
33
+ true
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,3 @@
1
+ module Duckpond
2
+ VERSION = "1.0.0"
3
+ end
data/lib/duckpond.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'duckpond/version'
2
+ require 'duckpond/duck'
3
+ require 'duckpond/binoculars'
4
+ require 'duckpond/sighting'
5
+
6
+ module Duckpond
7
+ end
@@ -0,0 +1,52 @@
1
+ require 'spec_helper'
2
+
3
+ module DuckPond
4
+ describe Binoculars do
5
+
6
+ let(:obj) { Object.new }
7
+
8
+ describe '#identify' do
9
+ it 'returns any ruby object, in "sighting" form' do
10
+ bins = Binoculars.new
11
+ sighting = bins.identify(obj)
12
+ expect(sighting).to be_a Sighting
13
+ expect(sighting.sighted_object). to be obj
14
+ end
15
+ end
16
+
17
+ describe ".identify" do
18
+ it 'returns any ruby object, in "sighting" form' do
19
+ sighting = Binoculars.identify(obj)
20
+ expect(sighting).to be_a Sighting
21
+ expect(sighting.sighted_object). to be obj
22
+ end
23
+ end
24
+
25
+ describe '.confirm' do
26
+
27
+ class StringDuck < Duck
28
+ quacks_like :to_s
29
+ quacks_like :length
30
+ end
31
+
32
+ context 'when given a ruby object and a duck class that it quacks like' do
33
+ it 'returns true' do
34
+ expect(DuckPond::Binoculars.confirm("Hello World", StringDuck)).to be true
35
+ end
36
+ end
37
+
38
+ context 'when given a ruby object and a duck class that it doesnt quacks like' do
39
+ it 'returns false' do
40
+ expect(DuckPond::Binoculars.confirm(Object.new, StringDuck)).to be false
41
+ end
42
+ end
43
+ end
44
+
45
+ describe '.confirm!' do
46
+ it 'behaves like the un-banged version, but raises an error if it doesnt quack right' do
47
+ expect {DuckPond::Binoculars.confirm!(Object.new, StringDuck)}.to raise_error
48
+ end
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,10 @@
1
+ module Duckpond
2
+ module Test
3
+ class Fooinator
4
+ def bar(obj)
5
+ obj
6
+ end
7
+ end
8
+ end
9
+ end
10
+
data/spec/duck_spec.rb ADDED
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ module DuckPond
4
+
5
+ describe Duck do
6
+ describe 'attributes' do
7
+ context '.quackings' do
8
+ it 'responds to and memoizes the result' do
9
+ expect(Duck).to respond_to :quacks
10
+ expect(Duck.quacks).to be_an Array
11
+ expect(Duck.quacks).to be_empty
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ class MyDuck < Duck
18
+ quacks_like :foo
19
+ quacks_like :bar
20
+ end
21
+
22
+ describe MyDuck do
23
+ context '.quackings' do
24
+ it 'quacks like foo and bar' do
25
+ quacks = MyDuck.quacks
26
+ expect(quacks.length).to eq 2
27
+ expect(quacks).to include :foo
28
+ expect(quacks).to include :bar
29
+ end
30
+ end
31
+
32
+ describe '.quacks_like?' do
33
+ it 'returns true if the argument is in the quackings' do
34
+ expect(MyDuck.quacks_like? :foo).to be true
35
+ expect(MyDuck.quacks_like? :chunky_bacon).to be false
36
+ end
37
+ end
38
+ end
39
+
40
+ class MySimilarDuck < Duck
41
+ looks_like MyDuck
42
+ quacks_like :chunky_bacon
43
+ end
44
+
45
+ describe MySimilarDuck do
46
+ it 'retains its parents quackings' do
47
+ expect(MySimilarDuck.quacks_like? :chunky_bacon).to be true
48
+ expect(MySimilarDuck.quacks_like? :foo).to be true
49
+ expect(MySimilarDuck.quacks_like? :bar).to be true
50
+ end
51
+ end
52
+
53
+ end
@@ -0,0 +1,38 @@
1
+ require 'ostruct'
2
+
3
+ module DuckPond
4
+ describe Sighting do
5
+
6
+ describe '#initialize' do
7
+ it 'is constructed using any ruby object' do
8
+ obj = Object.new
9
+ sighting = Sighting.new(obj)
10
+ expect(sighting.sighted_object).to be obj
11
+ end
12
+ end
13
+
14
+ describe '#quacks_like?' do
15
+
16
+ class MyChunkyBaconDuck < Duck
17
+ quacks_like :chunky_bacon
18
+ end
19
+
20
+ context 'when the sighted object quacks like the duck' do
21
+ it 'returns true' do
22
+ obj = OpenStruct.new(:chunky_bacon => :mmm)
23
+ sighting = Sighting.new(obj)
24
+ expect(sighting.quacks_like? MyChunkyBaconDuck).to be true
25
+ end
26
+ end
27
+
28
+ context 'when the sighted object does not quack like the duck' do
29
+ it 'returns false' do
30
+ obj = OpenStruct.new(:vegan_fallafal => :yuck)
31
+ sighting = Sighting.new(obj)
32
+ expect(sighting.quacks_like? MyChunkyBaconDuck).to be false
33
+ end
34
+ end
35
+
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,2 @@
1
+ require 'duckpond'
2
+ require 'classes/fooinator'
@@ -0,0 +1,120 @@
1
+ require 'spec_helper'
2
+
3
+ module Duckpond
4
+ describe 'The Problem' do
5
+ context 'when a method is called' do
6
+ it 'is often difficult to see what parameters are allowed' do
7
+
8
+ #
9
+ # Take this class for instance...
10
+ #
11
+ # It has a single method which;
12
+ #
13
+ # * Calls an instance method on its parameter.
14
+ # * Sends its parameter off to some other object.
15
+ # * Creates an instance variable with the result.
16
+ #
17
+
18
+ class Foo
19
+ def self.bar(obj)
20
+ obj.foo!
21
+ fooinator = Test::Fooinator.new
22
+ @fooified_obj = fooinator.foo(obj)
23
+ end
24
+ end
25
+
26
+ #
27
+ # From an architectural perspective, there is really nothing
28
+ # wrong with this class/method. Even from a design perspective
29
+ # the only thing that you can really criticize is that the
30
+ # method is a little vague in terms of what it does, and that's just
31
+ # because we don't know what "fooing" is.
32
+ #
33
+ # But there are a few other problems.
34
+ #
35
+ # You will often hear rubyists talking about the wonder of
36
+ # "duck typing". Developers can pass anything they want to the "bar"
37
+ # method above and it'll still work so long as the parameter responds
38
+ # to certain methods etc.
39
+ #
40
+ # You will almost as often hear programmers freaking out about how
41
+ # chaotic and crazy this approach is! Arguments about such matters usually
42
+ # eventually gravitate towards the problem being that ruby is not
43
+ # strongly typed. The knowledge about what "ducks" can be sent to the
44
+ # :bar method is not stored anywhere: it's implicit in obj's usage. Great if
45
+ # you were the developer of the method and you understand it completely,
46
+ # but what if it's someone else?
47
+ #
48
+ # In the above example, in order to see which type of object they can
49
+ # pass to the "bar" method, a developer would at the very least need
50
+ # to:
51
+ #
52
+ # * Grep for "foo!" to see what the hell it does
53
+ # * See what the hell a "Fooinator" does
54
+ # * Look at the fooinator#foo method to see what the hell THAT does
55
+ # * Look for all instances of @fooified_obj and see what the hell THOSE DO
56
+ #
57
+ # And even if they do all that, there's a chance they might miss something.
58
+ # If they do miss something, this will likely manifest itself in an error
59
+ # further up the stack, such as method missing exceptions etc., in places
60
+ # OTHER than where the actual mistake was made.
61
+ #
62
+ # Nightmare!
63
+ #
64
+ # Wouldn't it be nice if the "bar" method did a check or two, or even raised
65
+ # an exception when it was passed an object that wasn't compatible with its
66
+ # functionality? You could do this yourself manually:
67
+ #
68
+
69
+ class Foo
70
+ def self.bar(obj)
71
+ raise TypeError unless obj.respond_to?(:foo!) && obj.respond_to?(:chunky_bacon)
72
+
73
+ obj.foo!
74
+ fooinator = Test::Fooinator.new
75
+ @fooified_obj = fooinator.foo(obj)
76
+ end
77
+ end
78
+
79
+ #
80
+ # But now you've got more problems!
81
+ #
82
+ # * The method is now becoming longer and messier.
83
+ # * The "knowledge" about what :bar can receive is stored within the
84
+ # :bar method itself, but that knowledge may be needed elsewhere.
85
+ #
86
+ # Wouldn't it be nice if there was a neat way to store knowledge about all
87
+ # our ducks in one place, and to be able to reference them whenever we need to.
88
+ #
89
+ # Although duck typing is seen as a ruby technique, it is actually
90
+ # used in other languages too but the contract in strongly typed languages
91
+ # is made explicit through the use of interfaces. In c#, for example:
92
+ #
93
+ # public string foo(IMyInterface interface)
94
+ # {
95
+ # //your implementation here. A confused developer
96
+ # //could go off and look in IMyInterface to see what
97
+ # //this "duck" is meant to do.
98
+ # }
99
+ #
100
+ # As ruby is not strongly typed, you don't have this reference and the code
101
+ # becomes impossible for other developers to use!
102
+ #
103
+ # This is the problem duckpond hopes to solve.
104
+ #
105
+
106
+ class Reader
107
+ def intrigued?
108
+ true
109
+ end
110
+ end
111
+
112
+ the_reader = Reader.new
113
+ expect(the_reader).to be_intrigued
114
+
115
+ end
116
+ end
117
+ end
118
+ end
119
+
120
+
@@ -0,0 +1,102 @@
1
+ require "spec_helper"
2
+
3
+ module DuckPond
4
+ describe "The Solution" do
5
+ context 'when a method is called' do
6
+ it 'pays to use duckpond' do
7
+
8
+ #
9
+ # First, declare a duck.
10
+ #
11
+
12
+ class ObjDuck < DuckPond::Duck
13
+ quacks_like :to_s
14
+ quacks_like :length
15
+ end
16
+
17
+ #
18
+ # Grab a pair of binoculars...
19
+ #
20
+
21
+ binoculars = DuckPond::Binoculars.new
22
+
23
+ #
24
+ # Now, lets say you have an object...
25
+ #
26
+
27
+ obj = "Hello World"
28
+
29
+ #
30
+ # You can "spot" it with your binoculars...
31
+ #
32
+
33
+ sighting = binoculars.identify(obj)
34
+
35
+ #
36
+ # And now you can compare your sightings with your ducks!
37
+ #
38
+
39
+ result = sighting.quacks_like?(ObjDuck)
40
+ expect(result).to be true
41
+
42
+ #
43
+ # You could check all of this within a method:
44
+ #
45
+
46
+ binoculars = DuckPond::Binoculars.new
47
+ sighting = binoculars.identify(obj)
48
+ raise TypeError unless sighting.quacks_like?(ObjDuck)
49
+
50
+ #
51
+ # But because this trio of lines are so common, a
52
+ # convinience method exists to perform all three at
53
+ # once:
54
+ #
55
+
56
+ result = DuckPond::Binoculars.confirm(obj, ObjDuck)
57
+ expect(result).to be true
58
+
59
+ #
60
+ # The "bang" version will raise an error if the object isn't the duck.
61
+ #
62
+
63
+ expect { DuckPond::Binoculars.confirm!(Object.new, ObjDuck) }.to raise_error TypeError
64
+
65
+
66
+ #
67
+ # So, going back to that example from the problem_spec
68
+ #
69
+
70
+ class Foo
71
+ def self.bar(obj)
72
+ DuckPond::Binoculars.confirm!(obj,ObjDuck)
73
+
74
+ obj.foo!
75
+ fooinator = Test::Fooinator.new
76
+ @fooified_obj = fooinator.foo(obj)
77
+ end
78
+ end
79
+
80
+
81
+ #
82
+ # Viola!
83
+ #
84
+ # Final Tips:
85
+ #
86
+ # * Ducks should be commented liberally. They form the descripiton
87
+ # of a contract just as interfaces would in strongly typed languages.
88
+ # Developers will be prompted to consult the duck when they see a pair
89
+ # of binoculars in your code, so make sure they find what they're looking
90
+ # for.
91
+ #
92
+ # * Rather than writing the duckpond functionality directly within the methods
93
+ # themselves, you could easily put them in hooks or method aliases. If you do this
94
+ # though, remember that the point of this app is to make things *more* visible, not
95
+ # less, so don't go tucking these duck checks too far away from where they are needed
96
+ # or leave an obvious trail if you do!
97
+ #
98
+
99
+ end
100
+ end
101
+ end
102
+ end
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: duckpond
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Mikey Hogarth
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-06-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Explicit duck-typing for ruby
42
+ email:
43
+ - mikehogarth20@hotmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - .gitignore
49
+ - Gemfile
50
+ - Gemfile.lock
51
+ - LICENSE
52
+ - README.md
53
+ - Rakefile
54
+ - duckpond.gemspec
55
+ - lib/duckpond.rb
56
+ - lib/duckpond/binoculars.rb
57
+ - lib/duckpond/duck.rb
58
+ - lib/duckpond/sighting.rb
59
+ - lib/duckpond/version.rb
60
+ - spec/binoculars_spec.rb
61
+ - spec/classes/fooinator.rb
62
+ - spec/duck_spec.rb
63
+ - spec/sighting_spec.rb
64
+ - spec/spec_helper.rb
65
+ - spec/the_problem_spec.rb
66
+ - spec/the_solution_spec.rb
67
+ homepage: https://github.com/mikeyhogarth/duckpond
68
+ licenses:
69
+ - MIT
70
+ metadata: {}
71
+ post_install_message:
72
+ rdoc_options: []
73
+ require_paths:
74
+ - lib
75
+ required_ruby_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - '>='
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ requirements: []
86
+ rubyforge_project:
87
+ rubygems_version: 2.2.2
88
+ signing_key:
89
+ specification_version: 4
90
+ summary: Explicit duck-typing for ruby
91
+ test_files:
92
+ - spec/binoculars_spec.rb
93
+ - spec/classes/fooinator.rb
94
+ - spec/duck_spec.rb
95
+ - spec/sighting_spec.rb
96
+ - spec/spec_helper.rb
97
+ - spec/the_problem_spec.rb
98
+ - spec/the_solution_spec.rb