excalibur 0.0.2
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 +7 -0
- data/.gitignore +22 -0
- data/.rspec +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +162 -0
- data/Rakefile +2 -0
- data/excalibur.gemspec +32 -0
- data/lib/excalibur/configuration.rb +77 -0
- data/lib/excalibur/decorator.rb +55 -0
- data/lib/excalibur/duplicator.rb +19 -0
- data/lib/excalibur/railtie.rb +15 -0
- data/lib/excalibur/truncatable_content.rb +82 -0
- data/lib/excalibur/version.rb +4 -0
- data/lib/excalibur/view_helpers.rb +59 -0
- data/lib/excalibur.rb +91 -0
- data/lib/generators/excalibur/decorator_generator.rb +18 -0
- data/lib/generators/excalibur/install_generator.rb +18 -0
- data/lib/generators/templates/decorator.rb +75 -0
- data/lib/generators/templates/excalibur.rb +151 -0
- data/spec/lib/excalibur/configuration_spec.rb +215 -0
- data/spec/lib/excalibur/decorator_spec.rb +224 -0
- data/spec/lib/excalibur/duplicator_spec.rb +49 -0
- data/spec/lib/excalibur/truncatable_content_spec.rb +192 -0
- data/spec/lib/excalibur/view_helper_spec.rb +87 -0
- data/spec/lib/excalibur_spec.rb +85 -0
- data/spec/lib/generators/excalibur/decorator_generator_spec.rb +28 -0
- data/spec/lib/generators/excalibur/install_generator_spec.rb +30 -0
- data/spec/spec_helper.rb +80 -0
- metadata +219 -0
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rails/generators/base'
|
2
|
+
|
3
|
+
module Excalibur
|
4
|
+
module Generators
|
5
|
+
# the install generator allows you to get a free to use and fully
|
6
|
+
# documented initializer file for your rails app by running:
|
7
|
+
# rails g excalibur:install
|
8
|
+
class InstallGenerator < Rails::Generators::Base
|
9
|
+
source_root File.expand_path('../../templates', __FILE__)
|
10
|
+
|
11
|
+
desc 'Creates a Excalibur initializer.'
|
12
|
+
|
13
|
+
def copy_initializer
|
14
|
+
template 'excalibur.rb', 'config/initializers/excalibur.rb'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
class Excalibur::<%= class_name %>Decorator < Excalibur::Decorator
|
2
|
+
# ==> Full custom configuration
|
3
|
+
# it is possible to force a new config onto over the application wide
|
4
|
+
# default set in the initializer.
|
5
|
+
#
|
6
|
+
# You can pass a custom configuration in like so:
|
7
|
+
# excalibur_init @my_custom_config
|
8
|
+
#
|
9
|
+
# or start with a blank configuration like so:
|
10
|
+
# excalibur_init Excalibur::Configuration.new
|
11
|
+
#
|
12
|
+
# The last method is easiest as all configuration options are available in
|
13
|
+
# this decorator through a DSL instead of building the object from scratch.
|
14
|
+
|
15
|
+
# ==> Title and Description settings
|
16
|
+
# Titles and descriptions act mostly the same way within Excalibur. They
|
17
|
+
# share the same DSL with the small difference in method name. Below the
|
18
|
+
# description is for title but it applies to description as well.
|
19
|
+
#
|
20
|
+
# => Set content
|
21
|
+
# the excalibur_set_title_content method takes two parameters to change the
|
22
|
+
# content of a title. By defaults you can set a :prefix, :body and :suffix.
|
23
|
+
# All of these can be a string or a Proc.
|
24
|
+
#
|
25
|
+
# as an example:
|
26
|
+
# excalibur_set_title_content :body, 'my class specific title body'
|
27
|
+
#
|
28
|
+
# => Set option
|
29
|
+
# the excalibur_set_title_option method takes two arguments to change the
|
30
|
+
# options of a title. By defaults you can set a :length, :omission and
|
31
|
+
# :separator.
|
32
|
+
#
|
33
|
+
# :length takes any integer to indicate the length limit of the title.
|
34
|
+
# :omission is what fills the end of the line when the body is truncated
|
35
|
+
# below the limited length of the title :body.
|
36
|
+
# :separator determines what character the :body will be truncated on. with
|
37
|
+
# a single space (' ') it will break on words and with no-space ('') it
|
38
|
+
# will break on any character.
|
39
|
+
#
|
40
|
+
# as an examples:
|
41
|
+
# excalibur_set_title_content :length, 42
|
42
|
+
# excalibur_set_title_content :omission, '... (continued)'
|
43
|
+
#
|
44
|
+
# => set combinator
|
45
|
+
# the excalibur_set_title_combinator takes one argument and it should be a
|
46
|
+
# Proc. The proc is passed the decorated object so you have access to the
|
47
|
+
# object and the configuration of required. It needs to result in a string.
|
48
|
+
#
|
49
|
+
# excalibur_set_title_combinator(proc { |obj|
|
50
|
+
# # your code here
|
51
|
+
# })
|
52
|
+
|
53
|
+
# ==> Meta tag settings
|
54
|
+
# the excalibur_set_meta_tag method takes three arguments to set the content
|
55
|
+
# for a meta tag. The first and second arguments are about the type of meta
|
56
|
+
# tag while the third is used for the content.
|
57
|
+
#
|
58
|
+
# A description meta tag would look like this:
|
59
|
+
# excalibur_set_meta_tag :name, :description, 'Some description content'
|
60
|
+
#
|
61
|
+
# The content of a meta tag can be anything that prints nicely into a
|
62
|
+
# string, a Proc or an Array. The Proc may also result in an array and is
|
63
|
+
# passed the decorated object for access to the objects attributes and the
|
64
|
+
# excalibur configuration acting for the object.
|
65
|
+
|
66
|
+
# ==> Recommended use
|
67
|
+
# Because the title, description and the meta tags all allow for a Proc to
|
68
|
+
# be passed it gives you a lot of freedom. However like any freedom it is to
|
69
|
+
# be used with some warning. It is recommended when doing larger amounts of
|
70
|
+
# work in code of a proc to use the decorator to delegate that
|
71
|
+
# responsibility. The decorator becomes easier to test and it is also a lot
|
72
|
+
# cleaner.
|
73
|
+
#
|
74
|
+
# TODO: An article about how to do it properly will come soon!
|
75
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
# Use this to set up your default
|
2
|
+
Excalibur.configure do |config|
|
3
|
+
# ==> Your sane defaults:
|
4
|
+
|
5
|
+
# => Title content
|
6
|
+
# config.title.update_content :prefix, 'prefix - '
|
7
|
+
config.title.update_content :body, 'My website has a title by Excalibur'
|
8
|
+
|
9
|
+
# => Title options
|
10
|
+
# config.title.update_option :length, 69
|
11
|
+
# config.title.update_option :omission, '...'
|
12
|
+
# config.title.update_option :separator, ''
|
13
|
+
|
14
|
+
# => Description content
|
15
|
+
config.description.update_content :body, 'Excalibur gave me a description!'
|
16
|
+
|
17
|
+
# => Description options
|
18
|
+
# config.description.update_option :length, 155
|
19
|
+
# config.description.update_option :omission, '...'
|
20
|
+
# config.description.update_option :separator, ' '
|
21
|
+
|
22
|
+
# => Meta tags
|
23
|
+
config.set_meta_tag :name, :viewport, 'width=device-width, initial-scale=1'
|
24
|
+
|
25
|
+
# ==> Configuration DSL:
|
26
|
+
#
|
27
|
+
# Both the title and description are configurable in the same way;
|
28
|
+
# config.title for the title and config.description for the description.
|
29
|
+
# They both consist out of three elements; content, options and the
|
30
|
+
# combinator. The meta tags have their own interface as they are slightly
|
31
|
+
# different. Both the content in the title/description and the content in
|
32
|
+
# the meta tags can be given a Proc in order for on-render computation to
|
33
|
+
# occur.
|
34
|
+
|
35
|
+
# => Title/Description content
|
36
|
+
# The default of the gem tries to combine 3 parts; :prefix,
|
37
|
+
# :body and :suffix. They are put together in that order by the default
|
38
|
+
# combinator.
|
39
|
+
#
|
40
|
+
# To set these add:
|
41
|
+
# config.title.update_content :prefix, 'CNN.com - '
|
42
|
+
# config.title.update_content :body, 'Breaking, World, Business, Sports and
|
43
|
+
# Entertainment News'
|
44
|
+
#
|
45
|
+
# this will result in a title like 'CNN.com - Breaking, World, Business,
|
46
|
+
# Sports and Entertainment News'
|
47
|
+
#
|
48
|
+
# > Title Defaults:
|
49
|
+
# prefix: ''
|
50
|
+
# body: 'Excalibur'
|
51
|
+
# suffix: ''
|
52
|
+
#
|
53
|
+
# > Description Defaults:
|
54
|
+
# prefix: ''
|
55
|
+
# body: 'Excalibur; a worthy title for a gem about titles.'
|
56
|
+
# suffix: ''
|
57
|
+
|
58
|
+
# => Title/Description options
|
59
|
+
# The default of the gem uses the options to truncate the content
|
60
|
+
# components in the correct way. :length is the length the content will be
|
61
|
+
# truncated to. :omission is used to indicate that the content is truncated
|
62
|
+
# and is added behind the section that has been truncated. :separator
|
63
|
+
# determines if truncation happens on a character or not,
|
64
|
+
# '' for every letter and ' ' for a space as it allows for breaking on words
|
65
|
+
# or characters.
|
66
|
+
#
|
67
|
+
# To set these add:
|
68
|
+
# config.title.update_option :length, 42
|
69
|
+
# config.title.update_option :omission, '... (continued)'
|
70
|
+
#
|
71
|
+
# > Title Defaults:
|
72
|
+
# length: 69
|
73
|
+
# omission: '...'
|
74
|
+
# separator: ''
|
75
|
+
#
|
76
|
+
# > Description Defaults:
|
77
|
+
# length: 155
|
78
|
+
# omission: '...'
|
79
|
+
# separator: ' '
|
80
|
+
|
81
|
+
# => Title/Description combinator
|
82
|
+
# The combinator is by default a proc that combines the content elements
|
83
|
+
# together and truncates them according to what the options have specified.
|
84
|
+
# If your not into it yet the combinator is to be changed with caution.
|
85
|
+
#
|
86
|
+
# Change the combinator by:
|
87
|
+
# config.title.update_combinator(
|
88
|
+
# proc do |object|
|
89
|
+
# # your code here
|
90
|
+
# #
|
91
|
+
# # the object var is passed when rendering and contains an object
|
92
|
+
# # with the current configuration for that render. It's advised when
|
93
|
+
# # using data from that configuration to use object.configuration to
|
94
|
+
# # access it.
|
95
|
+
# end
|
96
|
+
# )
|
97
|
+
#
|
98
|
+
# > Default behavior
|
99
|
+
# By default the combinator takes the 3 content sections but only truncates
|
100
|
+
# the :body section. This does take into account the length of the :prefix
|
101
|
+
# and :suffix when truncating the content so the overall length of the
|
102
|
+
# title stays within the length set in the options.
|
103
|
+
#
|
104
|
+
# > Title/Description configuration examples:
|
105
|
+
# content:
|
106
|
+
# prefix: 'Excalibur | '
|
107
|
+
# body: 'The Object oriented way of setting SEO and meta information'
|
108
|
+
# options:
|
109
|
+
# length: 69
|
110
|
+
# omission: '...'
|
111
|
+
# separator: ''
|
112
|
+
# result: 'Excalibur | The Object oriented way of setting SEO and meta
|
113
|
+
# inform...'
|
114
|
+
#
|
115
|
+
# options:
|
116
|
+
# separator: ' '
|
117
|
+
# result: 'Excalibur | The Object oriented way of setting SEO and meta...'
|
118
|
+
#
|
119
|
+
# content:
|
120
|
+
# body: 'Just another website'
|
121
|
+
# suffix: ' - site ID'
|
122
|
+
# result: 'Just another website - site ID'
|
123
|
+
|
124
|
+
# => Meta tags
|
125
|
+
# Meta tags are basically represented in the configuration as a double
|
126
|
+
# layered hash. The hash is converted to meta tags types and the values are
|
127
|
+
# the content of the meta tag.
|
128
|
+
#
|
129
|
+
# These can be easily set using:
|
130
|
+
# config.set_meta_tag(
|
131
|
+
# :name,
|
132
|
+
# :viewport,
|
133
|
+
# 'width=device-width, initial-scale=1')
|
134
|
+
|
135
|
+
# => General configuration:
|
136
|
+
# it is possible to roll your own configuration without using the accessors
|
137
|
+
# provided in the DSL. You can use the Excalibur::Configuration class to
|
138
|
+
# create your own config. Have a look at the code how to do so!
|
139
|
+
#
|
140
|
+
# you can set it by simply:
|
141
|
+
# config = MyCustomConfiguration.new
|
142
|
+
#
|
143
|
+
# If you want to keep using parts of the default configuration but want to
|
144
|
+
# replace others configuration has a #merge! method to merge another
|
145
|
+
# Excalibur::Configuration object into the default. Note that this will only
|
146
|
+
# work if the supplied object is a Excalibur::Configuration or an inherited
|
147
|
+
# object.
|
148
|
+
#
|
149
|
+
# use this by:
|
150
|
+
# config.merge!(MyCustomConfiguration.new)
|
151
|
+
end
|
@@ -0,0 +1,215 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Excalibur
|
4
|
+
describe Configuration do
|
5
|
+
describe '#new' do
|
6
|
+
context 'when creating a configuration without parameters' do
|
7
|
+
let(:config) { Configuration.new }
|
8
|
+
|
9
|
+
it 'should create a title' do
|
10
|
+
expect(config.title).to be_instance_of TruncateableContent
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should create a describe' do
|
14
|
+
expect(config.description).to be_instance_of TruncateableContent
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should create an empty meta tags hash' do
|
18
|
+
expect(config.meta_tags).to be_instance_of ::HashWithIndifferentAccess
|
19
|
+
expect(config.meta_tags).to be_empty
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'when supplying parameters' do
|
24
|
+
let(:config) { Configuration.new('foo', 'bar', 'baz') }
|
25
|
+
|
26
|
+
it 'should set the right values' do
|
27
|
+
expect(config.title).to eq('foo')
|
28
|
+
expect(config.description).to eq('bar')
|
29
|
+
expect(config.meta_tags).to eq('baz')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '#merge!' do
|
35
|
+
context 'when trying to merge with the wrong type of object' do
|
36
|
+
let(:obj) { Configuration.new }
|
37
|
+
|
38
|
+
it 'should raise a TypeError' do
|
39
|
+
expect { obj.merge!('foo') }.to raise_error(TypeError, 'can only merge two Excalibur::Configuration objects')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'when merging two configurations' do
|
44
|
+
let(:obj_a) { Configuration.new(TruncateableContent.new, TruncateableContent.new) }
|
45
|
+
let(:obj_b) { Configuration.new(TruncateableContent.new, false, nil) }
|
46
|
+
|
47
|
+
context 'instance result' do
|
48
|
+
after do
|
49
|
+
obj_a.merge!(obj_b)
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should merge the instance variables' do
|
53
|
+
expect(obj_a).to receive(:merge_instance).exactly(3).times
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'function result' do
|
58
|
+
it 'should return itself' do
|
59
|
+
expect(obj_a.merge!(obj_b)).to be_instance_of Configuration
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe 'when merging content merging' do
|
65
|
+
let(:a) { 'foobar' }
|
66
|
+
let(:b) { 'baz' }
|
67
|
+
let(:config) { Configuration.new(a) }
|
68
|
+
let(:new_config) { Configuration.new(b) }
|
69
|
+
|
70
|
+
before do
|
71
|
+
config.merge!(new_config)
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'when the objects are different classes' do
|
75
|
+
context 'when the new object is nil' do
|
76
|
+
let(:new_config) { Configuration.new(nil) }
|
77
|
+
|
78
|
+
it 'should not change the config variable' do
|
79
|
+
expect( config.title ).to eq(config.title)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'when the new object is a value' do
|
84
|
+
let(:new_config) { Configuration.new(true) }
|
85
|
+
|
86
|
+
it 'should change the config variable' do
|
87
|
+
expect( config.title ).to eq(true)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'when the objects are the same class' do
|
93
|
+
context 'when merging two hashes' do
|
94
|
+
let(:a) { {foo: {bar: 'baz', other: 'old'}} }
|
95
|
+
let(:b) { {foo: {other: 'new'}} }
|
96
|
+
|
97
|
+
it 'should deep merge the two hashes' do
|
98
|
+
expect(config.title).to eq( { foo: {bar: 'baz', other: 'new'} } )
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context 'when merging two TruncatableContent' do
|
103
|
+
let(:config) { Configuration.new }
|
104
|
+
let(:b) { TruncateableContent.new({foo: 'bar'}, {foo: 'bar'}, 'foobar') }
|
105
|
+
|
106
|
+
it 'should merge the two TruncatableContent' do
|
107
|
+
expect(config.title.content).to eq( b.content )
|
108
|
+
expect(config.title.options).to eq( b.options )
|
109
|
+
expect(config.title.combinator).to eq( b.combinator )
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
context 'when merging two strings' do
|
114
|
+
let(:a) { 'foo' }
|
115
|
+
let(:b) { 'bar' }
|
116
|
+
|
117
|
+
it 'should concatenate the two strings' do
|
118
|
+
expect(config.title).to eq('foobar')
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
context 'when merging something else' do
|
123
|
+
let(:a) { true }
|
124
|
+
let(:b) { false }
|
125
|
+
|
126
|
+
it 'should replace it' do
|
127
|
+
expect(config.title).to eq(false)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe '#dup' do
|
135
|
+
it 'should create a duplicate of the object and the attributes' do
|
136
|
+
expect(Excalibur.configuration.title).to receive(:dup)
|
137
|
+
expect(Excalibur.configuration.description).to receive(:dup)
|
138
|
+
expect(Excalibur.configuration.meta_tags).to receive(:dup)
|
139
|
+
|
140
|
+
Excalibur.configuration.dup
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'should create a duplicate of the object and the attributes' do
|
144
|
+
expect(Excalibur.configuration).to receive(:dup_instance).exactly(3).times
|
145
|
+
|
146
|
+
Excalibur.configuration.dup
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
describe '#set_meta_tag' do
|
151
|
+
let(:config) do
|
152
|
+
c = Configuration.new
|
153
|
+
c.meta_tags = ::HashWithIndifferentAccess.new( name: ::HashWithIndifferentAccess.new( description: 'old' ) )
|
154
|
+
c
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'should overwrite a tag' do
|
158
|
+
config.set_meta_tag(:name, :description, 'Description content')
|
159
|
+
|
160
|
+
expect(config.meta_tags).to eq(::HashWithIndifferentAccess.new(
|
161
|
+
name: ::HashWithIndifferentAccess.new( description: 'Description content' ))
|
162
|
+
)
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'should create a new tag type when required' do
|
166
|
+
config.set_meta_tag(:foo, :bar, 'baz')
|
167
|
+
|
168
|
+
expect(config.meta_tags).to have_key(:foo)
|
169
|
+
expect(config.meta_tags[:foo]).to have_key(:bar)
|
170
|
+
expect(config.meta_tags[:foo]).to be_instance_of ::HashWithIndifferentAccess
|
171
|
+
expect(config.meta_tags[:foo][:bar]).to eq('baz')
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
describe '#remove_meta_tag' do
|
176
|
+
let(:config) do
|
177
|
+
c = Configuration.new
|
178
|
+
c.meta_tags = {
|
179
|
+
name: {
|
180
|
+
description: 'content',
|
181
|
+
other: 'content'
|
182
|
+
},
|
183
|
+
foo: {
|
184
|
+
bar: 'baz'
|
185
|
+
}
|
186
|
+
}
|
187
|
+
c
|
188
|
+
end
|
189
|
+
|
190
|
+
context 'when the type still has values left' do
|
191
|
+
before do
|
192
|
+
config.remove_meta_tag(:name, :other)
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'should have removed the name' do
|
196
|
+
expect(config.meta_tags[:name]).to_not have_key(:other)
|
197
|
+
end
|
198
|
+
|
199
|
+
it 'should still have the type' do
|
200
|
+
expect(config.meta_tags).to have_key(:name)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
context 'when the type still has values left' do
|
205
|
+
before do
|
206
|
+
config.remove_meta_tag(:foo, :bar)
|
207
|
+
end
|
208
|
+
|
209
|
+
it 'should have removed the type' do
|
210
|
+
expect(config.meta_tags).to_not have_key(:foo)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
@@ -0,0 +1,224 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Excalibur
|
4
|
+
class Dummy; end
|
5
|
+
class DummyDecorator < Decorator; end
|
6
|
+
|
7
|
+
describe Decorator do
|
8
|
+
before do
|
9
|
+
Excalibur.reset
|
10
|
+
DummyDecorator.configuration = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
after do
|
14
|
+
DummyDecorator.configuration = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#new' do
|
18
|
+
context 'when creating it without options' do
|
19
|
+
let(:obj) { DummyDecorator.decorate(Dummy.new) }
|
20
|
+
|
21
|
+
it { expect(obj.context).to be_empty }
|
22
|
+
it { expect(obj.configuration).to be_present }
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'when creating it with options' do
|
26
|
+
context 'when providing context' do
|
27
|
+
let(:obj) { DummyDecorator.decorate(Dummy.new, context: {foo: 'bar'}) }
|
28
|
+
|
29
|
+
it { expect(obj.context).to_not be_empty }
|
30
|
+
it { expect(obj.context).to eq({foo: 'bar'}) }
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'when providing config' do
|
34
|
+
let(:config) { Configuration.new }
|
35
|
+
let(:obj) { DummyDecorator.decorate(Dummy.new, config: config) }
|
36
|
+
|
37
|
+
it 'should try and merge the configuration' do
|
38
|
+
expect_any_instance_of(Configuration).to receive(:merge!).with(config)
|
39
|
+
|
40
|
+
obj
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'when configuring a decorator with mixed methods' do
|
47
|
+
before do
|
48
|
+
DummyDecorator.configuration = nil
|
49
|
+
|
50
|
+
class DummyDecorator < Decorator
|
51
|
+
excalibur_set_meta_tag(:foo, :bar, proc { |obj| 'content' })
|
52
|
+
excalibur_set_meta_tag(:name, :other, 'content')
|
53
|
+
|
54
|
+
excalibur_set_title_content(:prefix, 'Exc / ')
|
55
|
+
excalibur_set_title_content(:body, 'title body')
|
56
|
+
excalibur_set_title_option(:length, 42)
|
57
|
+
excalibur_set_title_combinator proc{ |obj| "result #{obj}" }
|
58
|
+
|
59
|
+
excalibur_set_description_content(:body, 'title body')
|
60
|
+
excalibur_set_description_option(:length, 42)
|
61
|
+
excalibur_set_description_combinator proc{ |obj| "result #{obj}" }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
it { expect(DummyDecorator.configuration.meta_tags).to have_key(:name) }
|
66
|
+
it { expect(DummyDecorator.configuration.meta_tags[:name]).to have_key(:other) }
|
67
|
+
it { expect(DummyDecorator.configuration.meta_tags).to have_key(:foo) }
|
68
|
+
it { expect(DummyDecorator.configuration.meta_tags[:foo]).to have_key(:bar) }
|
69
|
+
|
70
|
+
it { expect(DummyDecorator.configuration.title.content[:prefix]).to eq 'Exc / ' }
|
71
|
+
it { expect(DummyDecorator.configuration.title.content[:body]).to eq 'title body' }
|
72
|
+
it { expect(DummyDecorator.configuration.title.options[:length]).to eq 42 }
|
73
|
+
it { expect(DummyDecorator.configuration.title.combinator).to be_instance_of Proc }
|
74
|
+
it { expect(DummyDecorator.configuration.title.combinator.call('foobar')).to eq('result foobar') }
|
75
|
+
|
76
|
+
it { expect(DummyDecorator.configuration.description.content[:body]).to eq 'title body' }
|
77
|
+
it { expect(DummyDecorator.configuration.description.options[:length]).to eq 42 }
|
78
|
+
it { expect(DummyDecorator.configuration.description.combinator).to be_instance_of Proc }
|
79
|
+
it { expect(DummyDecorator.configuration.description.combinator.call('foobar')).to eq('result foobar') }
|
80
|
+
end
|
81
|
+
|
82
|
+
describe '::excalibur_init' do
|
83
|
+
context 'when creating a decorator' do
|
84
|
+
context 'when setting the config without a value' do
|
85
|
+
before do
|
86
|
+
class DummyDecorator < Decorator
|
87
|
+
excalibur_init
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
it { expect(DummyDecorator.configuration).to be_present }
|
92
|
+
it { expect(DummyDecorator.configuration).to be_instance_of Configuration }
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'when setting the config with a value' do
|
96
|
+
before do
|
97
|
+
class DummyDecorator < Decorator
|
98
|
+
excalibur_init true
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
it { expect(DummyDecorator.configuration).to be_present }
|
103
|
+
it { expect(DummyDecorator.configuration).to eq(true) }
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe '::configuration' do
|
109
|
+
it 'should duplicate the system wide configuration' do
|
110
|
+
expect( Excalibur.configuration ).to receive(:dup)
|
111
|
+
|
112
|
+
DummyDecorator.configuration
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'should only duplicate the system wide configuration once' do
|
116
|
+
DummyDecorator.configuration
|
117
|
+
|
118
|
+
expect( Excalibur.configuration ).to_not receive(:dup)
|
119
|
+
|
120
|
+
DummyDecorator.configuration
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe '::excalibur_set' do
|
125
|
+
describe '_title' do
|
126
|
+
describe '_content' do
|
127
|
+
it 'should change the title content' do
|
128
|
+
expect {
|
129
|
+
DummyDecorator.excalibur_set_title_content(:foo, 'bar')
|
130
|
+
}.to change(DummyDecorator.configuration.title, :content).to(body: 'Excalibur', foo: 'bar')
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe '_option' do
|
135
|
+
it 'should change the title options' do
|
136
|
+
expect {
|
137
|
+
DummyDecorator.excalibur_set_title_option(:foo, 'bar')
|
138
|
+
}.to change(DummyDecorator.configuration.title, :options).to(length: 69, omission: '...', separator: '', foo: 'bar')
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
describe '_combinator' do
|
143
|
+
it 'should change the title combinator' do
|
144
|
+
expect {
|
145
|
+
DummyDecorator.excalibur_set_title_combinator(true)
|
146
|
+
}.to change(DummyDecorator.configuration.title, :combinator).to(true)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe '_description' do
|
152
|
+
describe '_content' do
|
153
|
+
it 'should change the description content' do
|
154
|
+
expect {
|
155
|
+
DummyDecorator.excalibur_set_description_content(:foo, 'bar')
|
156
|
+
}.to change(DummyDecorator.configuration.description, :content).to(body: 'Excalibur; a worthy title for a gem about titles.', foo: 'bar')
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
describe '_option' do
|
161
|
+
it 'should change the description options' do
|
162
|
+
expect {
|
163
|
+
DummyDecorator.excalibur_set_description_option(:foo, 'bar')
|
164
|
+
}.to change(DummyDecorator.configuration.description, :options).to(length: 155, omission: '...', separator: ' ', foo: 'bar')
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe '_combinator' do
|
169
|
+
it 'should change the description combinator' do
|
170
|
+
expect {
|
171
|
+
DummyDecorator.excalibur_set_description_combinator(true)
|
172
|
+
}.to change(DummyDecorator.configuration.description, :combinator).to(true)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
describe '_meta_tag' do
|
178
|
+
it 'should change the meta tags' do
|
179
|
+
expect(DummyDecorator.configuration).to receive(:set_meta_tag).with(:name, :description, 'foobar')
|
180
|
+
|
181
|
+
DummyDecorator.excalibur_set_meta_tag(:name, :description, 'foobar')
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe '#configuration' do
|
187
|
+
let(:obj) { DummyDecorator.decorate(Dummy.new) }
|
188
|
+
|
189
|
+
it "should duplicate the decorator's configuration" do
|
190
|
+
expect(obj.class.configuration).to receive(:dup)
|
191
|
+
|
192
|
+
obj.configuration
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'should return a configuration' do
|
196
|
+
expect(obj.configuration).to be_instance_of Configuration
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
describe '#customize_configuration' do
|
201
|
+
let(:obj) { DummyDecorator.decorate(Dummy.new) }
|
202
|
+
|
203
|
+
it 'should merge the input with the configuration' do
|
204
|
+
expect(obj.configuration).to receive(:merge!).with('foobar')
|
205
|
+
|
206
|
+
obj.customize_configuration('foobar')
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
describe '#render_title' do
|
211
|
+
let(:obj) { DummyDecorator.decorate(Dummy.new) }
|
212
|
+
|
213
|
+
context 'when using the default settings' do
|
214
|
+
it { expect(obj.render_title).to eq('Excalibur') }
|
215
|
+
|
216
|
+
it 'should call to_s in the title' do
|
217
|
+
expect(obj.configuration.title).to receive(:to_s)
|
218
|
+
|
219
|
+
obj.render_title
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|