objectify 0.0.3 → 0.0.5
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/.document +5 -0
- data/.gitignore +47 -2
- data/.rspec +1 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +105 -16
- data/LICENSE.txt +20 -0
- data/README.md +230 -0
- data/Rakefile +14 -7
- data/lib/objectify.rb +1 -26
- data/lib/objectify/config/action.rb +31 -0
- data/lib/objectify/config/context.rb +97 -0
- data/lib/objectify/config/policies.rb +18 -0
- data/lib/objectify/executor.rb +21 -0
- data/lib/objectify/injector.rb +39 -0
- data/lib/objectify/instantiator.rb +14 -0
- data/lib/objectify/instrumentation.rb +12 -0
- data/lib/objectify/logging.rb +22 -0
- data/lib/objectify/policy_chain_executor.rb +27 -0
- data/lib/objectify/rails/application.rb +16 -0
- data/lib/objectify/rails/controller.rb +117 -0
- data/lib/objectify/rails/helpers.rb +14 -0
- data/lib/objectify/rails/log_subscriber.rb +59 -0
- data/lib/objectify/rails/railtie.rb +11 -0
- data/lib/objectify/rails/renderer.rb +47 -0
- data/lib/objectify/rails/routing.rb +97 -0
- data/lib/objectify/resolver.rb +27 -0
- data/lib/objectify/resolver_locator.rb +73 -0
- data/lib/objectify/route.rb +4 -0
- data/lib/objectify/version.rb +1 -1
- data/objectify.gemspec +13 -8
- data/spec/config/action_spec.rb +79 -0
- data/spec/config/context_spec.rb +137 -0
- data/spec/config/policies_spec.rb +23 -0
- data/spec/executor_spec.rb +47 -0
- data/spec/injector_spec.rb +88 -0
- data/spec/instantiator_spec.rb +22 -0
- data/spec/policy_chain_executor_spec.rb +60 -0
- data/spec/rails/renderer_spec.rb +63 -0
- data/spec/rails/routing_spec.rb +171 -0
- data/spec/resolver_locator_spec.rb +109 -0
- data/spec/resolver_spec.rb +28 -0
- data/spec/route_spec.rb +11 -0
- data/spec/spec_helper.rb +13 -5
- metadata +142 -62
- data/spec/objectify_spec.rb +0 -60
@@ -0,0 +1,137 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "objectify/config/context"
|
3
|
+
|
4
|
+
describe "Objectify::Config::Context" do
|
5
|
+
before do
|
6
|
+
@policies = stub("Policies")
|
7
|
+
@policies_factory = stub("PoliciesFactory", :new => @policies)
|
8
|
+
|
9
|
+
@context = Objectify::Config::Context.new(@policies_factory)
|
10
|
+
end
|
11
|
+
|
12
|
+
context "appending policy responders" do
|
13
|
+
before do
|
14
|
+
@context.append_policy_responders :authenticated => :unauthenticated
|
15
|
+
@context.append_policy_responders :blocked_profile => :unauthorized
|
16
|
+
end
|
17
|
+
|
18
|
+
it "is cumulative" do
|
19
|
+
responders = {:authenticated => :unauthenticated,
|
20
|
+
:blocked_profile => :unauthorized}
|
21
|
+
@context.policy_responders.should == responders
|
22
|
+
end
|
23
|
+
|
24
|
+
it "retrieves responders by policy name" do
|
25
|
+
@context.policy_responder(:authenticated).should == :unauthenticated
|
26
|
+
end
|
27
|
+
|
28
|
+
it "raises an error when a responder is missing" do
|
29
|
+
f = lambda { @context.policy_responder(:missing) }
|
30
|
+
f.should raise_error
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "setting defaults" do
|
35
|
+
before do
|
36
|
+
@opts = {:policies => [:a, :b], :skip_policies => :c}
|
37
|
+
@context.append_defaults @opts
|
38
|
+
end
|
39
|
+
|
40
|
+
it "uses the policies factory to create and store policies" do
|
41
|
+
@policies_factory.should have_received(:new).with(@opts)
|
42
|
+
@context.policies.should == @policies
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context "appending actions" do
|
47
|
+
before do
|
48
|
+
@route = stub("Route")
|
49
|
+
@action = stub("Action", :route => @route)
|
50
|
+
@context.append_action(@action)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "retrieves actions by route" do
|
54
|
+
@context.action(@route).should == @action
|
55
|
+
end
|
56
|
+
|
57
|
+
it "raises an error when no action for a route exists" do
|
58
|
+
lambda { @context.action(stub()) }.should raise_error
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "when there are no default policies" do
|
63
|
+
before do
|
64
|
+
@context = Objectify::Config::Context.new
|
65
|
+
end
|
66
|
+
|
67
|
+
it "returns an empty policies objectify" do
|
68
|
+
@context.policies.policies.should be_empty
|
69
|
+
@context.policies.skip_policies.should be_empty
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context "appending resolutions" do
|
74
|
+
before do
|
75
|
+
@locator = stub("ResolverLocator", :add => nil)
|
76
|
+
@context = Objectify::Config::Context.new(nil)
|
77
|
+
@context.locator = @locator
|
78
|
+
@context.append_resolutions :something => String.new
|
79
|
+
end
|
80
|
+
|
81
|
+
it "adds them to a locator it has" do
|
82
|
+
@locator.should have_received(:add).with(:something, String.new)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context "the legacy_action" do
|
87
|
+
before do
|
88
|
+
@action = stub("Action")
|
89
|
+
@action_factory = stub("ActionFactory", :new => @action)
|
90
|
+
@policies = stub("Policies")
|
91
|
+
@policies_factory = stub("PoliciesFactory", :new => @policies)
|
92
|
+
@route = stub("Route", :resource => :controller, :action => :action)
|
93
|
+
|
94
|
+
@context = Objectify::Config::Context.new(@policies_factory, @action_factory)
|
95
|
+
end
|
96
|
+
|
97
|
+
context "when there's no legacy action config" do
|
98
|
+
before do
|
99
|
+
@result = @context.legacy_action(@route)
|
100
|
+
end
|
101
|
+
|
102
|
+
it "creates a new action with the controller and action name and its policies" do
|
103
|
+
@action_factory.should have_received(:new).
|
104
|
+
with(:controller, :action, {}, @policies)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
context "when there is a legacy action config" do
|
109
|
+
before do
|
110
|
+
@action = stub("Action", :route => @route)
|
111
|
+
@context.append_action(@action)
|
112
|
+
@result = @context.legacy_action(@route)
|
113
|
+
end
|
114
|
+
|
115
|
+
it "returns the existing action" do
|
116
|
+
@result.should == @action
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context "objectify_controller" do
|
122
|
+
it "defaults to objectify/rails/objectify" do
|
123
|
+
@context.objectify_controller.should == "objectify/rails/objectify"
|
124
|
+
end
|
125
|
+
|
126
|
+
it "is overridable" do
|
127
|
+
@context.objectify_controller = "asdf"
|
128
|
+
@context.objectify_controller.should == "asdf"
|
129
|
+
end
|
130
|
+
|
131
|
+
it "isn't affected by reloading" do
|
132
|
+
@context.objectify_controller = "asdf"
|
133
|
+
@context.reload
|
134
|
+
@context.objectify_controller.should == "asdf"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "objectify/config/policies"
|
3
|
+
|
4
|
+
describe "Objectify::Config::Policies" do
|
5
|
+
before do
|
6
|
+
@opts = {:policies => [:a, :b, :c], :skip_policies => :b}
|
7
|
+
@policies = Objectify::Config::Policies.new(@opts)
|
8
|
+
@policies2 = Objectify::Config::Policies.new(:skip_policies => :c)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "extracts the policies from the options" do
|
12
|
+
@policies.policies.should == [:a, :b, :c]
|
13
|
+
end
|
14
|
+
|
15
|
+
it "extracts the skip policies from the options" do
|
16
|
+
@policies.skip_policies.should == [:b]
|
17
|
+
end
|
18
|
+
|
19
|
+
it "can merge with hashes of policy configs (ignoring nils)" do
|
20
|
+
@policies.merge({:skip_policies => :c},
|
21
|
+
{:policies => :b}, nil).should == [:a, :b]
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "objectify/executor"
|
3
|
+
|
4
|
+
describe "Objectify::Executor" do
|
5
|
+
before do
|
6
|
+
@instance = stub("Instance")
|
7
|
+
@instantiator = stub("Instantiator", :call => @instance)
|
8
|
+
@injector = stub("Injector", :call => true)
|
9
|
+
@executor = Objectify::Executor.new(@injector, @instantiator)
|
10
|
+
end
|
11
|
+
|
12
|
+
context "with a service" do
|
13
|
+
before do
|
14
|
+
@result = @executor.call(:some, :service)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "creates an instance with the instantiator" do
|
18
|
+
@instantiator.should have_received(:call).with(:some, :service)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "calls :call on the instance with the injector" do
|
22
|
+
@injector.should have_received(:call).with(@instance, :call)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "returns the result of Injector#call" do
|
26
|
+
@result.should be_true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "with a policy" do
|
31
|
+
before do
|
32
|
+
@result = @executor.call(:some, :policy)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "creates an instance with the instantiator" do
|
36
|
+
@instantiator.should have_received(:call).with(:some, :policy)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "calls :allowed? on the instance with the injector" do
|
40
|
+
@injector.should have_received(:call).with(@instance, :allowed?)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "returns the result of Injector#call" do
|
44
|
+
@result.should be_true
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "objectify/injector"
|
3
|
+
|
4
|
+
describe "Objectify::Injector" do
|
5
|
+
class MyInjectedClass
|
6
|
+
attr_reader :some_dependency
|
7
|
+
|
8
|
+
def initialize(some_dependency)
|
9
|
+
@some_dependency = some_dependency
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(some_dependency)
|
13
|
+
some_dependency
|
14
|
+
end
|
15
|
+
|
16
|
+
def requires_params(params)
|
17
|
+
params
|
18
|
+
end
|
19
|
+
|
20
|
+
def optional_arg(asdf=true)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# gotta use a fake resolver here because mocha sucks balls lolruby
|
25
|
+
class SimpleResolver
|
26
|
+
attr_accessor :name
|
27
|
+
|
28
|
+
def initialize(something)
|
29
|
+
@something = something
|
30
|
+
end
|
31
|
+
|
32
|
+
def call
|
33
|
+
@something
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "the simple case" do
|
38
|
+
before do
|
39
|
+
@dependency = stub("Dependency")
|
40
|
+
@resolver = SimpleResolver.new(@dependency)
|
41
|
+
@resolver_locator = stub("ResolverLocator", :call => @resolver)
|
42
|
+
@injector = Objectify::Injector.new(@resolver_locator)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "can constructor inject based on method name using a simple resolver" do
|
46
|
+
@injector.call(MyInjectedClass, :new).some_dependency.should == @dependency
|
47
|
+
end
|
48
|
+
|
49
|
+
it "can method inject based on method name using a simple resolver" do
|
50
|
+
object = MyInjectedClass.new(nil)
|
51
|
+
@injector.call(object, :call).should == @dependency
|
52
|
+
end
|
53
|
+
|
54
|
+
it "calls the resolver_locator to get the resolver" do
|
55
|
+
@injector.call(MyInjectedClass, :new)
|
56
|
+
@resolver_locator.should have_received(:call).with(:some_dependency)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "supports optional arguments" do
|
60
|
+
obj = MyInjectedClass.new("Asdf")
|
61
|
+
lambda { @injector.call(obj, :optional_arg) }.should_not raise_error
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class ParamsResolver
|
66
|
+
def name
|
67
|
+
:params
|
68
|
+
end
|
69
|
+
|
70
|
+
def call
|
71
|
+
{:some => "params"}
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context "recursive injection in to resolvers" do
|
76
|
+
before do
|
77
|
+
@resolver = ParamsResolver.new
|
78
|
+
@resolver_locator = stub("ResolverLocator", :call => @resolver)
|
79
|
+
@injector = Objectify::Injector.new(@resolver_locator)
|
80
|
+
end
|
81
|
+
|
82
|
+
it "can inject into resolvers" do
|
83
|
+
object = MyInjectedClass.new(nil)
|
84
|
+
@injector.call(object, :requires_params).should ==
|
85
|
+
{:some => "params"}
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "objectify/instantiator"
|
3
|
+
|
4
|
+
describe "Objectify::Instantiator" do
|
5
|
+
class MyService
|
6
|
+
end
|
7
|
+
|
8
|
+
before do
|
9
|
+
@service = MyService.new
|
10
|
+
@injector = stub("Injector", :call => @service)
|
11
|
+
@instantiator = Objectify::Instantiator.new(@injector)
|
12
|
+
@result = @instantiator.call(:my, :service)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "returns the result of injector#call" do
|
16
|
+
@result.should == @service
|
17
|
+
end
|
18
|
+
|
19
|
+
it "calls the injector with the generated constant" do
|
20
|
+
@injector.should have_received(:call).with(MyService, :new)
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "objectify/policy_chain_executor"
|
3
|
+
|
4
|
+
describe "Objectify::PolicyChainExecutor" do
|
5
|
+
before do
|
6
|
+
@policies = [:x, :y, :z]
|
7
|
+
@action = stub("Action", :policies => @policies)
|
8
|
+
@executor = stub("Executor", :call => true)
|
9
|
+
@responder = :an_responder
|
10
|
+
@context = stub("Context", :policy_responder => @responder)
|
11
|
+
|
12
|
+
@chain_executor = Objectify::PolicyChainExecutor.new(@executor, @context)
|
13
|
+
end
|
14
|
+
|
15
|
+
context "when all the policies execute successfully" do
|
16
|
+
before do
|
17
|
+
@result = @chain_executor.call(@action)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "calls each of the policies with the executor" do
|
21
|
+
@policies.each do |policy|
|
22
|
+
@executor.should have_received(:call).with(policy, :policy)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it "doesn't call any responders" do
|
27
|
+
@executor.should_not have_received(:call).with(anything, :responder)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "returns true" do
|
31
|
+
@result.should be_true
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "when one of the policies returns false" do
|
36
|
+
before do
|
37
|
+
@executor.stubs(:call).with(:y, :policy).returns(false)
|
38
|
+
@result = @chain_executor.call(@action)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "calls each of the policies with the executor" do
|
42
|
+
@policies[0..1].each do |policy|
|
43
|
+
@executor.should have_received(:call).with(policy, :policy)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it "doesn't call any the policies after the one that failed" do
|
48
|
+
@executor.should_not have_received(:call).with(:z, :policy)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "fetches and calls the policy responder for that policy" do
|
52
|
+
@context.should have_received(:policy_responder).with(:y)
|
53
|
+
@executor.should have_received(:call).with(:an_responder, :responder)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "returns false" do
|
57
|
+
@result.should be_false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "objectify/rails/renderer"
|
3
|
+
|
4
|
+
describe "Objectify::Rails::Renderer" do
|
5
|
+
before do
|
6
|
+
@controller = stub("Controller", :render => nil,
|
7
|
+
:redirect_to => nil,
|
8
|
+
:instance_variable_set => nil) # yeah, well.
|
9
|
+
@renderer = Objectify::Rails::Renderer.new(@controller)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "delegates template rendering" do
|
13
|
+
@renderer.template("something.html.erb", :some => :option)
|
14
|
+
@controller.should have_received(:render).with(:template => "something.html.erb",
|
15
|
+
:some => :option)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "delegates action rendering" do
|
19
|
+
@renderer.action("something.html.erb", :some => :option)
|
20
|
+
@controller.should have_received(:render).with(:action => "something.html.erb",
|
21
|
+
:some => :option)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "delegates partial rendering" do
|
25
|
+
@renderer.partial("something.html.erb", :some => :option)
|
26
|
+
@controller.should have_received(:render).with(:partial => "something.html.erb",
|
27
|
+
:some => :option)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "delegates rendering nothing" do
|
31
|
+
@renderer.nothing(:some => :option)
|
32
|
+
@controller.should have_received(:render).with(:nothing => true,
|
33
|
+
:some => :option)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "exposes the full render method" do
|
37
|
+
@renderer.render(:json => "asdf")
|
38
|
+
@controller.should have_received(:render).with(:json => "asdf")
|
39
|
+
end
|
40
|
+
|
41
|
+
it "delegates the respond_to method" do
|
42
|
+
@responder = stub("Responder")
|
43
|
+
@responder.stubs(:html).yields
|
44
|
+
@controller.stubs(:respond_to).yields(@responder)
|
45
|
+
|
46
|
+
@renderer.respond_to do |format|
|
47
|
+
format.html { }
|
48
|
+
end
|
49
|
+
|
50
|
+
@responder.should have_received(:html)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "delegates the redirect_to method" do
|
54
|
+
@renderer.redirect_to :somewhere
|
55
|
+
@controller.should have_received(:redirect_to).with(:somewhere)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "can set the data on the controller" do
|
59
|
+
@renderer.data("asdf")
|
60
|
+
@controller.should have_received(:instance_variable_set).
|
61
|
+
with(:@objectify_data, "asdf")
|
62
|
+
end
|
63
|
+
end
|