locomotivecms_steam 1.0.0.pre.beta.2 → 1.0.0.pre.beta.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +7 -1
- data/Gemfile.lock +22 -12
- data/bin/steam.rb +21 -7
- data/lib/locomotive/steam/adapters/mongodb.rb +1 -1
- data/lib/locomotive/steam/adapters/mongodb/query.rb +6 -0
- data/lib/locomotive/steam/configuration.rb +9 -0
- data/lib/locomotive/steam/errors.rb +3 -0
- data/lib/locomotive/steam/liquid/drops/content_types.rb +20 -2
- data/lib/locomotive/steam/liquid/filters/json.rb +42 -0
- data/lib/locomotive/steam/liquid/filters/misc.rb +4 -0
- data/lib/locomotive/steam/liquid/filters/number.rb +51 -0
- data/lib/locomotive/steam/liquid/tags/concerns/i18n_page.rb +0 -9
- data/lib/locomotive/steam/liquid/tags/concerns/path.rb +1 -1
- data/lib/locomotive/steam/liquid/tags/editable.rb +1 -0
- data/lib/locomotive/steam/liquid/tags/editable/base.rb +3 -1
- data/lib/locomotive/steam/liquid/tags/editable/model.rb +19 -0
- data/lib/locomotive/steam/liquid/tags/inherited_block.rb +25 -1
- data/lib/locomotive/steam/middlewares/site.rb +9 -5
- data/lib/locomotive/steam/models/entity.rb +9 -8
- data/lib/locomotive/steam/models/mapper.rb +22 -6
- data/lib/locomotive/steam/repositories/content_entry_repository.rb +15 -1
- data/lib/locomotive/steam/repositories/content_type_field_select_option_repository.rb +4 -0
- data/lib/locomotive/steam/repositories/page_repository.rb +7 -0
- data/lib/locomotive/steam/repositories/site_repository.rb +1 -2
- data/lib/locomotive/steam/server.rb +7 -0
- data/lib/locomotive/steam/services.rb +10 -11
- data/lib/locomotive/steam/services/page_finder_service.rb +21 -0
- data/lib/locomotive/steam/version.rb +1 -1
- data/spec/integration/repositories/content_entry_repository_spec.rb +5 -0
- data/spec/integration/repositories/page_repository_spec.rb +5 -0
- data/spec/support/liquid.rb +11 -0
- data/spec/unit/liquid/filters/json_spec.rb +57 -0
- data/spec/unit/liquid/filters/misc_spec.rb +14 -0
- data/spec/unit/liquid/filters/number_spec.rb +100 -0
- data/spec/unit/liquid/tags/editable/model_spec.rb +84 -0
- data/spec/unit/liquid/tags/inherited_block_spec.rb +13 -0
- data/spec/unit/liquid/tags/link_to_spec.rb +2 -2
- data/spec/unit/liquid/tags/path_to_spec.rb +3 -3
- data/spec/unit/middlewares/site_spec.rb +43 -0
- data/spec/unit/repositories/content_entry_repository_spec.rb +13 -12
- data/spec/unit/services_spec.rb +23 -1
- metadata +13 -2
@@ -2,11 +2,35 @@ module Locomotive
|
|
2
2
|
module Steam
|
3
3
|
module Liquid
|
4
4
|
module Tags
|
5
|
+
|
6
|
+
# Blocks are used with the Extends tag to define
|
7
|
+
# the content of blocks. Nested blocks are allowed.
|
8
|
+
#
|
9
|
+
# {% extends home %}
|
10
|
+
# {% block content }Hello world{% endblock %}
|
11
|
+
#
|
12
|
+
# Options used to generate the UI/UX of the editable element inputs
|
13
|
+
# - short_name (Boolean): use just the name and skip the name of the nested blocks.
|
14
|
+
# - priority (Integer): allow blocks to be displayed before others
|
15
|
+
#
|
5
16
|
class InheritedBlock < ::Liquid::InheritedBlock
|
6
17
|
|
18
|
+
def initialize(tag_name, markup, options)
|
19
|
+
super
|
20
|
+
|
21
|
+
@attributes = { short_name: false, priority: 0 }
|
22
|
+
markup.scan(::Liquid::TagAttributes) do |key, value|
|
23
|
+
@attributes[key.to_sym] = ::Liquid::Expression.parse(value)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
7
27
|
def parse(tokens)
|
8
28
|
super.tap do
|
9
|
-
ActiveSupport::Notifications.instrument('steam.parse.inherited_block',
|
29
|
+
ActiveSupport::Notifications.instrument('steam.parse.inherited_block', {
|
30
|
+
page: options[:page],
|
31
|
+
name: @name,
|
32
|
+
found_super: self.contains_super?(nodelist)
|
33
|
+
}.merge(@attributes))
|
10
34
|
end
|
11
35
|
end
|
12
36
|
|
@@ -11,9 +11,7 @@ module Locomotive::Steam
|
|
11
11
|
def _call
|
12
12
|
site = find_site
|
13
13
|
|
14
|
-
|
15
|
-
# based on the request.
|
16
|
-
render_no_site if site.nil?
|
14
|
+
no_site! if site.nil?
|
17
15
|
|
18
16
|
# log anyway
|
19
17
|
log_site(site)
|
@@ -30,8 +28,14 @@ module Locomotive::Steam
|
|
30
28
|
end
|
31
29
|
end
|
32
30
|
|
33
|
-
def
|
34
|
-
|
31
|
+
def no_site!
|
32
|
+
# render a simple message if the service was not able to find a site
|
33
|
+
# based on the request.
|
34
|
+
if services.configuration.render_404_if_no_site
|
35
|
+
render_response('Hi, we are sorry but no site was found.', 404, 'text/html')
|
36
|
+
else
|
37
|
+
raise NoSiteException.new
|
38
|
+
end
|
35
39
|
end
|
36
40
|
|
37
41
|
def log_site(site)
|
@@ -12,29 +12,30 @@ module Locomotive::Steam
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def method_missing(name, *args, &block)
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
_name = name.to_s
|
16
|
+
if attributes.include?(_name)
|
17
|
+
self[_name]
|
18
|
+
elsif _name.end_with?('=') && attributes.include?(_name.chop)
|
19
|
+
self[_name.chop] = args.first
|
19
20
|
else
|
20
21
|
super
|
21
22
|
end
|
22
23
|
end
|
23
24
|
|
24
25
|
def respond_to?(name, include_private = false)
|
25
|
-
attributes.include?(name) || super
|
26
|
+
attributes.include?(name.to_s) || super
|
26
27
|
end
|
27
28
|
|
28
29
|
def _id
|
29
|
-
self[
|
30
|
+
self['_id']
|
30
31
|
end
|
31
32
|
|
32
33
|
def []=(name, value)
|
33
|
-
attributes[name
|
34
|
+
attributes[name] = value
|
34
35
|
end
|
35
36
|
|
36
37
|
def [](name)
|
37
|
-
attributes[name
|
38
|
+
attributes[name]
|
38
39
|
end
|
39
40
|
|
40
41
|
def serialize
|
@@ -19,6 +19,8 @@ module Locomotive::Steam
|
|
19
19
|
@default_attributes = []
|
20
20
|
@associations = []
|
21
21
|
|
22
|
+
@entity_map = {}
|
23
|
+
|
22
24
|
instance_eval(&block) if block_given?
|
23
25
|
end
|
24
26
|
|
@@ -47,15 +49,17 @@ module Locomotive::Steam
|
|
47
49
|
end
|
48
50
|
|
49
51
|
def to_entity(attributes)
|
50
|
-
entity_klass
|
51
|
-
|
52
|
+
cache_entity(entity_klass, attributes) do
|
53
|
+
entity_klass.new(deserialize(attributes)).tap do |entity|
|
54
|
+
set_default_attributes(entity)
|
52
55
|
|
53
|
-
|
54
|
-
|
56
|
+
entity.localized_attributes = @localized_attributes_hash || {}
|
57
|
+
entity.associations = {}
|
55
58
|
|
56
|
-
|
59
|
+
attach_entity_to_associations(entity)
|
57
60
|
|
58
|
-
|
61
|
+
entity.base_url = @repository.base_url(entity)
|
62
|
+
end
|
59
63
|
end
|
60
64
|
end
|
61
65
|
|
@@ -132,6 +136,18 @@ module Locomotive::Steam
|
|
132
136
|
end
|
133
137
|
end
|
134
138
|
|
139
|
+
def cache_entity(entity_klass, attributes, &block)
|
140
|
+
return yield if attributes['_id'].blank?
|
141
|
+
|
142
|
+
key = "#{entity_klass.to_s}-#{attributes['_id']}"
|
143
|
+
|
144
|
+
if (entity = @entity_map[key]).nil?
|
145
|
+
entity = @entity_map[key] = yield
|
146
|
+
end
|
147
|
+
|
148
|
+
entity
|
149
|
+
end
|
150
|
+
|
135
151
|
end
|
136
152
|
|
137
153
|
end
|
@@ -130,7 +130,21 @@ module Locomotive
|
|
130
130
|
end
|
131
131
|
|
132
132
|
def prepare_conditions(*conditions)
|
133
|
-
|
133
|
+
_conditions = conditions.first.try(:with_indifferent_access)
|
134
|
+
|
135
|
+
prepare_conditions_for_select_fields(_conditions) if _conditions
|
136
|
+
|
137
|
+
super({ _visible: true }, _conditions)
|
138
|
+
end
|
139
|
+
|
140
|
+
# select fields? if so, use the _id of the option instead of the option name
|
141
|
+
def prepare_conditions_for_select_fields(conditions)
|
142
|
+
self.content_type.fields.selects.each do |field|
|
143
|
+
if value = conditions[name = field.name.to_s]
|
144
|
+
conditions.delete(name)
|
145
|
+
conditions[name + '_id'] = field.select_options.by_name(value).try(:_id)
|
146
|
+
end
|
147
|
+
end
|
134
148
|
end
|
135
149
|
|
136
150
|
def add_localized_fields_to_mapper(mapper)
|
@@ -12,6 +12,11 @@ require 'dragonfly/middleware'
|
|
12
12
|
|
13
13
|
require_relative 'middlewares'
|
14
14
|
|
15
|
+
if ENV['PROFILER']
|
16
|
+
require 'moped'
|
17
|
+
require 'rack-mini-profiler'
|
18
|
+
end
|
19
|
+
|
15
20
|
module Locomotive::Steam
|
16
21
|
module Server
|
17
22
|
|
@@ -38,6 +43,8 @@ module Locomotive::Steam
|
|
38
43
|
use Rack::Lint
|
39
44
|
use Rack::Session::Moneta, configuration.moneta
|
40
45
|
|
46
|
+
use Rack::MiniProfiler if ENV['PROFILER']
|
47
|
+
|
41
48
|
server.steam_middleware_stack.each { |k| use k }
|
42
49
|
}
|
43
50
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'morphine'
|
1
|
+
require 'morphine'
|
2
2
|
|
3
3
|
require_relative_all %w(concerns .), 'services'
|
4
4
|
|
@@ -15,22 +15,17 @@ module Locomotive
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
class
|
19
|
-
|
18
|
+
class Defer < SimpleDelegator
|
20
19
|
def initialize(&block)
|
21
|
-
@
|
22
|
-
|
23
|
-
super(@site)
|
20
|
+
@constructor = block
|
21
|
+
super(nil)
|
24
22
|
end
|
25
|
-
|
26
23
|
def __getobj__
|
27
|
-
super || @
|
24
|
+
super || __setobj__(@constructor.call)
|
28
25
|
end
|
29
|
-
|
30
26
|
def nil?
|
31
27
|
__getobj__.nil?
|
32
28
|
end
|
33
|
-
|
34
29
|
end
|
35
30
|
|
36
31
|
class Instance < Struct.new(:request)
|
@@ -38,7 +33,7 @@ module Locomotive
|
|
38
33
|
include Morphine
|
39
34
|
|
40
35
|
register :current_site do
|
41
|
-
repositories.current_site =
|
36
|
+
repositories.current_site = Defer.new { site_finder.find }
|
42
37
|
end
|
43
38
|
|
44
39
|
register :repositories do
|
@@ -134,6 +129,10 @@ module Locomotive
|
|
134
129
|
self.current_site.__setobj__(site)
|
135
130
|
end
|
136
131
|
|
132
|
+
def defer(name, &block)
|
133
|
+
send(:"#{name}=", Defer.new(&block))
|
134
|
+
end
|
135
|
+
|
137
136
|
end
|
138
137
|
|
139
138
|
end
|
@@ -17,8 +17,29 @@ module Locomotive
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
+
def by_handle(handle)
|
21
|
+
decorate { page_map[handle] }
|
22
|
+
end
|
23
|
+
|
20
24
|
private
|
21
25
|
|
26
|
+
# Instead of hitting the DB each time we want a page from its handle,
|
27
|
+
# just get all the handles at once and cache the result. (up to 20% boost)
|
28
|
+
#
|
29
|
+
def page_map
|
30
|
+
@page_map ||= {}
|
31
|
+
|
32
|
+
return @page_map[repository.locale] if @page_map[repository.locale]
|
33
|
+
|
34
|
+
{}.tap do |map|
|
35
|
+
repository.only_handle_and_fullpath.each do |page|
|
36
|
+
map[page.handle] = page
|
37
|
+
end
|
38
|
+
|
39
|
+
@page_map[repository.locale] = map
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
22
43
|
def path_combinations(path)
|
23
44
|
_path_combinations(path.split('/'))
|
24
45
|
end
|
@@ -50,6 +50,11 @@ describe Locomotive::Steam::ContentEntryRepository do
|
|
50
50
|
it { expect(subject.name).to eq 'Alice in Chains' }
|
51
51
|
end
|
52
52
|
|
53
|
+
describe 'filter by a select field' do
|
54
|
+
subject { repository.all(kind: 'grunge') }
|
55
|
+
it { expect(subject.map { |entry| entry[:name] }).to eq(['Alice in Chains', 'Pearl Jam']) }
|
56
|
+
end
|
57
|
+
|
53
58
|
describe '#group_by_select_option' do
|
54
59
|
subject { repository.group_by_select_option(:kind) }
|
55
60
|
it { expect(subject.map { |h| h[:name] }).to eq(%w(grunge rock country)) }
|
@@ -37,6 +37,11 @@ describe Locomotive::Steam::PageRepository do
|
|
37
37
|
it { expect(subject.title[:en]).to eq 'Music' }
|
38
38
|
end
|
39
39
|
|
40
|
+
describe '#only_handle_and_fullpath' do
|
41
|
+
subject { repository.only_handle_and_fullpath }
|
42
|
+
it { expect(subject.size).to eq 3 }
|
43
|
+
end
|
44
|
+
|
40
45
|
describe '#by_fullpath' do
|
41
46
|
subject { repository.by_fullpath('archives/news') }
|
42
47
|
it { expect(subject.title[:en]).to eq 'News archive' }
|
data/spec/support/liquid.rb
CHANGED
@@ -9,6 +9,17 @@ def parse_template(source, options = nil)
|
|
9
9
|
end
|
10
10
|
|
11
11
|
module Liquid
|
12
|
+
|
13
|
+
class TestDrop < Liquid::Drop
|
14
|
+
def initialize(source)
|
15
|
+
@_source = source
|
16
|
+
end
|
17
|
+
|
18
|
+
def before_method(meth)
|
19
|
+
@_source[meth.to_sym]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
12
23
|
class SimpleEventsListener
|
13
24
|
def initialize
|
14
25
|
ActiveSupport::Notifications.subscribe(/^steam\.parse\./) do |name, start, finish, id, payload|
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Locomotive::Steam::Liquid::Filters::Json do
|
4
|
+
|
5
|
+
include Locomotive::Steam::Liquid::Filters::Json
|
6
|
+
|
7
|
+
let(:input) { nil }
|
8
|
+
subject { json(*input) }
|
9
|
+
|
10
|
+
describe 'adds quotes to a string' do
|
11
|
+
|
12
|
+
let(:input) { 'foo' }
|
13
|
+
it { expect(subject).to eq %("foo") }
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'drop' do
|
18
|
+
|
19
|
+
describe 'includes only the fields specified' do
|
20
|
+
|
21
|
+
let(:input) { [Liquid::TestDrop.new(title: 'Acme', body: 'Lorem ipsum'), 'title'] }
|
22
|
+
it { expect(subject).to eq %("title":"Acme") }
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'collections' do
|
29
|
+
|
30
|
+
describe 'adds brackets and quotes to a collection' do
|
31
|
+
|
32
|
+
let(:input) { [['foo', 'bar']] }
|
33
|
+
it { expect(subject).to eq %(["foo","bar"]) }
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
describe 'includes the first field' do
|
38
|
+
|
39
|
+
let(:input) {
|
40
|
+
[[Liquid::TestDrop.new(title: 'Acme', body: 'Lorem ipsum'),
|
41
|
+
Liquid::TestDrop.new(title: 'Hello world', body: 'Lorem ipsum')], 'title'] }
|
42
|
+
it { expect(subject).to eq %("Acme","Hello world") }
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'includes the specified fields' do
|
47
|
+
|
48
|
+
let(:input) {
|
49
|
+
[[Liquid::TestDrop.new(title: 'Acme', body: 'Lorem ipsum', date: '2013-12-13'),
|
50
|
+
Liquid::TestDrop.new(title: 'Hello world', body: 'Lorem ipsum', date: '2013-12-12')], 'title, body'] }
|
51
|
+
it { expect(subject).to eq %({"title":"Acme","body":"Lorem ipsum"},{"title":"Hello world","body":"Lorem ipsum"}) }
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -105,4 +105,18 @@ describe Locomotive::Steam::Liquid::Filters::Misc do
|
|
105
105
|
|
106
106
|
end
|
107
107
|
|
108
|
+
describe '#hexdigest' do
|
109
|
+
|
110
|
+
let(:key) { 'key' }
|
111
|
+
let(:data) { 'The quick brown fox jumps over the lazy dog' }
|
112
|
+
let(:digest) { nil }
|
113
|
+
|
114
|
+
subject { hexdigest(data, key, digest) }
|
115
|
+
|
116
|
+
it 'returns the authentication code as a hex-encoded string' do
|
117
|
+
expect(subject).to eq 'de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9'
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
108
122
|
end
|