inject 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +2 -0
- data/LICENSE +20 -0
- data/README.md +32 -0
- data/Rakefile +38 -0
- data/inject.gemspec +18 -0
- data/lib/inject.rb +66 -0
- data/test/injection.rb +39 -0
- data/test/readme_example.rb +24 -0
- data/test/sources.rb +70 -0
- metadata +69 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Arun Srinivasan
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# Inject
|
2
|
+
|
3
|
+
Inject arguments into methods, by name.
|
4
|
+
|
5
|
+
Inspired by ideas from Raptor and Objectify. Figured something
|
6
|
+
like this might be useful on its own.
|
7
|
+
|
8
|
+
# Example
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
class InsultParams
|
12
|
+
def target
|
13
|
+
"Arthur Philip Dent"
|
14
|
+
end
|
15
|
+
|
16
|
+
def insult
|
17
|
+
"You're a jerk, Dent... a complete kneebiter."
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Wowbagger
|
22
|
+
def self.vilify(target, insult)
|
23
|
+
[target, insult].join(": ")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
injector = Inject::Injector.new(InsultParams.new)
|
28
|
+
|
29
|
+
injector.call(Wowbagger, :vilify)
|
30
|
+
# => "Arthur Philip Dent: You're a jerk, Dent... a complete kneebiter."
|
31
|
+
```
|
32
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
$:.push("lib")
|
2
|
+
require "inject"
|
3
|
+
require "tst"
|
4
|
+
|
5
|
+
name = "inject"
|
6
|
+
version = Inject::VERSION
|
7
|
+
|
8
|
+
desc "Run the tests"
|
9
|
+
task :test do
|
10
|
+
Tst.run "test/*.rb",
|
11
|
+
:load_paths => ["lib"],
|
12
|
+
:reporter => Tst::Reporters::Pretty.new
|
13
|
+
end
|
14
|
+
|
15
|
+
namespace :gem do
|
16
|
+
desc 'Clean up generated files'
|
17
|
+
task :clean do
|
18
|
+
sh 'rm -rf pkg'
|
19
|
+
end
|
20
|
+
|
21
|
+
desc "Build the gem"
|
22
|
+
task :build => :clean do
|
23
|
+
sh "mkdir pkg"
|
24
|
+
sh "gem build #{name}.gemspec"
|
25
|
+
sh "mv #{name}-#{version}.gem pkg/"
|
26
|
+
end
|
27
|
+
|
28
|
+
desc "Release v#{version}"
|
29
|
+
task :release => :build do
|
30
|
+
sh "git commit --allow-empty -a -m 'Release #{version}'"
|
31
|
+
sh "git tag v#{version}"
|
32
|
+
sh "git push origin master"
|
33
|
+
sh "git push origin v#{version}"
|
34
|
+
sh "gem push pkg/#{name}-#{version}.gem"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
task :default => :test
|
data/inject.gemspec
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require './lib/inject'
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = "inject"
|
5
|
+
s.version = Inject::VERSION
|
6
|
+
s.summary = "Inject arguments into methods. By name."
|
7
|
+
s.description = "Inject arguments into methods. By name."
|
8
|
+
|
9
|
+
s.authors = ["Arun Srinivasan"]
|
10
|
+
s.email = ["satchmorun@gmail.com"]
|
11
|
+
s.homepage = "http://github.com/satchmorun/inject"
|
12
|
+
|
13
|
+
s.files = `git ls-files`.split("\n")
|
14
|
+
s.test_files = `git ls-files -- test/*`.split("\n")
|
15
|
+
|
16
|
+
s.add_development_dependency "tst"
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
end
|
data/lib/inject.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
module Inject
|
2
|
+
VERSION = "0.0.1"
|
3
|
+
|
4
|
+
class UnknownArg < ArgumentError; end
|
5
|
+
class Conflict < NameError; end
|
6
|
+
|
7
|
+
class Injector
|
8
|
+
NULL_SOURCE = Proc.new {}
|
9
|
+
|
10
|
+
attr_reader :known
|
11
|
+
|
12
|
+
def initialize(*sources)
|
13
|
+
@known = {}
|
14
|
+
sources.each { |source| add_source(source) }
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(target, name)
|
18
|
+
method = target.method(name)
|
19
|
+
args = resolve(method.parameters)
|
20
|
+
method.call(*args)
|
21
|
+
end
|
22
|
+
|
23
|
+
def add_source(source)
|
24
|
+
extract_injections(source).each do |name|
|
25
|
+
prevent_collisions(name)
|
26
|
+
known[name] = source.method(name)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def extract_injections(source)
|
31
|
+
if source.respond_to?(:injections)
|
32
|
+
source.injections
|
33
|
+
else
|
34
|
+
source.class.instance_methods(false)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def resolve(parameters)
|
39
|
+
parameters.map do |type, name|
|
40
|
+
fetch(type, name).call unless ignore?(type)
|
41
|
+
end.compact
|
42
|
+
end
|
43
|
+
|
44
|
+
def ignore?(type)
|
45
|
+
@ignored_types ||= [:block, :rest]
|
46
|
+
@ignored_types.include?(type)
|
47
|
+
end
|
48
|
+
|
49
|
+
def fetch(type, name)
|
50
|
+
known.fetch(name) do |key|
|
51
|
+
prevent_unkown_required_args(type, name)
|
52
|
+
NULL_SOURCE
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def prevent_unkown_required_args(type, name)
|
57
|
+
return unless type == :req
|
58
|
+
raise UnknownArg.new("Don't know how to inject :#{name}")
|
59
|
+
end
|
60
|
+
|
61
|
+
def prevent_collisions(name)
|
62
|
+
return unless known.key?(name)
|
63
|
+
raise Conflict.new("The :#{name} method is defined more than once.")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
data/test/injection.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'inject'
|
2
|
+
|
3
|
+
class Source
|
4
|
+
def answer; 42 end
|
5
|
+
def injections; [:answer] end
|
6
|
+
end
|
7
|
+
|
8
|
+
class Target
|
9
|
+
def none; 'no args' end
|
10
|
+
def opt(unknown = 'unknown opt arg') unknown end
|
11
|
+
def known_opt(answer = nil) answer end
|
12
|
+
def req(answer) answer end
|
13
|
+
def block(&b) b end
|
14
|
+
def unknown(unknown_arg) 'should never get here' end
|
15
|
+
def rest(*answer) answer end
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_injection(method, options={})
|
19
|
+
tst "calling #{method}" do
|
20
|
+
source = Source.new
|
21
|
+
target = Target.new
|
22
|
+
injector = Inject::Injector.new(source)
|
23
|
+
|
24
|
+
if options[:raises]
|
25
|
+
assert_raises options[:raises] { injector.call(target, method) }
|
26
|
+
else
|
27
|
+
result = injector.call(target, method)
|
28
|
+
assert_equal options[:expected], result
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
test_injection :none , :expected => 'no args'
|
34
|
+
test_injection :opt , :expected => 'unknown opt arg'
|
35
|
+
test_injection :known_opt , :expected => 42
|
36
|
+
test_injection :req , :expected => 42
|
37
|
+
test_injection :block , :expected => nil
|
38
|
+
test_injection :unknown , :raises => Inject::UnknownArg
|
39
|
+
test_injection :rest , :expected => []
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'inject'
|
2
|
+
|
3
|
+
class InsultParams
|
4
|
+
def target
|
5
|
+
"Arthur Philip Dent"
|
6
|
+
end
|
7
|
+
|
8
|
+
def insult
|
9
|
+
"You're a jerk, Dent... a complete kneebiter."
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Wowbagger
|
14
|
+
def self.vilify(target, insult)
|
15
|
+
[target, insult].join(": ")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
tst "Wowbagger" do
|
20
|
+
injector = Inject::Injector.new(InsultParams.new)
|
21
|
+
expected = "Arthur Philip Dent: You're a jerk, Dent... a complete kneebiter."
|
22
|
+
actual = injector.call(Wowbagger, :vilify)
|
23
|
+
assert_equal expected, actual
|
24
|
+
end
|
data/test/sources.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'inject'
|
2
|
+
|
3
|
+
class SourceA; def a; 'a' end end
|
4
|
+
class SourceB; def b; 'b' end end
|
5
|
+
class Conflict; def b; 'conflict' end end
|
6
|
+
class APrime < SourceA;
|
7
|
+
def c; 'c' end
|
8
|
+
def injections; [:a, :c] end
|
9
|
+
end
|
10
|
+
|
11
|
+
class Target
|
12
|
+
def self.a(a); a end
|
13
|
+
def self.b(b); b end
|
14
|
+
def self.c(c); c end
|
15
|
+
end
|
16
|
+
|
17
|
+
tst "Injector.new with no sources" do
|
18
|
+
Inject::Injector.new
|
19
|
+
end
|
20
|
+
|
21
|
+
tst "Injector.new with one source" do
|
22
|
+
source = SourceA.new
|
23
|
+
injector = Inject::Injector.new(source)
|
24
|
+
|
25
|
+
assert_equal 'a', injector.call(Target, :a)
|
26
|
+
end
|
27
|
+
|
28
|
+
tst "Injector.new with more than one sources" do
|
29
|
+
sources = [SourceA.new, SourceB.new]
|
30
|
+
injector = Inject::Injector.new(*sources)
|
31
|
+
|
32
|
+
# Now we have access to injections from both
|
33
|
+
# SourceA and SourceB
|
34
|
+
assert_equal 'a', injector.call(Target, :a)
|
35
|
+
assert_equal 'b', injector.call(Target, :b)
|
36
|
+
end
|
37
|
+
|
38
|
+
tst "Injector.new detects name collisions" do
|
39
|
+
conflict = assert_raises do
|
40
|
+
sources = [SourceA.new, SourceB.new, Conflict.new]
|
41
|
+
Inject::Injector.new(*sources)
|
42
|
+
end
|
43
|
+
|
44
|
+
assert_equal Inject::Conflict, conflict.class
|
45
|
+
assert_equal "The :b method is defined more than once.", conflict.message
|
46
|
+
end
|
47
|
+
|
48
|
+
tst "Injector#add_source detects name collisions" do
|
49
|
+
injector = Inject::Injector.new(SourceB.new)
|
50
|
+
conflict = assert_raises { injector.add_source(Conflict.new) }
|
51
|
+
|
52
|
+
assert_equal Inject::Conflict, conflict.class
|
53
|
+
assert_equal "The :b method is defined more than once.", conflict.message
|
54
|
+
end
|
55
|
+
|
56
|
+
tst "sources can declare their injections" do
|
57
|
+
class APrime < SourceA;
|
58
|
+
def c; 'c' end
|
59
|
+
def injections; [:a, :c] end
|
60
|
+
end
|
61
|
+
|
62
|
+
source = APrime.new
|
63
|
+
injector = Inject::Injector.new(source)
|
64
|
+
|
65
|
+
# Inherited methods won't be auto-discovered, so
|
66
|
+
# we check that both :a and :c do the right thing.
|
67
|
+
# :a - inherited, :c - not inherited.
|
68
|
+
assert_equal 'a', injector.call(Target, :a)
|
69
|
+
assert_equal 'c', injector.call(Target, :c)
|
70
|
+
end
|
metadata
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: inject
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Arun Srinivasan
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-08-28 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: tst
|
16
|
+
requirement: &70264599879080 !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: *70264599879080
|
25
|
+
description: Inject arguments into methods. By name.
|
26
|
+
email:
|
27
|
+
- satchmorun@gmail.com
|
28
|
+
executables: []
|
29
|
+
extensions: []
|
30
|
+
extra_rdoc_files: []
|
31
|
+
files:
|
32
|
+
- .gitignore
|
33
|
+
- Gemfile
|
34
|
+
- LICENSE
|
35
|
+
- README.md
|
36
|
+
- Rakefile
|
37
|
+
- inject.gemspec
|
38
|
+
- lib/inject.rb
|
39
|
+
- test/injection.rb
|
40
|
+
- test/readme_example.rb
|
41
|
+
- test/sources.rb
|
42
|
+
homepage: http://github.com/satchmorun/inject
|
43
|
+
licenses: []
|
44
|
+
post_install_message:
|
45
|
+
rdoc_options: []
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ! '>='
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
requirements: []
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 1.8.10
|
63
|
+
signing_key:
|
64
|
+
specification_version: 3
|
65
|
+
summary: Inject arguments into methods. By name.
|
66
|
+
test_files:
|
67
|
+
- test/injection.rb
|
68
|
+
- test/readme_example.rb
|
69
|
+
- test/sources.rb
|