make the I18nDecorator more robust (edge cases) + fs models inherit from base now (avoid code duplication) + fix bugs

did committed Feb 12, 2015
commit 3e3565c64e95962da4edacfad2e23b4a7c7f4e09
Showing 14 changed files with 208 additions and 78 deletions
locomotive/steam/decorators/i18n_decorator.rb b/lib/locomotive/steam/decorators/i18n_decorator.rb +37 -8
@@ @@ -10,6 +10,8 @@ module Locomotive
attr_reader :__default_locale__
def initialize(object, attributes, locale = nil, default_locale = nil)
+ # ::Object.send(:puts, "Decorating #{object.class.name} with #{self.class.name}")
+
self.__localized_attributes__ = attributes || (object.respond_to?(:localized_attributes) ? object.localized_attributes : [])
self.__frozen_locale__ = false
self.__locale__ = locale
@@ @@ -57,16 +59,43 @@ module Locomotive
@__frozen_locale__ = false
end
- def method_missing(name, *args, &block)
- # DEBUG: ::Object.send(:puts, "[#{name}] with #{args.inspect}")
- if __localized_attributes__.include?(name.to_sym)
- field = __getobj__.public_send(:attributes)[name.to_sym]
+ def __is_localized_attribute__(name)
+ __localized_attributes__.include?(name.to_sym)
+ end
+
+ def __get_localized_value__(name)
+ # first get all the values in all the locales
+ field = __getobj__.public_send(:attributes)[name.to_sym]
+
+ # same value (can be nil) for all the locale?
+ if field.is_a?(Hash)
+ # if so, look first for the value in the the current locale.
+ # if no value, then in the default locale
field[__locale__] || field[__default_locale__]
- elsif name.to_s.end_with?('=') && __localized_attributes__.include?(name.to_s.chop.to_sym)
- field = __getobj__.public_send(:attributes)[name.to_s.chop.to_sym]
- field[__locale__] = args.first
else
- super
+ field
+ end
+ end
+
+ def __set_localized_value__(name, value)
+ field = __getobj__.public_send(:attributes)[name.to_sym] || {}
+
+ if field.is_a?(Hash)
+ field[__locale__] = value
+ else
+ field = { __locale__ => value }
+ end
+ end
+
+ def method_missing(name, *args, &block)
+ # ::Object.send(:puts, "[#{name}][#{__locale__.inspect}][#{__default_locale__.inspect}] with #{args.inspect}") # DEBUG:
+ if __is_localized_attribute__(name)
+ __get_localized_value__(name)
+ elsif name.to_s.end_with?('=') && __is_localized_attribute__(name.to_s.chop)
+ __set_localized_value__(name.to_s.chop, args.first)
+ else
+ # Note: we want to hit the method_missing of the target object
+ __getobj__.send(name, *args, &block)
end
end
locomotive/steam/liquid/drops/i18n_base.rb b/lib/locomotive/steam/liquid/drops/i18n_base.rb +3 -0
@@ @@ -5,12 +5,15 @@ module Locomotive
class I18nBase < Base
def initialize(source, localized_attributes = nil)
+ # puts "creating #{self.class.name} drop for #{source.class.name}(#{source.object_id.inspect})"
decorated = source if source.respond_to?(:__locale__)
decorated ||= Locomotive::Steam::Decorators::I18nDecorator.new(source, localized_attributes)
super(decorated)
end
def context=(context)
+ # puts "context=... #{self.class.name} / #{@_source.attributes.inspect} / #{@_source.__getobj__.object_id.inspect}"
+ # puts "locale=#{context.registers[:locale].inspect}"
if locale = context.registers[:locale]
@_source.__locale__ = locale
end
locomotive/steam/middlewares/renderer.rb b/lib/locomotive/steam/middlewares/renderer.rb +42 -3
@@ @@ -16,6 +16,7 @@ module Locomotive::Steam
private
def render_page
+ # TODO: redirection
content = parse_and_render_liquid
render_response(content, page.not_found? ? 404: 200)
end
@@ @@ -27,11 +28,49 @@ module Locomotive::Steam
def parse_and_render_liquid
document = services.liquid_parser.parse(page)
+ document.render(liquid_context)
+ end
+
+ # == TEST ==
- puts document.inspect
- # page #.tap { |s| puts s.inspect }
+ def liquid_context
+ ::Liquid::Context.new(liquid_assigns, {}, liquid_registers, true)
+ end
+
+ def liquid_registers
+ {
+ request: request,
+ locale: locale,
+ site: site,
+ page: page,
+ services: services,
+ repositories: services.repositories,
+ logger: Locomotive::Common::Logger
+ }
+ end
- 'TEST'
+ def liquid_assigns
+ {
+ 'site' => site.to_liquid,
+ 'page' => page.to_liquid,
+ 'models' => Locomotive::Steam::Liquid::Drops::ContentTypes.new,
+ 'contents' => Locomotive::Steam::Liquid::Drops::ContentTypes.new,
+ 'current_page' => params[:page],
+ 'params' => params.stringify_keys,
+ 'path' => request.path,
+ 'fullpath' => request.fullpath,
+ 'url' => request.url,
+ 'ip_address' => request.ip,
+ 'post?' => request.post?,
+ 'host' => request.host_with_port,
+ 'now' => Time.zone.now,
+ 'today' => Date.today,
+ 'locale' => locale,
+ 'default_locale' => site.default_locale.to_s,
+ 'locales' => site.locales.map(&:to_s),
+ 'current_user' => {},
+ 'session' => Locomotive::Steam::Liquid::Drops::SessionProxy.new,
+ }
end
locomotive/steam/middlewares/timezone.rb b/lib/locomotive/steam/middlewares/timezone.rb +2 -2
@@ @@ -13,9 +13,9 @@ module Locomotive::Steam
log "Timezone: #{timezone.inspect}"
# DEBUG
- # Time.use_zone(timezone) do
+ Time.use_zone(timezone) do
self.next
- # end
+ end
end
end
locomotive/steam/repositories/filesystem/models/base.rb b/lib/locomotive/steam/repositories/filesystem/models/base.rb +40 -0
@@ @@ -0,0 +1,40 @@
+ module Locomotive
+ module Steam
+ module Repositories
+ module Filesystem
+ module Models
+
+ class Base
+
+ attr_accessor :attributes
+
+ def initialize(attributes)
+ @attributes = attributes
+ end
+
+ def method_missing(name, *args, &block)
+ if attributes.include?(name)
+ attributes[name.to_sym]
+ else
+ super
+ end
+ end
+
+ def self.set_localized_attributes(list)
+ singleton = class << self; self; end
+ singleton.class_eval do
+ define_method(:localized_attributes) { list }
+ end
+
+ class_eval do
+ define_method(:localized_attributes) { list }
+ end
+ end
+
+ end
+
+ end
+ end
+ end
+ end
+ end
locomotive/steam/repositories/filesystem/models/page.rb b/lib/locomotive/steam/repositories/filesystem/models/page.rb +4 -18
@@ @@ -4,7 +4,9 @@ module Locomotive
module Filesystem
module Models
- class Page < Struct.new(:attributes)
+ class Page < Base
+
+ set_localized_attributes [:title, :slug, :permalink, :template, :template_path, :fullpath, :seo, :meta_description, :meta_keywords]
def initialize(attributes)
super({
@@ @@ -17,14 +19,6 @@ module Locomotive
}.merge(attributes))
end
- def method_missing(name, *args, &block)
- if attributes.include?(name)
- attributes[name.to_sym] # getter
- else
- super
- end
- end
-
def templatized?
!!content_type
end
@@ @@ -33,16 +27,8 @@ module Locomotive
attributes[:fullpath].values.first == '404'
end
- def localized_attributes
- self.class.localized_attributes
- end
-
- def self.localized_attributes
- [:title, :slug, :permalink, :template, :template_path, :fullpath, :seo, :meta_description, :meta_keywords]
- end
-
def to_liquid
- Steam::Liquids::Drops::Page.new(self)
+ Steam::Liquid::Drops::Page.new(self)
end
end
locomotive/steam/repositories/filesystem/models/site.rb b/lib/locomotive/steam/repositories/filesystem/models/site.rb +4 -18
@@ @@ -4,25 +4,11 @@ module Locomotive
module Filesystem
module Models
- class Site < Struct.new(:attributes)
+ class Site < Base
- attr_accessor :root_path
-
- def method_missing(name, *args, &block)
- if attributes.include?(name)
- attributes[name.to_sym] # getter
- else
- super
- end
- end
+ set_localized_attributes [:seo, :meta_description, :meta_keywords]
- def localized_attributes
- self.class.localized_attributes
- end
-
- def self.localized_attributes
- [:seo, :meta_description, :meta_keywords]
- end
+ attr_accessor :root_path
def default_locale
self.locales.try(:first) || :en
@@ @@ -33,7 +19,7 @@ module Locomotive
end
def to_liquid
- Steam::Liquids::Drops::Site.new(self, localized_attributes)
+ Steam::Liquid::Drops::Site.new(self)
end
end
locomotive/steam/repositories/filesystem/models/snippet.rb b/lib/locomotive/steam/repositories/filesystem/models/snippet.rb +3 -17
@@ @@ -4,28 +4,14 @@ module Locomotive
module Filesystem
module Models
- class Snippet < Struct.new(:attributes)
+ class Snippet < Base
+
+ set_localized_attributes [:template, :template_path]
def initialize(attributes)
super({ template: {} }.merge(attributes))
end
- def method_missing(name, *args, &block)
- if attributes.include?(name)
- attributes[name.to_sym] # getter
- else
- super
- end
- end
-
- def localized_attributes
- self.class.localized_attributes
- end
-
- def self.localized_attributes
- [:template, :template_path]
- end
-
end
end
locomotive/steam/repositories/filesystem/site.rb b/lib/locomotive/steam/repositories/filesystem/site.rb +1 -3
@@ @@ -6,9 +6,7 @@ module Locomotive
class Site < Struct.new(:loader)
def by_host(host, options = {})
- Filesystem::Models::Site.new(loader.attributes).tap do |site|
- loader.default_locale = site.default_locale.to_sym
- end
+ Filesystem::Models::Site.new(loader.attributes)
end
end
locomotive/steam/repositories/filesystem/theme_asset.rb b/lib/locomotive/steam/repositories/filesystem/theme_asset.rb +3 -2
@@ @@ -6,12 +6,13 @@ module Locomotive
class ThemeAsset < Struct.new(:site)
def url_for(path)
- ['', 'sites', site._id.to_s, 'theme', path].join('/')
+ path
+ # ['', 'sites', site._id.to_s, 'theme', path].join('/') # Engine
end
def checksums
raise 'TODO checksums'
- # site.theme_assets.checksums
+ # site.theme_assets.checksums # Engine
end
end
locomotive/steam/services.rb b/lib/locomotive/steam/services.rb +1 -1
@@ @@ -19,7 +19,7 @@ module Locomotive
require_relative 'repositories/filesystem.rb'
klass = Steam::Repositories::Filesystem
end
- klass.build_instance
+ klass.build_instance(nil, nil, options)
end
register :site_finder do
spec/integration/server/basic_spec.rb +4 -4
@@ @@ -8,10 +8,10 @@ describe Locomotive::Steam::Server do
run_server
end
- it 'can render the index page', pending: true do
- get '/index'
- expect(last_response.status).to eq(200)
- end
+ # it 'can render the index page' do
+ # get '/index'
+ # expect(last_response.status).to eq(200)
+ # end
# it 'shows the index page' do
# get '/index'
spec/unit/decorators/i18n_decorator_spec.rb +20 -2
@@ @@ -2,8 +2,8 @@ require 'spec_helper'
describe Locomotive::Steam::Decorators::I18nDecorator do
- let(:page) { instance_double('Page', published?: true, attributes: { title: { en: 'Hello world!', fr: 'Bonjour monde' } }) }
- let(:localized) { [:title] }
+ let(:page) { instance_double('Page', published?: true, attributes: { title: { en: 'Hello world!', fr: 'Bonjour monde' }, slug: 'hello-world' }) }
+ let(:localized) { [:title, :slug] }
let(:locale) { 'fr' }
let(:default_locale) { nil }
let(:decorated) { Locomotive::Steam::Decorators::I18nDecorator.new(page, localized, locale, default_locale) }
@@ @@ -12,6 +12,10 @@ describe Locomotive::Steam::Decorators::I18nDecorator do
expect(decorated.title).to eq 'Bonjour monde'
end
+ it 'uses the same value for all the locales' do
+ expect(decorated.slug).to eq 'hello-world'
+ end
+
it 'allows access to the other methods of the model too' do
expect(decorated.published?).to eq true
end
@@ @@ -55,4 +59,18 @@ describe Locomotive::Steam::Decorators::I18nDecorator do
expect(decorated.__locale__).to eq :fr
end
+ describe 'with a model' do
+
+ let(:model) { Locomotive::Steam::Repositories::Filesystem::Models::Site.new(name: 'Acme') }
+ let(:decorated) { Locomotive::Steam::Decorators::I18nDecorator.new(model, nil, locale, default_locale) }
+
+ it 'runs some basic tests' do
+ expect(model.localized_attributes).to eq [:seo, :meta_description, :meta_keywords]
+ expect(model.class.localized_attributes).to eq [:seo, :meta_description, :meta_keywords]
+ expect(decorated.name).to eq 'Acme'
+ expect(decorated.meta_description).to eq nil
+ end
+
+ end
+
end
spec/unit/repositories/filesystem_spec.rb +44 -0
@@ @@ -0,0 +1,44 @@
+ require 'spec_helper'
+
+ describe Locomotive::Steam::Repositories::Filesystem do
+
+ let(:site) { instance_double('Site', name: 'PCH') }
+ let(:repositories) { Locomotive::Steam::Repositories::Filesystem.build_instance(site) }
+
+ describe '#theme_asset' do
+
+ subject { repositories.theme_asset }
+
+ context 'by default' do
+
+ it 'returns a class of ThemeAssetRepository' do
+ expect(subject.class).to eq Locomotive::Steam::Repositories::Filesystem::ThemeAsset
+ end
+
+ it 'gets access to the site' do
+ expect(subject.site.name).to eq 'PCH'
+ end
+
+ end
+
+ context 'a different repository' do
+
+ before do
+ repositories.theme_asset = MyThemeAssetRepository.new(site)
+ end
+
+ it 'returns a class of ThemeAssetRepository' do
+ expect(subject.class).to eq MyThemeAssetRepository
+ end
+
+ it 'gets access to the site' do
+ expect(subject.site.name).to eq 'PCH'
+ end
+
+ end
+
+ end
+
+ class MyThemeAssetRepository < Struct.new(:site); end
+
+ end