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 |