brainstem 0.2.6.1 → 1.0.0.pre.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.
- 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
|