interjectable 0.0.2

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: 0af3542297a01bc7ee22e3285d3e8304696930db
4
+ data.tar.gz: 13b3b515d6091e5060929799e01bebda5247847c
5
+ SHA512:
6
+ metadata.gz: be91741b3702f14722f9553935f71ddc8429cc33e6e52d37807f105e6476e54943f79cc8af624e385859853cdfb59365c38e4b405cf20ed48c79c234daa2aca9
7
+ data.tar.gz: d3eb4089dcbe35bdb36a7ec801072f2ec125a60f38fdd1c8b0016063c434065ded77bdfd1bc811021cd69d75d8323885dbae928e0df9693d01ab01ecb946d407
data/.gitignore ADDED
@@ -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/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in injectable.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Zach Margolis
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.
data/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # Interjectable
2
+
3
+ Interjectable is a really simple Ruby library for dependency injection, designed to make unit testing easier.
4
+
5
+ ## Installation
6
+
7
+ It's a gem!
8
+
9
+ ```ruby
10
+ gem 'interjectable'
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ Interjectable has one module (`Interjectable`) and one method (`inject`). Use it like so!
16
+
17
+ ```ruby
18
+ class MyClass
19
+ extend Interjectable
20
+
21
+ inject(:dependency) { SomeOtherClass.new }
22
+ inject(:other_dependency) { AnotherClass.new }
23
+ end
24
+ ```
25
+
26
+ This replaces a pattern we've used before, adding default dependencies in the constructor, or as memoized methods.
27
+
28
+ ```ruby
29
+ # OLD WAY, see above
30
+ class MyClass
31
+ attr_accessor :dependency
32
+
33
+ def initialize(dependency=SomeOtherClass.new)
34
+ @dependency=dependency
35
+ end
36
+
37
+ def other_depency
38
+ @other_dependency ||= AnotherClass.new
39
+ end
40
+ end
41
+ ```
42
+
43
+ ## Dependency Injection + Unit Testing?
44
+
45
+ > Ok but what the heck is dependency injection and what does it have to do with unit tests?
46
+
47
+ So in the real world, objects depend on other objects: object A uses object B to parse a file. This is normal. But what about when you want to test object A independently from object B? Object B might depend on objects C, D, E and so on, so the test would become needlessly complex.
48
+
49
+ For the sake of testing object A, we can stub out object B with something fake. But for normal usage of object A, we want to actually use object B (and all its dependencies). We can accommodate both these use cases with dependency injection!
50
+
51
+ Let's check it out: we can build a class A that normally references B, but in our test we can safely replace B, and don't even have to require or load B at all!
52
+
53
+ ```ruby
54
+ # a.rb
55
+ class A
56
+ extend Interjectable
57
+
58
+ inject(:b) { B.new }
59
+
60
+ def read
61
+ b.parse
62
+ end
63
+ end
64
+
65
+ # a_spec.rb
66
+ require 'a'
67
+
68
+ describe A do
69
+ describe "#read" do
70
+ before do
71
+ a.b = double("FakeB", parse: 'result')
72
+ end
73
+
74
+ it "parses from its b" do
75
+ subject.read.should == 'result'
76
+ end
77
+ end
78
+ end
79
+ ```
80
+
81
+ > Great, why this library over any other?
82
+
83
+ Interjectable aims to provide clear defaults for easy debugging.
84
+
85
+ The other libraries we found used inject/provide setups. That setup is nice because files don't reference each other. However, this can become a headache to debug to actually figure out what is being used where. In our use cases, we use dependency injection for simplified testing, not for hands-free configuration.
data/Rakefile ADDED
@@ -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 'interjectable/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "interjectable"
8
+ spec.version = Interjectable::VERSION
9
+ spec.authors = ["Zach Margolis"]
10
+ spec.email = ["zbmargolis@gmail.com"]
11
+ spec.description = %q{A simple dependency injection library for unit testing}
12
+ spec.summary = %q{A simple dependency injection library for unit testing}
13
+ spec.homepage = "https://github.com/zachmargolis/interjectable"
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{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ end
@@ -0,0 +1,3 @@
1
+ module Interjectable
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,21 @@
1
+ require "interjectable/version"
2
+
3
+ module Interjectable
4
+ def self.extended(mod)
5
+ super
6
+ end
7
+
8
+ def inject(dependency, &default_block)
9
+ attr_writer dependency
10
+
11
+ define_method(dependency) do
12
+ # @dependency ||= instance_eval(&default_block)
13
+ ivar_name = "@#{dependency}"
14
+ if instance_variable_defined?(ivar_name)
15
+ instance_variable_get(ivar_name)
16
+ else
17
+ instance_variable_set(ivar_name, instance_eval(&default_block))
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ describe Interjectable do
4
+ context "when extended" do
5
+ let(:klass) { Class.new { extend Interjectable } }
6
+ let(:instance) { klass.new }
7
+
8
+ describe "#inject" do
9
+ before do
10
+ klass.inject(:some_dependency) { :service }
11
+ end
12
+
13
+ it "adds an instance method getter and setter" do
14
+ instance.some_dependency = 'aaa'
15
+ instance.some_dependency.should == 'aaa'
16
+ end
17
+
18
+ it "lazy-loads the default block" do
19
+ instance.instance_variable_get("@some_dependency").should be_nil
20
+ instance.some_dependency.should == :service
21
+ instance.instance_variable_get("@some_dependency").should_not be_nil
22
+ end
23
+
24
+ it "allows transitive dependencies (via instance_eval)" do
25
+ klass.inject(:first_dependency) { second_dependency }
26
+ klass.inject(:second_dependency) { :value }
27
+
28
+ instance.first_dependency.should == :value
29
+ end
30
+
31
+ it "calls dependency block once, even with a falsy value" do
32
+ klass.inject(:some_falsy_dependency) { @count += 1; nil }
33
+
34
+ instance.instance_variable_set("@count", 0)
35
+ 2.times { instance.some_falsy_dependency.should be_nil }
36
+ instance.instance_variable_get("@count").should == 1
37
+ end
38
+
39
+ context "with a dependency on another class" do
40
+ before do
41
+ defined?(SomeOtherClass).should be_false
42
+
43
+ klass.inject(:some_other_class) { SomeOtherClass.new }
44
+ end
45
+
46
+ it "does not need to load that class (can be stubbed away)" do
47
+ instance.some_other_class = :fake_other_class
48
+
49
+ instance.some_other_class.should == :fake_other_class
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,7 @@
1
+ require 'rspec'
2
+
3
+ $LOAD_PATH.unshift(
4
+ File.join(File.dirname(__FILE__), '..', 'lib', 'interjectable')
5
+ )
6
+
7
+ require 'interjectable'
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: interjectable
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Zach Margolis
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-03-17 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
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: A simple dependency injection library for unit testing
56
+ email:
57
+ - zbmargolis@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - .gitignore
63
+ - Gemfile
64
+ - LICENSE.txt
65
+ - README.md
66
+ - Rakefile
67
+ - interjectable.gemspec
68
+ - lib/interjectable.rb
69
+ - lib/interjectable/version.rb
70
+ - spec/interjectable_spec.rb
71
+ - spec/spec_helper.rb
72
+ homepage: https://github.com/zachmargolis/interjectable
73
+ licenses:
74
+ - MIT
75
+ metadata: {}
76
+ post_install_message:
77
+ rdoc_options: []
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ requirements: []
91
+ rubyforge_project:
92
+ rubygems_version: 2.2.2
93
+ signing_key:
94
+ specification_version: 4
95
+ summary: A simple dependency injection library for unit testing
96
+ test_files:
97
+ - spec/interjectable_spec.rb
98
+ - spec/spec_helper.rb