codeine 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/LICENSE +8 -0
- data/Rakefile +1 -0
- data/codeine.gemspec +22 -0
- data/examples/flexible.rb +32 -0
- data/examples/simple.rb +26 -0
- data/lib/codeine.rb +59 -0
- data/lib/codeine/containable.rb +8 -0
- data/lib/codeine/container.rb +33 -0
- data/lib/codeine/injectable.rb +22 -0
- data/lib/codeine/version.rb +3 -0
- data/readme.markdown +46 -0
- data/spec/.rspec +2 -0
- data/spec/containable_spec.rb +31 -0
- data/spec/container_spec.rb +55 -0
- data/spec/injectable_spec.rb +31 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/utility_spec.rb +48 -0
- metadata +75 -0
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
Copyright (c) 2011 Tim Ariyeh
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
8
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/codeine.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "codeine/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "codeine"
|
7
|
+
s.version = Codeine::VERSION
|
8
|
+
s.authors = ["Tim Ariyeh"]
|
9
|
+
s.email = ["tim.ariyeh@gmail.com"]
|
10
|
+
s.homepage = "https://github.com/timariyeh/codeine"
|
11
|
+
s.summary = %q{A simple Ruby dependency injector}
|
12
|
+
s.description = %q{A really simple, partitionable, ruby-flavored dependency injector}
|
13
|
+
|
14
|
+
s.rubyforge_project = "codeine"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_development_dependency "rspec"
|
22
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
$LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
|
2
|
+
require 'codeine'
|
3
|
+
|
4
|
+
|
5
|
+
module FooModule
|
6
|
+
class A
|
7
|
+
codeine_inject :logger
|
8
|
+
def initialize
|
9
|
+
puts logger.inspect
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module BarModule
|
15
|
+
class A
|
16
|
+
codeine_inject :logger
|
17
|
+
def initialize
|
18
|
+
puts logger.inspect
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
container_foo = Codeine.container_for(FooModule)
|
25
|
+
container_foo.register(:logger){"the fancy logger for FooModule"}
|
26
|
+
|
27
|
+
container_bar = Codeine.container_for(BarModule)
|
28
|
+
container_bar.register(:logger){"the simple logger for BarModule"}
|
29
|
+
|
30
|
+
|
31
|
+
FooModule::A.new
|
32
|
+
BarModule::A.new
|
data/examples/simple.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
$LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
|
2
|
+
require 'codeine'
|
3
|
+
|
4
|
+
Codeine.activate
|
5
|
+
Codeine.register(:logger){"some logger"}
|
6
|
+
|
7
|
+
module FooModule
|
8
|
+
class A
|
9
|
+
codeine_inject :logger
|
10
|
+
def initialize
|
11
|
+
puts logger.inspect
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module BarModule
|
17
|
+
class A
|
18
|
+
codeine_inject :logger
|
19
|
+
def initialize
|
20
|
+
puts logger.inspect
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
FooModule::A.new
|
26
|
+
BarModule::A.new
|
data/lib/codeine.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require "codeine/version"
|
2
|
+
require "codeine/container"
|
3
|
+
require "codeine/injectable"
|
4
|
+
require "codeine/containable"
|
5
|
+
|
6
|
+
module Codeine
|
7
|
+
class << self
|
8
|
+
|
9
|
+
#automatically called later in this file
|
10
|
+
def activate()
|
11
|
+
Module.send(:include, Codeine::Containable)
|
12
|
+
Class.send(:include, Codeine::Injectable)
|
13
|
+
end
|
14
|
+
|
15
|
+
def container_for(mod)
|
16
|
+
mod.codeine_container ||= Container.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def default_container
|
20
|
+
@default_container ||= Container.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def register(service, &block)
|
24
|
+
default_container.register(service, &block)
|
25
|
+
end
|
26
|
+
|
27
|
+
def get(service)
|
28
|
+
default_container.get(service)
|
29
|
+
end
|
30
|
+
alias :[] :get
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
module Utility
|
35
|
+
class << self
|
36
|
+
def constant_path(constant)
|
37
|
+
constants = []
|
38
|
+
parts = constant.to_s.split("::")
|
39
|
+
parts.count.times do |i|
|
40
|
+
constants << parts[0..i].inject(Kernel) do |memo, obj|
|
41
|
+
memo.const_get(obj)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
constants
|
45
|
+
end
|
46
|
+
|
47
|
+
def nearest_container(constant)
|
48
|
+
container = nil
|
49
|
+
constant_path(constant).reverse.each do |c|
|
50
|
+
next unless c.respond_to? :codeine_container
|
51
|
+
break if container = c.codeine_container
|
52
|
+
end
|
53
|
+
container || ::Codeine.default_container
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
Codeine.activate
|
@@ -0,0 +1,33 @@
|
|
1
|
+
|
2
|
+
module Codeine
|
3
|
+
class Container
|
4
|
+
|
5
|
+
def services
|
6
|
+
@services ||= {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def filters
|
10
|
+
@filters ||= []
|
11
|
+
end
|
12
|
+
|
13
|
+
def register(key, &block)
|
14
|
+
services[key.to_sym] = block
|
15
|
+
end
|
16
|
+
|
17
|
+
def get(key)
|
18
|
+
key = key.to_sym
|
19
|
+
service = services[key].call
|
20
|
+
filters.each do |f|
|
21
|
+
if key.to_s =~ f[:pattern]
|
22
|
+
f[:block].call(key, service)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
service
|
26
|
+
end
|
27
|
+
alias :[] :get
|
28
|
+
|
29
|
+
def filter(pattern, &block)
|
30
|
+
filters.push :pattern => pattern, :block => block
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
|
2
|
+
module Codeine
|
3
|
+
module Injectable
|
4
|
+
|
5
|
+
def nearest_codeine_container
|
6
|
+
Codeine::Utility.nearest_container(self)
|
7
|
+
end
|
8
|
+
|
9
|
+
def codeine_inject(service, method_name = nil)
|
10
|
+
method_name = method_name || service
|
11
|
+
define_method(method_name.to_sym) do
|
12
|
+
cache = instance_variable_get("@codeine_#{service}")
|
13
|
+
unless cache
|
14
|
+
cache = self.class.nearest_codeine_container[service.to_sym]
|
15
|
+
instance_variable_set("@codeine_#{service}", cache)
|
16
|
+
end
|
17
|
+
cache
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
data/readme.markdown
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
Codeine
|
2
|
+
=======
|
3
|
+
|
4
|
+
A simple dependency injector for ruby projects.
|
5
|
+
|
6
|
+
Despite how flexible ruby is, and despite the insistence of a large part of the community, I frequently run into the need on larger projects to centrally manage my dependencies. I end up building something like Codeine for each one, so I decided to build it one more time and re-use it.
|
7
|
+
|
8
|
+
Usage
|
9
|
+
-----
|
10
|
+
|
11
|
+
Codeine can operate as either a global or module-local dependency container. Using it globally is the least flexible, but presents the simplest syntax.
|
12
|
+
|
13
|
+
require 'codeine'
|
14
|
+
Codeine.register(:logger){Logger.new}
|
15
|
+
|
16
|
+
class Foo
|
17
|
+
codeine_inject :logger
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
logger.log "Initialized..."
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
For library code, and for larger projects, it's probably a better idea to segregate the containers.
|
26
|
+
|
27
|
+
require 'codeine'
|
28
|
+
|
29
|
+
|
30
|
+
module ProjectA
|
31
|
+
class Foo
|
32
|
+
codeine_inject :logger
|
33
|
+
|
34
|
+
def initialize
|
35
|
+
logger.log "Initialized..."
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
container = Codeine.container_for(ProjectA)
|
41
|
+
container.register(:logger){Logger.new}
|
42
|
+
|
43
|
+
foo = ProjectA::Foo.new
|
44
|
+
|
45
|
+
|
46
|
+
The the container bound to the ProjectA module will only service injection requests from classes/modules that reside within it
|
data/spec/.rspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require_relative "spec_helper"
|
2
|
+
require 'codeine'
|
3
|
+
|
4
|
+
|
5
|
+
describe Codeine::Containable do
|
6
|
+
before(:each) do
|
7
|
+
module Foo
|
8
|
+
class Bar
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should create getter/setter" do
|
14
|
+
Foo.send(:extend, Codeine::Containable)
|
15
|
+
Foo.should respond_to :codeine_container
|
16
|
+
Foo.should respond_to :codeine_container=
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should store container at the instance level" do
|
20
|
+
Foo.send(:extend, Codeine::Containable)
|
21
|
+
Foo::Bar.send(:extend, Codeine::Containable)
|
22
|
+
|
23
|
+
Foo.codeine_container = "foo_container"
|
24
|
+
Foo::Bar.codeine_container = "bar_container"
|
25
|
+
|
26
|
+
Foo.codeine_container.should == "foo_container"
|
27
|
+
Foo::Bar.codeine_container.should == "bar_container"
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
|
2
|
+
require_relative "spec_helper"
|
3
|
+
require 'codeine'
|
4
|
+
|
5
|
+
describe Codeine::Container do
|
6
|
+
let(:container){Codeine::Container.new}
|
7
|
+
|
8
|
+
describe "#register" do
|
9
|
+
it "should accept a block and register it as a service" do
|
10
|
+
hash = Hash.new
|
11
|
+
container.register(:foo){hash}
|
12
|
+
|
13
|
+
container.services[:foo].call.should == hash
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#get" do
|
18
|
+
it "should execute the block registered at the given key" do
|
19
|
+
hash = Hash.new
|
20
|
+
container.register(:foo){hash}
|
21
|
+
|
22
|
+
container.get(:foo).should == hash
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should be aliased to []" do
|
26
|
+
hash = Hash.new
|
27
|
+
container.register(:foo){hash}
|
28
|
+
|
29
|
+
container[:foo].should == hash
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#filter" do
|
34
|
+
it "should fire the given block when a key matches the given filter" do
|
35
|
+
hash = Hash.new
|
36
|
+
container.register(:foo){hash}
|
37
|
+
container.filter(/^foo/){|key, service|
|
38
|
+
service[:bar] = "baz"
|
39
|
+
}
|
40
|
+
service = container.get(:foo)
|
41
|
+
service[:bar].should == "baz"
|
42
|
+
end
|
43
|
+
|
44
|
+
it "shouldn't fire the given block when a key doesn't match the given filter" do
|
45
|
+
hash = Hash.new
|
46
|
+
container.register(:foo){hash}
|
47
|
+
container.filter(/^bar/){|key, service|
|
48
|
+
service[:bar] = "baz"
|
49
|
+
}
|
50
|
+
service = container.get(:foo)
|
51
|
+
service[:bar].should_not == "baz"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
require_relative "spec_helper"
|
3
|
+
require 'codeine'
|
4
|
+
|
5
|
+
|
6
|
+
describe Codeine::Injectable do
|
7
|
+
before(:each) do
|
8
|
+
module Foo
|
9
|
+
class Bar
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "dynamic methods" do
|
15
|
+
it "should create a module-level inject_service method" do
|
16
|
+
Foo::Bar.should_not respond_to(:inject_service)
|
17
|
+
Foo::Bar.send(:extend, Codeine::Injectable)
|
18
|
+
Foo::Bar.should respond_to(:codeine_inject)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should create a service getter for injected services" do
|
22
|
+
Foo::Bar.send(:extend, Codeine::Injectable)
|
23
|
+
Foo::Bar.send(:extend, Codeine::Containable)
|
24
|
+
Foo::Bar.codeine_container = {:bat => "man"}
|
25
|
+
Foo::Bar.codeine_inject(:bat)
|
26
|
+
bar = Foo::Bar.new
|
27
|
+
bar.bat.should == "man"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require_relative "spec_helper"
|
2
|
+
require 'codeine'
|
3
|
+
|
4
|
+
|
5
|
+
describe Codeine::Utility do
|
6
|
+
before(:each) do
|
7
|
+
module Foo
|
8
|
+
module Bar
|
9
|
+
class Baz
|
10
|
+
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "constant_path" do
|
17
|
+
it "should return an array of constant values" do
|
18
|
+
path = Codeine::Utility.constant_path("Foo")
|
19
|
+
path[0].should == Foo
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should return constant path in heirarchial order" do
|
23
|
+
path = Codeine::Utility.constant_path(Foo::Bar::Baz)
|
24
|
+
path.should == [Foo, Foo::Bar, Foo::Bar::Baz]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "nearest_container" do
|
29
|
+
|
30
|
+
it "should look up the constant heirarchy for a container" do
|
31
|
+
Foo.send(:extend, Codeine::Injectable)
|
32
|
+
Foo.send(:extend, Codeine::Containable)
|
33
|
+
Foo::Bar.send(:extend, Codeine::Injectable)
|
34
|
+
Foo.codeine_container = "foo_container"
|
35
|
+
Foo::Bar.nearest_codeine_container.should == "foo_container"
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should not look down the constant heirarchy for a container" do
|
39
|
+
Foo.send(:extend, Codeine::Injectable)
|
40
|
+
Foo.send(:extend, Codeine::Containable)
|
41
|
+
Foo::Bar.send(:extend, Codeine::Injectable)
|
42
|
+
Foo::Bar.send(:extend, Codeine::Containable)
|
43
|
+
|
44
|
+
Foo::Bar.codeine_container = "bar_container"
|
45
|
+
Foo.nearest_codeine_container.should_not == "bar_container"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: codeine
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Tim Ariyeh
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-10-08 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: &13428680 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *13428680
|
25
|
+
description: A really simple, partitionable, ruby-flavored dependency injector
|
26
|
+
email:
|
27
|
+
- tim.ariyeh@gmail.com
|
28
|
+
executables: []
|
29
|
+
extensions: []
|
30
|
+
extra_rdoc_files: []
|
31
|
+
files:
|
32
|
+
- .gitignore
|
33
|
+
- Gemfile
|
34
|
+
- LICENSE
|
35
|
+
- Rakefile
|
36
|
+
- codeine.gemspec
|
37
|
+
- examples/flexible.rb
|
38
|
+
- examples/simple.rb
|
39
|
+
- lib/codeine.rb
|
40
|
+
- lib/codeine/containable.rb
|
41
|
+
- lib/codeine/container.rb
|
42
|
+
- lib/codeine/injectable.rb
|
43
|
+
- lib/codeine/version.rb
|
44
|
+
- readme.markdown
|
45
|
+
- spec/.rspec
|
46
|
+
- spec/containable_spec.rb
|
47
|
+
- spec/container_spec.rb
|
48
|
+
- spec/injectable_spec.rb
|
49
|
+
- spec/spec_helper.rb
|
50
|
+
- spec/utility_spec.rb
|
51
|
+
homepage: https://github.com/timariyeh/codeine
|
52
|
+
licenses: []
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options: []
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
requirements: []
|
70
|
+
rubyforge_project: codeine
|
71
|
+
rubygems_version: 1.8.6
|
72
|
+
signing_key:
|
73
|
+
specification_version: 3
|
74
|
+
summary: A simple Ruby dependency injector
|
75
|
+
test_files: []
|