brainstem 0.2.6.1 → 1.0.0.pre.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/CHANGELOG.md +16 -2
- data/Gemfile.lock +51 -36
- data/README.md +531 -110
- data/brainstem.gemspec +6 -2
- data/lib/brainstem.rb +25 -9
- data/lib/brainstem/concerns/controller_param_management.rb +22 -0
- data/lib/brainstem/concerns/error_presentation.rb +58 -0
- data/lib/brainstem/concerns/inheritable_configuration.rb +29 -0
- data/lib/brainstem/concerns/lookup.rb +30 -0
- data/lib/brainstem/concerns/presenter_dsl.rb +111 -0
- data/lib/brainstem/controller_methods.rb +17 -8
- data/lib/brainstem/dsl/association.rb +55 -0
- data/lib/brainstem/dsl/associations_block.rb +12 -0
- data/lib/brainstem/dsl/base_block.rb +31 -0
- data/lib/brainstem/dsl/conditional.rb +25 -0
- data/lib/brainstem/dsl/conditionals_block.rb +15 -0
- data/lib/brainstem/dsl/configuration.rb +112 -0
- data/lib/brainstem/dsl/field.rb +68 -0
- data/lib/brainstem/dsl/fields_block.rb +25 -0
- data/lib/brainstem/preloader.rb +98 -0
- data/lib/brainstem/presenter.rb +325 -134
- data/lib/brainstem/presenter_collection.rb +82 -286
- data/lib/brainstem/presenter_validator.rb +96 -0
- data/lib/brainstem/query_strategies/README.md +107 -0
- data/lib/brainstem/query_strategies/base_strategy.rb +62 -0
- data/lib/brainstem/query_strategies/filter_and_search.rb +50 -0
- data/lib/brainstem/query_strategies/filter_or_search.rb +103 -0
- data/lib/brainstem/test_helpers.rb +5 -1
- data/lib/brainstem/version.rb +1 -1
- data/spec/brainstem/concerns/controller_param_management_spec.rb +42 -0
- data/spec/brainstem/concerns/error_presentation_spec.rb +113 -0
- data/spec/brainstem/concerns/inheritable_configuration_spec.rb +210 -0
- data/spec/brainstem/concerns/presenter_dsl_spec.rb +412 -0
- data/spec/brainstem/controller_methods_spec.rb +15 -27
- data/spec/brainstem/dsl/association_spec.rb +123 -0
- data/spec/brainstem/dsl/conditional_spec.rb +93 -0
- data/spec/brainstem/dsl/configuration_spec.rb +1 -0
- data/spec/brainstem/dsl/field_spec.rb +212 -0
- data/spec/brainstem/preloader_spec.rb +137 -0
- data/spec/brainstem/presenter_collection_spec.rb +565 -244
- data/spec/brainstem/presenter_spec.rb +726 -167
- data/spec/brainstem/presenter_validator_spec.rb +209 -0
- data/spec/brainstem/query_strategies/filter_and_search_spec.rb +46 -0
- data/spec/brainstem/query_strategies/filter_or_search_spec.rb +45 -0
- data/spec/spec_helper.rb +11 -3
- data/spec/spec_helpers/db.rb +32 -65
- data/spec/spec_helpers/presenters.rb +124 -29
- data/spec/spec_helpers/rr.rb +11 -0
- data/spec/spec_helpers/schema.rb +115 -0
- metadata +126 -30
- data/lib/brainstem/association_field.rb +0 -53
- data/lib/brainstem/engine.rb +0 -4
- data/pkg/brainstem-0.2.5.gem +0 -0
- data/pkg/brainstem-0.2.6.gem +0 -0
- data/spec/spec_helpers/cleanup.rb +0 -23
@@ -1,8 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'spec_helpers/presenters'
|
3
2
|
|
4
3
|
describe Brainstem::ControllerMethods do
|
5
|
-
class
|
4
|
+
class TasksController
|
6
5
|
include Brainstem::ControllerMethods
|
7
6
|
|
8
7
|
attr_accessor :call_results
|
@@ -12,73 +11,62 @@ describe Brainstem::ControllerMethods do
|
|
12
11
|
end
|
13
12
|
end
|
14
13
|
|
15
|
-
before do
|
16
|
-
UserPresenter.presents User
|
17
|
-
TaskPresenter.presents Task
|
18
|
-
WorkspacePresenter.presents Workspace
|
19
|
-
PostPresenter.presents Post
|
20
|
-
end
|
21
|
-
|
22
14
|
describe "#present_object" do
|
23
15
|
before do
|
24
|
-
@controller =
|
16
|
+
@controller = TasksController.new
|
25
17
|
end
|
26
18
|
|
27
19
|
describe "calling #present with sensible params" do
|
28
20
|
before do
|
29
|
-
def @controller.
|
21
|
+
def @controller.brainstem_present(klass, options)
|
30
22
|
@call_results = { :klass => klass, :options => options, :block_result => yield }
|
31
23
|
end
|
32
24
|
end
|
33
25
|
|
34
26
|
it "works with arrays of ActiveRecord objects" do
|
35
|
-
@controller.
|
27
|
+
@controller.brainstem_present_object([Workspace.find(1), Workspace.find(3)])
|
36
28
|
expect(@controller.call_results[:klass]).to eq(Workspace)
|
37
|
-
expect(@controller.call_results[:options][:as]).to eq("workspaces")
|
38
29
|
expect(@controller.call_results[:block_result].pluck(:id)).to eq([1, 3])
|
39
30
|
end
|
40
31
|
|
41
32
|
it "works with a Relation" do
|
42
|
-
@controller.
|
33
|
+
@controller.brainstem_present_object(Workspace.owned_by(1))
|
43
34
|
expect(@controller.call_results[:klass]).to eq(Workspace)
|
44
|
-
expect(@controller.call_results[:options][:as]).to eq("workspaces")
|
45
35
|
expect(@controller.call_results[:block_result].pluck(:id)).to eq([1, 2, 3, 4])
|
46
36
|
end
|
47
37
|
|
48
38
|
it "works with singleton objects" do
|
49
|
-
@controller.
|
39
|
+
@controller.brainstem_present_object(Workspace.find(1))
|
50
40
|
expect(@controller.call_results[:klass]).to eq(Workspace)
|
51
|
-
expect(@controller.call_results[:options][:as]).to eq("workspaces")
|
52
41
|
expect(@controller.call_results[:block_result].pluck(:id)).to eq([1])
|
53
42
|
end
|
54
43
|
|
55
|
-
it "
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
expect(@controller.call_results[:block_result].pluck(:id)).to eq([1])
|
44
|
+
it "raises an error when given a key_map" do
|
45
|
+
expect {
|
46
|
+
@controller.brainstem_present_object(Workspace.find(1), :key_map => { "Workspace" => "your_workspaces" })
|
47
|
+
}.to raise_error(/brainstem_key annotation/)
|
60
48
|
end
|
61
49
|
|
62
50
|
it "passes through the controller params" do
|
63
|
-
@controller.
|
51
|
+
@controller.brainstem_present_object(Workspace.find(1))
|
64
52
|
expect(@controller.call_results[:options][:params]).to eq(@controller.params.merge(:only => '1'))
|
65
53
|
end
|
66
54
|
|
67
55
|
it "passes through supplied options" do
|
68
|
-
@controller.
|
56
|
+
@controller.brainstem_present_object(Workspace.find(1), :foo => :bar)
|
69
57
|
expect(@controller.call_results[:options][:foo]).to eq(:bar)
|
70
58
|
end
|
71
59
|
|
72
60
|
it "adds an only param if there is only one object to present" do
|
73
|
-
@controller.
|
61
|
+
@controller.brainstem_present_object(Workspace.find(1))
|
74
62
|
expect(@controller.call_results[:options][:params][:only]).to eq("1")
|
75
63
|
|
76
|
-
@controller.
|
64
|
+
@controller.brainstem_present_object(Workspace.all)
|
77
65
|
expect(@controller.call_results[:options][:params][:only]).to be_nil
|
78
66
|
end
|
79
67
|
|
80
68
|
it "passes :apply_default_filters => false to the PresenterCollection so that filters are not applied by default" do
|
81
|
-
@controller.
|
69
|
+
@controller.brainstem_present_object(Workspace.find(1))
|
82
70
|
expect(@controller.call_results[:options][:apply_default_filters]).to eq(false)
|
83
71
|
end
|
84
72
|
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'brainstem/dsl/association'
|
3
|
+
|
4
|
+
describe Brainstem::DSL::Association do
|
5
|
+
let(:name) { :user }
|
6
|
+
let(:target_class) { User }
|
7
|
+
let(:description) { "This object's user" }
|
8
|
+
let(:options) { { } }
|
9
|
+
let(:association) { Brainstem::DSL::Association.new(name, target_class, description, options) }
|
10
|
+
|
11
|
+
describe "#run_on" do
|
12
|
+
let(:context) { { } }
|
13
|
+
|
14
|
+
context 'with no special options' do
|
15
|
+
it 'calls the method by name on the model' do
|
16
|
+
object = Object.new
|
17
|
+
mock(object).user
|
18
|
+
association.run_on(object, context)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'when given a via' do
|
23
|
+
let(:options) { { via: :user2 } }
|
24
|
+
|
25
|
+
it 'calls the method named in :via on the model' do
|
26
|
+
object = Object.new
|
27
|
+
mock(object).user2
|
28
|
+
association.run_on(object, context)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'when given a dynamic lambda' do
|
33
|
+
let(:options) { { dynamic: lambda { |model| some_instance_method; :return_value } } }
|
34
|
+
|
35
|
+
it 'calls the lambda in the context of the given instance' do
|
36
|
+
instance = Object.new
|
37
|
+
mock(instance).some_instance_method
|
38
|
+
expect(association.run_on(:anything, context, instance)).to eq :return_value
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'when given a lookup lambda' do
|
43
|
+
let(:options) { { lookup: lambda { |models| some_instance_method; Hash[models.map { |model| [model.id, model.username] }] } } }
|
44
|
+
let(:first_model) { target_class.create(username: 'Ben') }
|
45
|
+
let(:second_model) { target_class.create(username: 'Nate') }
|
46
|
+
let(:models) { [first_model, second_model] }
|
47
|
+
let(:context) {
|
48
|
+
{
|
49
|
+
lookup: Brainstem::Presenter.new.send(:empty_lookup_cache, [], [name.to_s]),
|
50
|
+
models: models
|
51
|
+
}
|
52
|
+
}
|
53
|
+
# {:lookup=>{:fields=>{}, :associations=>{"user"=>nil}}}
|
54
|
+
|
55
|
+
context 'The first model is ran' do
|
56
|
+
it 'builds lookup cache and returns the value for the first model' do
|
57
|
+
expect(context[:lookup][:associations][name.to_s]).to eq(nil)
|
58
|
+
instance = Object.new
|
59
|
+
mock(instance).some_instance_method
|
60
|
+
expect(association.run_on(first_model, context, instance)).to eq('Ben')
|
61
|
+
expect(context[:lookup][:associations][name.to_s]).to eq({ first_model.id => 'Ben', second_model.id => 'Nate' })
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'The second model is ran after the first' do
|
66
|
+
it 'returns the value from the lookup cache and does not run the lookup' do
|
67
|
+
instance = Object.new
|
68
|
+
mock(instance).some_instance_method
|
69
|
+
association.run_on(first_model, context, instance)
|
70
|
+
expect(context[:lookup][:associations][name.to_s]).to eq({ first_model.id => 'Ben', second_model.id => 'Nate' })
|
71
|
+
|
72
|
+
mock(instance).some_instance_method.never
|
73
|
+
expect(association.run_on(second_model, context, instance)).to eq('Nate')
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'with no lookup_fetch' do
|
78
|
+
context 'when the lookup returns on object which does not respond to []' do
|
79
|
+
let(:options) { { lookup: lambda { |models| nil } } }
|
80
|
+
|
81
|
+
it 'should raise error explaining the default lookup fetch relies on [] to access the model\'s value from the lookup' do
|
82
|
+
expect {
|
83
|
+
association.run_on(first_model, context)
|
84
|
+
}.to raise_error(StandardError, 'Brainstem expects the return result of the `lookup` to be a Hash since it must respond to [] in order to access the model\'s assocation(s). Default: lookup_fetch: lambda { |lookup, model| lookup[model.id] }`')
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'with a dynamic lambda' do
|
90
|
+
let(:options) {
|
91
|
+
{
|
92
|
+
lookup: lambda { |models| lookup_instance_method; Hash[models.map { |model| [model.id, model.username] }] },
|
93
|
+
dynamic: lambda { |model| dynamic_instance_method; model.username }
|
94
|
+
}
|
95
|
+
}
|
96
|
+
|
97
|
+
it 'calls the lookup lambda and not the dynamic lambda' do
|
98
|
+
instance = Object.new
|
99
|
+
mock(instance).dynamic_instance_method.never
|
100
|
+
mock(instance).lookup_instance_method
|
101
|
+
expect(association.run_on(first_model, context, instance)).to eq 'Ben'
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context 'when given a lookup_fetch' do
|
106
|
+
let(:options) {
|
107
|
+
{
|
108
|
+
lookup: lambda { |models| Hash[models.map { |model| [model.id, model.username] }] },
|
109
|
+
lookup_fetch: lambda { |lookup, model| some_instance_method; lookup[model.id] }
|
110
|
+
}
|
111
|
+
}
|
112
|
+
|
113
|
+
it 'returns the value from the lookup using the lookup_fetch lambda' do
|
114
|
+
context[:lookup][:associations][name.to_s] = {}
|
115
|
+
context[:lookup][:associations][name.to_s][first_model.id] = "Ben's stubbed out Name"
|
116
|
+
instance = Object.new
|
117
|
+
mock(instance).some_instance_method
|
118
|
+
expect(association.run_on(first_model, context, instance)).to eq("Ben's stubbed out Name")
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'brainstem/dsl/conditional'
|
3
|
+
|
4
|
+
describe Brainstem::DSL::Conditional do
|
5
|
+
let(:conditional) { Brainstem::DSL::Conditional.new(name, type, action, description) }
|
6
|
+
let(:model) { Workspace.first }
|
7
|
+
|
8
|
+
describe '.matches?' do
|
9
|
+
context 'as a :model conditional' do
|
10
|
+
let(:name) { :title_is_hello }
|
11
|
+
let(:type) { :model }
|
12
|
+
let(:action) { lambda { |model| model.title == 'hello' } }
|
13
|
+
let(:description) { 'visible when the title is hello' }
|
14
|
+
|
15
|
+
it 'calls the action and passes in the given model' do
|
16
|
+
model.title = 'not hello'
|
17
|
+
expect(conditional.matches?(model)).to be false
|
18
|
+
model.title = 'hello'
|
19
|
+
expect(conditional.matches?(model)).to be true
|
20
|
+
end
|
21
|
+
|
22
|
+
describe 'when given a helper instance' do
|
23
|
+
let(:action) { lambda { |model| some_method == 5 } }
|
24
|
+
|
25
|
+
it 'calls the action in the context of the given helper' do
|
26
|
+
helper_class = Class.new do
|
27
|
+
def some_method
|
28
|
+
5
|
29
|
+
end
|
30
|
+
end
|
31
|
+
expect(conditional.matches?(model, helper_class.new)).to be true
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'caches in the model conditional cache' do
|
36
|
+
hash = { model: {}, request: {} }
|
37
|
+
expect(conditional.matches?(model, Object.new, hash)).to be false
|
38
|
+
expect(hash).to eq({ model: { title_is_hello: false }, request: {} })
|
39
|
+
|
40
|
+
model.title = 'hello'
|
41
|
+
expect(conditional.matches?(model, Object.new, hash)).to be false
|
42
|
+
|
43
|
+
hash = { model: {}, request: {} }
|
44
|
+
expect(conditional.matches?(model, Object.new, hash)).to be true
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'as a :request conditional' do
|
49
|
+
let(:name) { :user_is_bob }
|
50
|
+
let(:type) { :request }
|
51
|
+
let(:action) { lambda { current_user == 'bob' } }
|
52
|
+
let(:description) { 'visible only to bob' }
|
53
|
+
|
54
|
+
it 'calls the action in the helper context, without passing in any arguments' do
|
55
|
+
helper_class = Class.new do
|
56
|
+
def current_user
|
57
|
+
'jane'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
expect(conditional.matches?(model, helper_class.new)).to be false
|
61
|
+
|
62
|
+
helper_class = Class.new do
|
63
|
+
def current_user
|
64
|
+
'bob'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
expect(conditional.matches?(model, helper_class.new)).to be true
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'performs caching' do
|
71
|
+
cache = { model: {}, request: {} }
|
72
|
+
|
73
|
+
helper_class = Class.new do
|
74
|
+
def current_user
|
75
|
+
'jane'
|
76
|
+
end
|
77
|
+
end
|
78
|
+
expect(conditional.matches?(model, helper_class.new, cache)).to be false
|
79
|
+
expect(cache[:request][:user_is_bob]).to be false
|
80
|
+
|
81
|
+
helper_class = Class.new do
|
82
|
+
def current_user
|
83
|
+
'bob'
|
84
|
+
end
|
85
|
+
end
|
86
|
+
expect(conditional.matches?(model, helper_class.new, cache)).to be false
|
87
|
+
|
88
|
+
cache = { model: {}, request: {} }
|
89
|
+
expect(conditional.matches?(model, helper_class.new, cache)).to be true
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
# This is tested in concerns/inheritable_configuration_spec.rb
|
@@ -0,0 +1,212 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'brainstem/dsl/field'
|
3
|
+
|
4
|
+
describe Brainstem::DSL::Field do
|
5
|
+
let(:name) { :title }
|
6
|
+
let(:type) { :string }
|
7
|
+
let(:description) { 'the title of this model' }
|
8
|
+
let(:options) { { } }
|
9
|
+
let(:field) { Brainstem::DSL::Field.new(name, type, description, options) }
|
10
|
+
let(:model) { Workspace.first }
|
11
|
+
|
12
|
+
describe '#method_name' do
|
13
|
+
describe 'by default' do
|
14
|
+
it 'returns the name' do
|
15
|
+
expect(field.method_name).to eq 'title'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe 'on dynamic fields' do
|
20
|
+
let(:options) { { dynamic: lambda { 2 } } }
|
21
|
+
|
22
|
+
it 'returns nil' do
|
23
|
+
expect(field.method_name).to be_nil
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe 'when :via is present' do
|
28
|
+
let(:options) { { via: :description } }
|
29
|
+
|
30
|
+
it 'uses the :via method name' do
|
31
|
+
expect(field.method_name).to eq 'description'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#run_on' do
|
37
|
+
let(:context) { { } }
|
38
|
+
|
39
|
+
context 'on :dynamic fields' do
|
40
|
+
let(:options) { { dynamic: lambda { some_instance_method } } }
|
41
|
+
|
42
|
+
it 'calls the :dynamic lambda in the context of the given instance' do
|
43
|
+
do_not_allow(model).title
|
44
|
+
instance = Object.new
|
45
|
+
mock(instance).some_instance_method
|
46
|
+
field.run_on(model, context, instance)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'on :lookup fields' do
|
51
|
+
let(:options) { { lookup: lambda { |models| some_instance_method; Hash[models.map { |model| [model.id, model.title] }] } } }
|
52
|
+
let(:first_model) { Workspace.create(title: "Ben's Project") }
|
53
|
+
let(:second_model) { Workspace.create(title: "Nate's Project") }
|
54
|
+
let(:models) { [first_model, second_model] }
|
55
|
+
let(:context) {
|
56
|
+
{
|
57
|
+
lookup: Brainstem::Presenter.new.send(:empty_lookup_cache, [name.to_s], []),
|
58
|
+
models: models
|
59
|
+
}
|
60
|
+
}
|
61
|
+
# {:lookup=>{:fields=>{"title"=>nil}, :associations=>{}}
|
62
|
+
|
63
|
+
context 'The first model is ran' do
|
64
|
+
it 'builds lookup cache and returns the value for the first model' do
|
65
|
+
expect(context[:lookup][:fields][name.to_s]).to eq(nil)
|
66
|
+
instance = Object.new
|
67
|
+
mock(instance).some_instance_method
|
68
|
+
expect(field.run_on(first_model, context, instance)).to eq("Ben's Project")
|
69
|
+
expect(context[:lookup][:fields][name.to_s]).to eq({ first_model.id => "Ben's Project", second_model.id => "Nate's Project" })
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'The second model is ran after the first' do
|
74
|
+
it 'returns the value from the lookup cache and does not run the lookup' do
|
75
|
+
instance = Object.new
|
76
|
+
mock(instance).some_instance_method
|
77
|
+
field.run_on(first_model, context, instance)
|
78
|
+
expect(context[:lookup][:fields][name.to_s]).to eq({ first_model.id => "Ben's Project", second_model.id => "Nate's Project" })
|
79
|
+
|
80
|
+
mock(instance).some_instance_method.never
|
81
|
+
expect(field.run_on(second_model, context, instance)).to eq("Nate's Project")
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'with no lookup_fetch' do
|
86
|
+
context 'when the lookup returns on object which does not respond to []' do
|
87
|
+
let(:options) { { lookup: lambda { |models| nil } } }
|
88
|
+
|
89
|
+
it 'should raise error explaining the default lookup fetch relies on [] to access the model\'s value from the lookup' do
|
90
|
+
expect {
|
91
|
+
field.run_on(first_model, context)
|
92
|
+
}.to raise_error(StandardError, 'Brainstem expects the return result of the `lookup` to be a Hash since it must respond to [] in order to access the model\'s assocation(s). Default: lookup_fetch: lambda { |lookup, model| lookup[model.id] }`')
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context 'with a dynamic lambda' do
|
98
|
+
let(:options) {
|
99
|
+
{
|
100
|
+
lookup: lambda { |models| lookup_instance_method; Hash[models.map { |model| [model.id, model.title] }] },
|
101
|
+
dynamic: lambda { |model| dynamic_instance_method; model.title }
|
102
|
+
}
|
103
|
+
}
|
104
|
+
|
105
|
+
it 'does not use the dynamic lambda' do
|
106
|
+
instance = Object.new
|
107
|
+
mock(instance).dynamic_instance_method.never
|
108
|
+
mock(instance).lookup_instance_method
|
109
|
+
expect(field.run_on(first_model, context, instance)).to eq "Ben's Project"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
context 'on :lookup_fetch' do
|
114
|
+
let(:options) {
|
115
|
+
{
|
116
|
+
lookup: lambda { |models| Hash[models.map { |model| [model.id, model.title] }] },
|
117
|
+
lookup_fetch: lambda { |lookup, model| some_instance_method; lookup[model.id] }
|
118
|
+
}
|
119
|
+
}
|
120
|
+
|
121
|
+
it 'returns the value from the lookup using the lookup_fetch lambda' do
|
122
|
+
context[:lookup][:fields][name.to_s] = {}
|
123
|
+
context[:lookup][:fields][name.to_s][first_model.id] = "Ben's stubbed out Project"
|
124
|
+
instance = Object.new
|
125
|
+
mock(instance).some_instance_method
|
126
|
+
expect(field.run_on(first_model, context, instance)).to eq("Ben's stubbed out Project")
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context 'on non-:dynamic fields' do
|
132
|
+
it 'calls method_name on the model' do
|
133
|
+
mock(model).foo
|
134
|
+
mock(field).method_name { 'foo' }
|
135
|
+
field.run_on(model, context)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe '#conditionals_match?' do
|
141
|
+
let(:fake_conditional) do
|
142
|
+
Class.new do
|
143
|
+
def initialize(result)
|
144
|
+
@result = result
|
145
|
+
end
|
146
|
+
|
147
|
+
def matches?(model, helper_instance, conditional_cache)
|
148
|
+
@result
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
context 'when no :if option has been set on the field' do
|
154
|
+
it 'returns true when there are no conditions' do
|
155
|
+
expect(field.conditionals_match?(model, WorkspacePresenter.configuration[:conditionals])).to eq true
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
context 'when a single :if has been set' do
|
160
|
+
let(:options) { { if: :title_is_hello } }
|
161
|
+
|
162
|
+
it 'returns true if the conditional matches' do
|
163
|
+
expect(field.conditionals_match?(model, title_is_hello: fake_conditional.new(true))).to eq true
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'returns false if the conditional does not match' do
|
167
|
+
expect(field.conditionals_match?(model, title_is_hello: fake_conditional.new(false))).to eq false
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
context 'when multiple :if options have been passed' do
|
172
|
+
let(:options) { { if: [:title_is_hello, :user_is_bob] } }
|
173
|
+
|
174
|
+
it 'returns true if all of the conditionals match' do
|
175
|
+
expect(field.conditionals_match?(model, title_is_hello: fake_conditional.new(true), user_is_bob: fake_conditional.new(false))).to eq false
|
176
|
+
expect(field.conditionals_match?(model, title_is_hello: fake_conditional.new(false), user_is_bob: fake_conditional.new(true))).to eq false
|
177
|
+
expect(field.conditionals_match?(model, title_is_hello: fake_conditional.new(true), user_is_bob: fake_conditional.new(true))).to eq true
|
178
|
+
expect(field.conditionals_match?(model,
|
179
|
+
unknown: fake_conditional.new(false),
|
180
|
+
title_is_hello: fake_conditional.new(true),
|
181
|
+
user_is_bob: fake_conditional.new(true))).to eq true
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe "#optioned?" do
|
187
|
+
context "when is not an optional field" do
|
188
|
+
it 'returns true' do
|
189
|
+
expect(field.optioned?(['some_optional_field', 'some_other_optional_field'])).to eq true
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
context "when is an optional field" do
|
194
|
+
let(:name) { :expensive_title }
|
195
|
+
let(:type) { :string }
|
196
|
+
let(:options) { { optional: true } }
|
197
|
+
let(:description) { 'the optional expensive title field' }
|
198
|
+
|
199
|
+
context "when not requested" do
|
200
|
+
it 'returns false' do
|
201
|
+
expect(field.optioned?([])).to eq false
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
context "when requested" do
|
206
|
+
it 'returns true' do
|
207
|
+
expect(field.optioned?(['expensive_title', 'some_other_optional_field'])).to eq true
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|