brainstem 1.0.0.pre.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/Gemfile.lock +1 -1
- data/README.md +383 -32
- data/bin/brainstem +6 -0
- data/brainstem.gemspec +2 -0
- data/docs/api_doc_generator.markdown +175 -0
- data/docs/brainstem_executable.markdown +32 -0
- data/docs/docgen.png +0 -0
- data/docs/docgen_ascii.txt +63 -0
- data/docs/executable.png +0 -0
- data/docs/executable_ascii.txt +10 -0
- data/lib/brainstem/api_docs.rb +146 -0
- data/lib/brainstem/api_docs/abstract_collection.rb +116 -0
- data/lib/brainstem/api_docs/atlas.rb +158 -0
- data/lib/brainstem/api_docs/builder.rb +167 -0
- data/lib/brainstem/api_docs/controller.rb +122 -0
- data/lib/brainstem/api_docs/controller_collection.rb +40 -0
- data/lib/brainstem/api_docs/endpoint.rb +234 -0
- data/lib/brainstem/api_docs/endpoint_collection.rb +58 -0
- data/lib/brainstem/api_docs/exceptions.rb +8 -0
- data/lib/brainstem/api_docs/formatters/abstract_formatter.rb +64 -0
- data/lib/brainstem/api_docs/formatters/markdown/controller_formatter.rb +76 -0
- data/lib/brainstem/api_docs/formatters/markdown/endpoint_collection_formatter.rb +73 -0
- data/lib/brainstem/api_docs/formatters/markdown/endpoint_formatter.rb +169 -0
- data/lib/brainstem/api_docs/formatters/markdown/helper.rb +76 -0
- data/lib/brainstem/api_docs/formatters/markdown/presenter_formatter.rb +200 -0
- data/lib/brainstem/api_docs/introspectors/abstract_introspector.rb +100 -0
- data/lib/brainstem/api_docs/introspectors/rails_introspector.rb +232 -0
- data/lib/brainstem/api_docs/presenter.rb +225 -0
- data/lib/brainstem/api_docs/presenter_collection.rb +97 -0
- data/lib/brainstem/api_docs/resolver.rb +73 -0
- data/lib/brainstem/api_docs/sinks/abstract_sink.rb +37 -0
- data/lib/brainstem/api_docs/sinks/controller_presenter_multifile_sink.rb +93 -0
- data/lib/brainstem/api_docs/sinks/stdout_sink.rb +44 -0
- data/lib/brainstem/cli.rb +146 -0
- data/lib/brainstem/cli/abstract_command.rb +97 -0
- data/lib/brainstem/cli/generate_api_docs_command.rb +169 -0
- data/lib/brainstem/concerns/controller_dsl.rb +300 -0
- data/lib/brainstem/concerns/controller_param_management.rb +30 -9
- data/lib/brainstem/concerns/formattable.rb +38 -0
- data/lib/brainstem/concerns/inheritable_configuration.rb +3 -2
- data/lib/brainstem/concerns/optional.rb +43 -0
- data/lib/brainstem/concerns/presenter_dsl.rb +76 -15
- data/lib/brainstem/controller_methods.rb +6 -3
- data/lib/brainstem/dsl/association.rb +6 -3
- data/lib/brainstem/dsl/associations_block.rb +6 -3
- data/lib/brainstem/dsl/base_block.rb +2 -4
- data/lib/brainstem/dsl/conditional.rb +7 -3
- data/lib/brainstem/dsl/conditionals_block.rb +4 -4
- data/lib/brainstem/dsl/configuration.rb +184 -8
- data/lib/brainstem/dsl/field.rb +6 -3
- data/lib/brainstem/dsl/fields_block.rb +2 -3
- data/lib/brainstem/help_text.txt +8 -0
- data/lib/brainstem/presenter.rb +27 -6
- data/lib/brainstem/presenter_validator.rb +5 -2
- data/lib/brainstem/time_classes.rb +1 -1
- data/lib/brainstem/version.rb +1 -1
- data/spec/brainstem/api_docs/abstract_collection_spec.rb +156 -0
- data/spec/brainstem/api_docs/atlas_spec.rb +353 -0
- data/spec/brainstem/api_docs/builder_spec.rb +100 -0
- data/spec/brainstem/api_docs/controller_collection_spec.rb +92 -0
- data/spec/brainstem/api_docs/controller_spec.rb +225 -0
- data/spec/brainstem/api_docs/endpoint_collection_spec.rb +144 -0
- data/spec/brainstem/api_docs/endpoint_spec.rb +346 -0
- data/spec/brainstem/api_docs/formatters/abstract_formatter_spec.rb +30 -0
- data/spec/brainstem/api_docs/formatters/markdown/controller_formatter_spec.rb +126 -0
- data/spec/brainstem/api_docs/formatters/markdown/endpoint_collection_formatter_spec.rb +85 -0
- data/spec/brainstem/api_docs/formatters/markdown/endpoint_formatter_spec.rb +261 -0
- data/spec/brainstem/api_docs/formatters/markdown/helper_spec.rb +100 -0
- data/spec/brainstem/api_docs/formatters/markdown/presenter_formatter_spec.rb +485 -0
- data/spec/brainstem/api_docs/introspectors/abstract_introspector_spec.rb +192 -0
- data/spec/brainstem/api_docs/introspectors/rails_introspector_spec.rb +170 -0
- data/spec/brainstem/api_docs/presenter_collection_spec.rb +84 -0
- data/spec/brainstem/api_docs/presenter_spec.rb +519 -0
- data/spec/brainstem/api_docs/resolver_spec.rb +72 -0
- data/spec/brainstem/api_docs/sinks/abstract_sink_spec.rb +16 -0
- data/spec/brainstem/api_docs/sinks/controller_presenter_multifile_sink_spec.rb +56 -0
- data/spec/brainstem/api_docs/sinks/stdout_sink_spec.rb +22 -0
- data/spec/brainstem/api_docs_spec.rb +58 -0
- data/spec/brainstem/cli/abstract_command_spec.rb +91 -0
- data/spec/brainstem/cli/generate_api_docs_command_spec.rb +125 -0
- data/spec/brainstem/cli_spec.rb +67 -0
- data/spec/brainstem/concerns/controller_dsl_spec.rb +471 -0
- data/spec/brainstem/concerns/controller_param_management_spec.rb +36 -16
- data/spec/brainstem/concerns/formattable_spec.rb +30 -0
- data/spec/brainstem/concerns/inheritable_configuration_spec.rb +104 -4
- data/spec/brainstem/concerns/optional_spec.rb +48 -0
- data/spec/brainstem/concerns/presenter_dsl_spec.rb +202 -31
- data/spec/brainstem/dsl/association_spec.rb +18 -2
- data/spec/brainstem/dsl/conditional_spec.rb +25 -2
- data/spec/brainstem/dsl/configuration_spec.rb +1 -1
- data/spec/brainstem/dsl/field_spec.rb +18 -2
- data/spec/brainstem/presenter_collection_spec.rb +10 -2
- data/spec/brainstem/presenter_spec.rb +32 -0
- data/spec/brainstem/presenter_validator_spec.rb +12 -7
- data/spec/dummy/rails.rb +49 -0
- data/spec/shared/atlas_taker.rb +18 -0
- data/spec/shared/formattable.rb +14 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/spec_helpers/db.rb +1 -1
- data/spec/spec_helpers/presenters.rb +20 -14
- metadata +106 -6
@@ -2,41 +2,61 @@ require 'spec_helper'
|
|
2
2
|
require 'brainstem/concerns/controller_param_management'
|
3
3
|
|
4
4
|
describe Brainstem::Concerns::ControllerParamManagement do
|
5
|
-
|
6
|
-
|
5
|
+
subject do
|
6
|
+
Class.new do
|
7
|
+
include Brainstem::Concerns::ControllerParamManagement
|
7
8
|
|
8
|
-
|
9
|
-
|
9
|
+
def controller_name
|
10
|
+
self.class.controller_name
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.controller_name
|
14
|
+
'tasks'
|
15
|
+
end
|
10
16
|
end
|
11
17
|
end
|
12
18
|
|
13
19
|
before do
|
14
|
-
|
15
|
-
|
20
|
+
subject.brainstem_model_name = nil
|
21
|
+
subject.brainstem_plural_model_name = nil
|
16
22
|
end
|
17
23
|
|
18
24
|
describe '.brainstem_model_name' do
|
19
25
|
it 'is settable on the controller' do
|
20
|
-
|
21
|
-
expect(
|
26
|
+
subject.brainstem_model_name = 'thingy'
|
27
|
+
expect(subject.new.brainstem_model_name).to eq 'thingy'
|
22
28
|
end
|
23
29
|
|
24
30
|
it 'has good defaults' do
|
25
|
-
expect(
|
26
|
-
expect(
|
31
|
+
expect(subject.new.brainstem_model_name).to eq 'task'
|
32
|
+
expect(subject.new.brainstem_plural_model_name).to eq 'tasks'
|
33
|
+
end
|
34
|
+
|
35
|
+
it "has good defaults on the class level" do
|
36
|
+
expect(subject.brainstem_model_name).to eq 'task'
|
37
|
+
expect(subject.brainstem_plural_model_name).to eq 'tasks'
|
27
38
|
end
|
28
39
|
end
|
29
40
|
|
30
41
|
describe '.brainstem_plural_model_name' do
|
31
42
|
it 'is infered from the singular model name' do
|
32
|
-
|
33
|
-
expect(
|
43
|
+
subject.brainstem_model_name = 'thingy'
|
44
|
+
expect(subject.brainstem_plural_model_name).to eq 'thingies'
|
45
|
+
expect(subject.new.brainstem_plural_model_name).to eq 'thingies'
|
34
46
|
end
|
35
47
|
|
36
48
|
it 'can be overridden' do
|
37
|
-
|
38
|
-
|
39
|
-
expect(
|
49
|
+
subject.brainstem_model_name = 'thingy'
|
50
|
+
subject.brainstem_plural_model_name = 'thingzees'
|
51
|
+
expect(subject.brainstem_plural_model_name).to eq 'thingzees'
|
52
|
+
expect(subject.new.brainstem_plural_model_name).to eq 'thingzees'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '.brainstem_model_class' do
|
57
|
+
it "classifies and constantizes the brainstem_model_name" do
|
58
|
+
subject.brainstem_model_name = "object"
|
59
|
+
expect(subject.brainstem_model_class).to eq Object
|
40
60
|
end
|
41
61
|
end
|
42
|
-
end
|
62
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'brainstem/concerns/formattable'
|
3
|
+
|
4
|
+
module Brainstem
|
5
|
+
module Concerns
|
6
|
+
describe Formattable do
|
7
|
+
let(:formattable_class) do
|
8
|
+
Class.new do
|
9
|
+
include Brainstem::Concerns::Formattable
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:subject) { formattable_class.new }
|
14
|
+
|
15
|
+
describe "#formatter_type" do
|
16
|
+
it "returns the class name underscored and symbolized" do
|
17
|
+
stub(formattable_class).to_s { "MyClass" }
|
18
|
+
expect(subject.formatter_type).to eq :my_class
|
19
|
+
end
|
20
|
+
|
21
|
+
it "returns only the last segment of a class name" do
|
22
|
+
stub(formattable_class).to_s { "Namespaced::MyClass" }
|
23
|
+
expect(subject.formatter_type).to eq :my_class
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -33,22 +33,51 @@ describe Brainstem::Concerns::InheritableConfiguration do
|
|
33
33
|
expect(parent_class.configuration['ten']).to be_nil
|
34
34
|
end
|
35
35
|
|
36
|
-
|
37
|
-
|
36
|
+
it "does not inherit nonheritable keys" do
|
37
|
+
expect(parent_class.configuration['nonheritable']).to be_nil
|
38
|
+
parent_class.configuration.nonheritable! :nonheritable
|
39
|
+
parent_class.configuration['nonheritable'] = "parent"
|
40
|
+
expect(parent_class.configuration['nonheritable']).to eq "parent"
|
41
|
+
|
42
|
+
subclass = Class.new(parent_class)
|
43
|
+
expect(subclass.configuration['nonheritable']).to be_nil
|
44
|
+
|
45
|
+
subclass.configuration['nonheritable'] = "child"
|
46
|
+
|
47
|
+
subsubclass = Class.new(subclass)
|
48
|
+
expect(subsubclass.configuration['nonheritable']).to be_nil
|
49
|
+
end
|
50
|
+
|
51
|
+
describe '#keys and #to_h' do
|
52
|
+
let(:subclass) { Class.new(parent_class) }
|
53
|
+
let(:subsubclass) { Class.new(subclass) }
|
54
|
+
|
55
|
+
before do
|
38
56
|
parent_class.configuration['1'] = :a
|
39
57
|
parent_class.configuration['2'] = :b
|
40
58
|
|
41
|
-
subclass = Class.new(parent_class)
|
42
59
|
subclass.configuration['2'] = :c
|
43
60
|
subclass.configuration['3'] = :d
|
44
61
|
|
45
|
-
subsubclass = Class.new(subclass)
|
46
62
|
subsubclass.configuration['3'] = :e
|
47
63
|
subsubclass.configuration['4'] = :f
|
64
|
+
end
|
48
65
|
|
66
|
+
it "returns the union of this class's keys with any parent keys" do
|
49
67
|
expect(parent_class.configuration.keys).to eq ['1', '2']
|
68
|
+
expect(parent_class.configuration.to_h).to eq({ '1' => :a, '2' => :b })
|
50
69
|
expect(subclass.configuration.keys).to eq ['1', '2', '3']
|
70
|
+
expect(subclass.configuration.to_h).to eq({ '1' => :a, '2' => :c, '3' => :d })
|
51
71
|
expect(subsubclass.configuration.keys).to eq ['1', '2', '3', '4']
|
72
|
+
expect(subsubclass.configuration.to_h).to eq({ '1' => :a, '2' => :c, '3' => :e, '4' => :f })
|
73
|
+
|
74
|
+
# it doesn't mutate storage
|
75
|
+
subclass.configuration.to_h['1'] = :new
|
76
|
+
subclass.configuration.to_h['2'] = :new
|
77
|
+
expect(subclass.configuration['1']).to eq :a
|
78
|
+
expect(subclass.configuration['2']).to eq :c
|
79
|
+
expect(parent_class.configuration['1']).to eq :a
|
80
|
+
expect(parent_class.configuration['2']).to eq :b
|
52
81
|
|
53
82
|
expect(parent_class.configuration['1']).to eq :a
|
54
83
|
expect(parent_class.configuration['2']).to eq :b
|
@@ -62,6 +91,64 @@ describe Brainstem::Concerns::InheritableConfiguration do
|
|
62
91
|
expect(subsubclass.configuration['3']).to eq :e
|
63
92
|
expect(subsubclass.configuration['4']).to eq :f
|
64
93
|
end
|
94
|
+
|
95
|
+
it "does not return nonheritable keys in the parent" do
|
96
|
+
parent_class.configuration.nonheritable! :nonheritable
|
97
|
+
parent_class.configuration['nonheritable'] = "why yes, I am nonheritable"
|
98
|
+
expect(subclass.configuration.keys).not_to include 'nonheritable'
|
99
|
+
|
100
|
+
expect(subclass.configuration.to_h.keys).not_to include 'nonheritable'
|
101
|
+
expect(subclass.configuration.has_key?('nonheritable')).to eq false
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "#fetch" do
|
106
|
+
let(:config) { parent_class.configuration }
|
107
|
+
let(:my_block) { Proc.new { nil } }
|
108
|
+
|
109
|
+
before do
|
110
|
+
parent_class.configuration["my_key"] = "yep"
|
111
|
+
end
|
112
|
+
|
113
|
+
context "when key is found" do
|
114
|
+
it "returns the key" do
|
115
|
+
expect(config.fetch("my_key")).to eq "yep"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context "when key is not found" do
|
120
|
+
context "when default or block not given" do
|
121
|
+
it "raises a KeyError exception" do
|
122
|
+
expect { config.fetch("fake_key") }.to raise_exception KeyError
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context "when block given" do
|
127
|
+
before do
|
128
|
+
mock(my_block).call { "hey" }
|
129
|
+
end
|
130
|
+
|
131
|
+
it "evals and returns the block" do
|
132
|
+
expect(config.fetch("fake_key", &my_block)).to eq "hey"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
context "when default given" do
|
137
|
+
it "returns the default" do
|
138
|
+
expect(config.fetch("fake_key", "hey")).to eq "hey"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context "when default and block given" do
|
143
|
+
before do
|
144
|
+
mock(my_block).call("hey") { "sup" }
|
145
|
+
end
|
146
|
+
|
147
|
+
it "evals and returns the block, passing it the default" do
|
148
|
+
expect(config.fetch("fake_key", "hey", &my_block)).to eq "sup"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
65
152
|
end
|
66
153
|
|
67
154
|
describe '#nest!' do
|
@@ -199,6 +286,19 @@ describe Brainstem::Concerns::InheritableConfiguration do
|
|
199
286
|
expect(lambda { subclass.configuration['list'] = 2 }).to raise_error('You cannot override an inheritable array once set')
|
200
287
|
end
|
201
288
|
end
|
289
|
+
|
290
|
+
describe "#nonheritable!" do
|
291
|
+
it "adds the key to the nonheritable attributes list" do
|
292
|
+
parent_class.configuration.nonheritable! :nonheritable
|
293
|
+
expect(parent_class.configuration.nonheritable_keys.to_a).to eq ["nonheritable"]
|
294
|
+
end
|
295
|
+
|
296
|
+
it "dedupes" do
|
297
|
+
parent_class.configuration.nonheritable! :nonheritable
|
298
|
+
parent_class.configuration.nonheritable! :nonheritable
|
299
|
+
expect(parent_class.configuration.nonheritable_keys.to_a).to eq ["nonheritable"]
|
300
|
+
end
|
301
|
+
end
|
202
302
|
end
|
203
303
|
|
204
304
|
describe '#configuration' do
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'brainstem/concerns/optional'
|
3
|
+
|
4
|
+
describe Brainstem::Concerns::Optional do
|
5
|
+
let(:optional_class) do
|
6
|
+
Class.new do
|
7
|
+
include Brainstem::Concerns::Optional
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
context "when options are not passed" do
|
12
|
+
it "raises no error" do
|
13
|
+
expect { optional_class.new }.not_to raise_error
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "when options are passed" do
|
18
|
+
context "when option is whitelisted" do
|
19
|
+
before do
|
20
|
+
stub.any_instance_of(optional_class).valid_options { [:thing] }
|
21
|
+
end
|
22
|
+
|
23
|
+
context "when an accessor exists" do
|
24
|
+
before do
|
25
|
+
mock.any_instance_of(optional_class).thing=("blah")
|
26
|
+
end
|
27
|
+
|
28
|
+
it "passes the option to the accessor" do
|
29
|
+
optional_class.new(thing: "blah")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "when no accessor exists" do
|
34
|
+
it "raises an error" do
|
35
|
+
expect { optional_class.new(thing: "blah") }.to \
|
36
|
+
raise_error NoMethodError
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "when option is not whitelisted" do
|
42
|
+
it "does not send the symbol" do
|
43
|
+
dont_allow.any_instance_of(optional_class).other_thing
|
44
|
+
expect { optional_class.new(other_thing: "nope") }.not_to raise_error
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -5,11 +5,17 @@ require 'brainstem/concerns/presenter_dsl'
|
|
5
5
|
#
|
6
6
|
# brainstem_key :projects
|
7
7
|
#
|
8
|
+
# title "Project"
|
9
|
+
# description "It does stuff"
|
10
|
+
#
|
11
|
+
#
|
8
12
|
# conditionals do
|
9
|
-
# model :title_is_hello, lambda { workspace.title == 'hello' }, 'visible when the title is hello'
|
10
|
-
# request :user_is_bob, lambda { current_user.username == 'bob' }, 'visible only to bob'
|
13
|
+
# model :title_is_hello, lambda { workspace.title == 'hello' }, info: 'visible when the title is hello'
|
14
|
+
# request :user_is_bob, lambda { current_user.username == 'bob' }, info: 'visible only to bob'
|
11
15
|
# end
|
12
16
|
#
|
17
|
+
# sort_order :created_at, ".created_at"
|
18
|
+
#
|
13
19
|
# fields do
|
14
20
|
# field :title, :string
|
15
21
|
# field :description, :string
|
@@ -20,7 +26,8 @@ require 'brainstem/concerns/presenter_dsl'
|
|
20
26
|
# if: [:user_is_bob, :title_is_hello]
|
21
27
|
#
|
22
28
|
# with_options if: :user_is_bob do
|
23
|
-
# field :bob_title, :string,
|
29
|
+
# field :bob_title, :string,
|
30
|
+
# info: 'another name for the title, only for Bob',
|
24
31
|
# via: :title
|
25
32
|
# end
|
26
33
|
# fields :nested_permissions do
|
@@ -30,10 +37,13 @@ require 'brainstem/concerns/presenter_dsl'
|
|
30
37
|
# end
|
31
38
|
#
|
32
39
|
# associations do
|
33
|
-
# association :tasks, Task,
|
40
|
+
# association :tasks, Task,
|
41
|
+
# info: 'The Tasks in this Workspace',
|
34
42
|
# restrict_to_only: true
|
35
|
-
# association :lead_user, User,
|
36
|
-
#
|
43
|
+
# association :lead_user, User,
|
44
|
+
# info: 'The user who runs this Workspace'
|
45
|
+
# association :subtasks, Task,
|
46
|
+
# info: 'Only Tasks in this Workspace that are subtasks',
|
37
47
|
# dynamic: lambda { |workspace| workspace.tasks.where('parent_id IS NOT NULL') }
|
38
48
|
# association :something, :polymorphic
|
39
49
|
# end
|
@@ -62,11 +72,99 @@ describe Brainstem::Concerns::PresenterDSL do
|
|
62
72
|
end
|
63
73
|
end
|
64
74
|
|
75
|
+
describe 'the title method' do
|
76
|
+
it "is stored in the configuration" do
|
77
|
+
presenter_class.title "Project"
|
78
|
+
expect(presenter_class.configuration[:title][:info]).to eq "Project"
|
79
|
+
end
|
80
|
+
|
81
|
+
it "stores options" do
|
82
|
+
presenter_class.title "Project", nodoc: true
|
83
|
+
expect(presenter_class.configuration[:title][:nodoc]).to be true
|
84
|
+
end
|
85
|
+
|
86
|
+
it "is not inherited" do
|
87
|
+
presenter_class.title "Project"
|
88
|
+
subclass = Class.new(presenter_class)
|
89
|
+
expect(subclass.configuration).not_to have_key :title
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe 'the description method' do
|
94
|
+
it "is stored in the configuration" do
|
95
|
+
presenter_class.description "desc 123"
|
96
|
+
expect(presenter_class.configuration[:description][:info]).to eq "desc 123"
|
97
|
+
end
|
98
|
+
|
99
|
+
it "stores options" do
|
100
|
+
presenter_class.description "Project", nodoc: true
|
101
|
+
expect(presenter_class.configuration[:description][:nodoc]).to be true
|
102
|
+
end
|
103
|
+
|
104
|
+
it "is not inherited" do
|
105
|
+
presenter_class.description "desc 123"
|
106
|
+
subclass = Class.new(presenter_class)
|
107
|
+
expect(subclass.configuration).not_to have_key :description
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe 'the nodoc! method' do
|
112
|
+
before do
|
113
|
+
presenter_class.nodoc!
|
114
|
+
end
|
115
|
+
|
116
|
+
it "is stored in the configuration" do
|
117
|
+
expect(presenter_class.configuration[:nodoc]).to be true
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
# sort_order :created_at, ".created_at"
|
123
|
+
describe 'the sort_order block' do
|
124
|
+
let(:value) { "widgets.created_at" }
|
125
|
+
let(:orders) { presenter_class.configuration[:sort_orders] }
|
126
|
+
|
127
|
+
context "when passed value is a column" do
|
128
|
+
before do
|
129
|
+
presenter_class.sort_order :created_at, value, info: "sorts by creation time"
|
130
|
+
end
|
131
|
+
|
132
|
+
it "is stored in the configuration by name" do
|
133
|
+
expect(orders).to have_key "created_at"
|
134
|
+
end
|
135
|
+
|
136
|
+
it "stores the value passed" do
|
137
|
+
expect(orders[:created_at][:value]).to eq "widgets.created_at"
|
138
|
+
end
|
139
|
+
|
140
|
+
it "stores the documentation" do
|
141
|
+
expect(orders[:created_at][:info]).to eq "sorts by creation time"
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
context "when passed value is a block" do
|
146
|
+
let(:value) { Proc.new { nil } }
|
147
|
+
|
148
|
+
before do
|
149
|
+
presenter_class.sort_order :created_at, info: "sorts by creation time", &value
|
150
|
+
end
|
151
|
+
|
152
|
+
it "stores the value passed" do
|
153
|
+
expect(orders[:created_at][:value]).to eq value
|
154
|
+
end
|
155
|
+
|
156
|
+
it "stores the documentation" do
|
157
|
+
expect(orders[:created_at][:info]).to eq "sorts by creation time"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
|
65
163
|
describe 'the conditional block' do
|
66
164
|
before do
|
67
165
|
presenter_class.conditionals do
|
68
|
-
model :title_is_hello, lambda { |workspace| workspace.title == 'hello' }, 'visible when the title is hello'
|
69
|
-
request :user_is_bob, lambda { current_user == 'bob' }, 'visible only to bob'
|
166
|
+
model :title_is_hello, lambda { |workspace| workspace.title == 'hello' }, info: 'visible when the title is hello', nodoc: true
|
167
|
+
request :user_is_bob, lambda { current_user == 'bob' }, info: 'visible only to bob'
|
70
168
|
end
|
71
169
|
end
|
72
170
|
|
@@ -75,6 +173,7 @@ describe Brainstem::Concerns::PresenterDSL do
|
|
75
173
|
expect(presenter_class.configuration[:conditionals][:title_is_hello].action).to be_present
|
76
174
|
expect(presenter_class.configuration[:conditionals][:title_is_hello].type).to eq :model
|
77
175
|
expect(presenter_class.configuration[:conditionals][:title_is_hello].description).to eq 'visible when the title is hello'
|
176
|
+
expect(presenter_class.configuration[:conditionals][:title_is_hello].options).to eq({ nodoc: true, info: 'visible when the title is hello' })
|
78
177
|
expect(presenter_class.configuration[:conditionals][:user_is_bob].action).to be_present
|
79
178
|
expect(presenter_class.configuration[:conditionals][:user_is_bob].type).to eq :request
|
80
179
|
expect(presenter_class.configuration[:conditionals][:user_is_bob].description).to eq 'visible only to bob'
|
@@ -83,13 +182,30 @@ describe Brainstem::Concerns::PresenterDSL do
|
|
83
182
|
it 'is inherited and overridable' do
|
84
183
|
subclass = Class.new(presenter_class)
|
85
184
|
subclass.conditionals do
|
86
|
-
model :silly_conditional, lambda { rand > 0.5 }, 'visible half the time'
|
87
|
-
model :title_is_hello, lambda { |workspace| workspace.title == 'HELLO' }, 'visible when the title is hello (in all caps)'
|
185
|
+
model :silly_conditional, lambda { rand > 0.5 }, info: 'visible half the time'
|
186
|
+
model :title_is_hello, lambda { |workspace| workspace.title == 'HELLO' }, info: 'visible when the title is hello (in all caps)'
|
88
187
|
end
|
89
188
|
expect(presenter_class.configuration[:conditionals].keys).to eq %w[title_is_hello user_is_bob]
|
90
189
|
expect(subclass.configuration[:conditionals].keys).to eq %w[title_is_hello user_is_bob silly_conditional]
|
91
190
|
expect(presenter_class.configuration[:conditionals][:title_is_hello].description).to eq "visible when the title is hello"
|
191
|
+
expect(presenter_class.configuration[:conditionals][:title_is_hello].options).to eq({ nodoc: true, info: "visible when the title is hello" })
|
92
192
|
expect(subclass.configuration[:conditionals][:title_is_hello].description).to eq "visible when the title is hello (in all caps)"
|
193
|
+
expect(subclass.configuration[:conditionals][:title_is_hello].options).to eq({ info: "visible when the title is hello (in all caps)" })
|
194
|
+
end
|
195
|
+
|
196
|
+
context 'when options hash is a hash with indifferent access' do
|
197
|
+
before do
|
198
|
+
presenter_class.conditionals do
|
199
|
+
request :user_is_jane, lambda { current_user == 'jane' }, { info: 'visible only to Jane' }.with_indifferent_access
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'is stored in the configuration correctly' do
|
204
|
+
expect(presenter_class.configuration[:conditionals].keys).to include('user_is_jane')
|
205
|
+
expect(presenter_class.configuration[:conditionals][:user_is_jane].action).to be_present
|
206
|
+
expect(presenter_class.configuration[:conditionals][:user_is_jane].type).to eq :request
|
207
|
+
expect(presenter_class.configuration[:conditionals][:user_is_jane].description).to eq 'visible only to Jane'
|
208
|
+
end
|
93
209
|
end
|
94
210
|
end
|
95
211
|
|
@@ -103,7 +219,8 @@ describe Brainstem::Concerns::PresenterDSL do
|
|
103
219
|
if: [:user_is_bob, :title_is_hello]
|
104
220
|
|
105
221
|
with_options if: :user_is_bob do
|
106
|
-
field :bob_title, :string,
|
222
|
+
field :bob_title, :string,
|
223
|
+
info: 'another name for the title, only for Bob',
|
107
224
|
via: :title
|
108
225
|
end
|
109
226
|
fields :nested_permissions do
|
@@ -125,7 +242,11 @@ describe Brainstem::Concerns::PresenterDSL do
|
|
125
242
|
expect(presenter_class.configuration[:fields][:secret].options).to eq({ via: :secret_info, if: [:user_is_bob, :title_is_hello] })
|
126
243
|
expect(presenter_class.configuration[:fields][:bob_title].type).to eq :string
|
127
244
|
expect(presenter_class.configuration[:fields][:bob_title].description).to eq 'another name for the title, only for Bob'
|
128
|
-
expect(presenter_class.configuration[:fields][:bob_title].options).to eq(
|
245
|
+
expect(presenter_class.configuration[:fields][:bob_title].options).to eq(
|
246
|
+
via: :title,
|
247
|
+
if: [:user_is_bob],
|
248
|
+
info: 'another name for the title, only for Bob'
|
249
|
+
)
|
129
250
|
end
|
130
251
|
|
131
252
|
it 'handles nesting' do
|
@@ -139,7 +260,7 @@ describe Brainstem::Concerns::PresenterDSL do
|
|
139
260
|
subclass.fields do
|
140
261
|
field :title, :string
|
141
262
|
with_options if: [:some_condition, :some_other_condition] do
|
142
|
-
field :updated_at, :datetime, 'this time I have a description and condition'
|
263
|
+
field :updated_at, :datetime, info: 'this time I have a description and condition'
|
143
264
|
end
|
144
265
|
end
|
145
266
|
expect(presenter_class.configuration[:fields].keys).to match_array %w[updated_at dynamic_title secret bob_title nested_permissions]
|
@@ -147,24 +268,32 @@ describe Brainstem::Concerns::PresenterDSL do
|
|
147
268
|
expect(presenter_class.configuration[:fields][:updated_at].description).to be_nil
|
148
269
|
expect(presenter_class.configuration[:fields][:updated_at].options).to eq({})
|
149
270
|
expect(subclass.configuration[:fields][:updated_at].description).to eq 'this time I have a description and condition'
|
150
|
-
expect(subclass.configuration[:fields][:updated_at].options).to eq(
|
271
|
+
expect(subclass.configuration[:fields][:updated_at].options).to eq(
|
272
|
+
if: [:some_condition, :some_other_condition],
|
273
|
+
info: 'this time I have a description and condition'
|
274
|
+
)
|
151
275
|
end
|
152
276
|
|
153
277
|
it 'any :if options are combined and inherited using with_options' do
|
154
278
|
presenter_class.fields do
|
155
279
|
with_options if: :user_is_bob do
|
156
|
-
field :bob_title, :string,
|
157
|
-
|
158
|
-
|
280
|
+
field :bob_title, :string,
|
281
|
+
info: 'another name for the title, only for Bob',
|
282
|
+
via: :title,
|
283
|
+
if: :another_condition
|
284
|
+
field :bob_title2, :string,
|
285
|
+
info: 'another name for the title, only for Bob',
|
159
286
|
via: :title, if: :another_condition
|
160
287
|
end
|
161
288
|
end
|
162
289
|
subclass = Class.new(presenter_class)
|
163
290
|
subclass.fields do
|
164
291
|
with_options if: [:user_is_bob, :more_specific] do
|
165
|
-
field :bob_title, :string,
|
292
|
+
field :bob_title, :string,
|
293
|
+
info: 'another name for the title, only for Bob',
|
166
294
|
via: :title, if: [:another_condition]
|
167
|
-
field :bob_title2, :string,
|
295
|
+
field :bob_title2, :string,
|
296
|
+
info: 'another name for the title, only for Bob',
|
168
297
|
via: :title
|
169
298
|
end
|
170
299
|
end
|
@@ -206,14 +335,30 @@ describe Brainstem::Concerns::PresenterDSL do
|
|
206
335
|
expect(subclass.configuration[:fields][:nested_permissions][:deeper][:something]).to be_present
|
207
336
|
expect(subclass.configuration[:fields][:new_nested_permissions]).to be_present
|
208
337
|
end
|
338
|
+
|
339
|
+
context "when options is a hash with indifferent access" do
|
340
|
+
before do
|
341
|
+
presenter_class.fields do
|
342
|
+
field :synced_at, :datetime, { info: "Last time the object was synced" }.with_indifferent_access
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
it "is stored in the configuration correctly" do
|
347
|
+
expect(presenter_class.configuration[:fields].keys).to include('synced_at')
|
348
|
+
expect(presenter_class.configuration[:fields][:synced_at].type).to eq :datetime
|
349
|
+
expect(presenter_class.configuration[:fields][:synced_at].description).to eq 'Last time the object was synced'
|
350
|
+
end
|
351
|
+
end
|
209
352
|
end
|
210
353
|
|
211
354
|
describe 'the associations block' do
|
212
355
|
before do
|
213
356
|
presenter_class.associations do
|
214
|
-
association :tasks, Task,
|
357
|
+
association :tasks, Task,
|
358
|
+
info: 'The Tasks in this Workspace',
|
215
359
|
restrict_to_only: true
|
216
|
-
association :subtasks, Task,
|
360
|
+
association :subtasks, Task,
|
361
|
+
info: 'Only Tasks in this Workspace that are subtasks',
|
217
362
|
dynamic: lambda { |workspace| workspace.tasks.where('parent_id IS NOT NULL') }
|
218
363
|
association :something, :polymorphic
|
219
364
|
end
|
@@ -223,10 +368,10 @@ describe Brainstem::Concerns::PresenterDSL do
|
|
223
368
|
expect(presenter_class.configuration[:associations].keys).to match_array %w[tasks subtasks something]
|
224
369
|
expect(presenter_class.configuration[:associations][:tasks].target_class).to eq Task
|
225
370
|
expect(presenter_class.configuration[:associations][:tasks].description).to eq 'The Tasks in this Workspace'
|
226
|
-
expect(presenter_class.configuration[:associations][:tasks].options).to eq({ restrict_to_only: true })
|
371
|
+
expect(presenter_class.configuration[:associations][:tasks].options).to eq({ restrict_to_only: true, info: 'The Tasks in this Workspace' })
|
227
372
|
expect(presenter_class.configuration[:associations][:subtasks].target_class).to eq Task
|
228
373
|
expect(presenter_class.configuration[:associations][:subtasks].description).to eq 'Only Tasks in this Workspace that are subtasks'
|
229
|
-
expect(presenter_class.configuration[:associations][:subtasks].options.keys).to
|
374
|
+
expect(presenter_class.configuration[:associations][:subtasks].options.keys).to match_array [:dynamic, :info]
|
230
375
|
expect(presenter_class.configuration[:associations][:something].target_class).to eq :polymorphic
|
231
376
|
expect(presenter_class.configuration[:associations][:something].description).to be_nil
|
232
377
|
end
|
@@ -234,20 +379,37 @@ describe Brainstem::Concerns::PresenterDSL do
|
|
234
379
|
it 'is inherited and overridable' do
|
235
380
|
subclass = Class.new(presenter_class)
|
236
381
|
subclass.associations do
|
237
|
-
association :tasks, Task, 'The Tasks in this Workspace'
|
238
|
-
association :lead_user, User, 'The user who runs this Workspace'
|
382
|
+
association :tasks, Task, info: 'The Tasks in this Workspace'
|
383
|
+
association :lead_user, User, info: 'The user who runs this Workspace'
|
239
384
|
end
|
240
385
|
|
241
386
|
expect(presenter_class.configuration[:associations].keys).to match_array %w[tasks subtasks something]
|
242
387
|
expect(subclass.configuration[:associations].keys).to match_array %w[tasks subtasks lead_user something]
|
243
388
|
|
244
|
-
expect(presenter_class.configuration[:associations][:tasks].options).to eq({ restrict_to_only: true })
|
389
|
+
expect(presenter_class.configuration[:associations][:tasks].options).to eq({ restrict_to_only: true, info: 'The Tasks in this Workspace' })
|
245
390
|
expect(presenter_class.configuration[:associations][:lead_user]).to be_nil
|
246
391
|
|
247
|
-
expect(subclass.configuration[:associations][:tasks].options).to eq({})
|
392
|
+
expect(subclass.configuration[:associations][:tasks].options).to eq({ info: 'The Tasks in this Workspace' })
|
248
393
|
expect(subclass.configuration[:associations][:lead_user].target_class).to eq User
|
249
394
|
expect(subclass.configuration[:associations][:lead_user].description).to eq 'The user who runs this Workspace'
|
250
395
|
end
|
396
|
+
|
397
|
+
context "when options is a hash with indifferent access" do
|
398
|
+
before do
|
399
|
+
presenter_class.associations do
|
400
|
+
association :something_else, :polymorphic, { info: 'The other things in this Workspace', restrict_to_only: true }.with_indifferent_access
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
it "is stored in the configuration correctly" do
|
405
|
+
expect(presenter_class.configuration[:associations].keys).to include('something_else')
|
406
|
+
expect(presenter_class.configuration[:associations][:something_else].description).to eq 'The other things in this Workspace'
|
407
|
+
expect(presenter_class.configuration[:associations][:something_else].options).to eq(
|
408
|
+
info: 'The other things in this Workspace',
|
409
|
+
restrict_to_only: true
|
410
|
+
)
|
411
|
+
end
|
412
|
+
end
|
251
413
|
end
|
252
414
|
|
253
415
|
describe ".helper" do
|
@@ -373,16 +535,25 @@ describe Brainstem::Concerns::PresenterDSL do
|
|
373
535
|
end
|
374
536
|
|
375
537
|
describe ".filter" do
|
538
|
+
let(:foo) { presenter_class.configuration[:filters][:foo] }
|
539
|
+
|
376
540
|
it "creates an entry in the filters configuration" do
|
377
|
-
|
378
|
-
|
379
|
-
|
541
|
+
my_proc = Proc.new { 1 }
|
542
|
+
presenter_class.filter(:foo, :default => true, &my_proc)
|
543
|
+
|
544
|
+
expect(foo).to eq({ "default" => true, "value" => my_proc })
|
380
545
|
end
|
381
546
|
|
382
547
|
it "accepts names without blocks" do
|
383
548
|
presenter_class.filter(:foo)
|
384
|
-
expect(
|
549
|
+
expect(foo[:value]).to be_nil
|
550
|
+
end
|
551
|
+
|
552
|
+
it "records the info option" do
|
553
|
+
presenter_class.filter(:foo, :info => "This is documented.")
|
554
|
+
expect(foo[:info]).to eq "This is documented."
|
385
555
|
end
|
556
|
+
|
386
557
|
end
|
387
558
|
|
388
559
|
describe ".search" do
|