inject 0.0.1
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.
- 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
|