refactoring the middlewares (WIP)

did committed Feb 10, 2015
commit 34b5dd19229b8dd1877573ab9eacf93317c6789c
Showing 45 changed files with 1273 additions and 420 deletions
Gemfile +2 -2
@@ @@ -3,11 +3,11 @@ source 'https://rubygems.org'
gemspec
group :development do
- # gem 'locomotivecms_common', '~> 0.0.2', path: '../common'
+ gem 'locomotivecms_common', '~> 0.0.2', path: '../common'
# gem 'locomotivecms_models', '~> 0.0.1', path: '../models'
# gem 'locomotivecms_models', '0.0.1.pre.alpha'
# gem 'locomotivecms-liquid', path: '/Users/didier/Documents/LocomotiveCMS/gems/liquid'
- # gem 'thin'
+ gem 'thin'
end
group :test do
Gemfile.lock +16 -4
@@ @@ -9,7 +9,7 @@ PATH
dragonfly (~> 1.0.7)
haml (~> 4.0.6)
httparty (~> 0.13.3)
- kaminari (~> 0.16.2)
+ kaminari (= 0.16.1)
kramdown (~> 1.5.0)
locomotivecms-solid (~> 4.0.0.alpha2)
locomotivecms_common (~> 0.0.2)
@@ @@ -22,6 +22,12 @@ PATH
sprockets (~> 2.12.3)
sprockets-sass (~> 1.3.1)
+ PATH
+ remote: ../common
+ specs:
+ locomotivecms_common (0.0.2)
+ colorize
+
GEM
remote: https://rubygems.org/
specs:
@@ @@ -79,6 +85,7 @@ GEM
simplecov (~> 0.9.1)
term-ansicolor (~> 1.3)
thor (~> 0.19.1)
+ daemons (1.1.9)
debugger-linecache (1.2.0)
diff-lcs (1.2.5)
docile (1.1.5)
@@ @@ -87,6 +94,7 @@ GEM
multi_json (~> 1.0)
rack
erubis (2.7.0)
+ eventmachine (1.0.4)
execjs (2.3.0)
ffi (1.9.6)
haml (4.0.6)
@@ @@ -104,15 +112,13 @@ GEM
json_spec (1.1.4)
multi_json (~> 1.0)
rspec (>= 2.0, < 4.0)
- kaminari (0.16.2)
+ kaminari (0.16.1)
actionpack (>= 3.0.0)
activesupport (>= 3.0.0)
kramdown (1.5.0)
locomotivecms-liquid (4.0.0.alpha2)
locomotivecms-solid (4.0.0.alpha2)
locomotivecms-liquid (~> 4.0.0.alpha2)
- locomotivecms_common (0.0.2)
- colorize
loofah (2.0.1)
nokogiri (>= 1.5.9)
method_source (0.8.2)
@@ @@ -185,6 +191,10 @@ GEM
tilt (~> 1.1)
term-ansicolor (1.3.0)
tins (~> 1.0)
+ thin (1.6.3)
+ daemons (~> 1.0, >= 1.0.9)
+ eventmachine (~> 1.0)
+ rack (~> 1.0)
thor (0.19.1)
thread_safe (0.3.4)
tilt (1.4.1)
@@ @@ -201,7 +211,9 @@ DEPENDENCIES
coveralls
i18n-spec (~> 0.6.0)
json_spec (~> 1.1.4)
+ locomotivecms_common (~> 0.0.2)!
locomotivecms_steam!
pry-byebug
rake (~> 10.4.2)
rspec (~> 3.1.0)
+ thin
Rakefile +5 -0
@@ @@ -15,4 +15,9 @@ require_relative 'lib/locomotive/steam'
require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new('spec')
+
+ RSpec::Core::RakeTask.new('spec:unit') do |spec|
+ spec.pattern = 'spec/unit/**/*_spec.rb'
+ end
+
task default: :spec
example/server.rb +21 -9
@@ @@ -6,26 +6,38 @@ require 'bundler/setup'
Bundler.require
require 'thin'
- # require 'common'
- require 'locomotive/common'
require_relative '../lib/locomotive/steam'
require_relative '../lib/locomotive/steam/server'
- require_relative '../lib/locomotive/steam/initializers'
path = ENV['SITE_PATH'] || File.join(File.expand_path(File.dirname(__FILE__)), '../spec/fixtures/default')
# reader = Locomotive::Mounter::Reader::FileSystem.instance
# reader.run!(path: path)
- datastore = Locomotive::Steam::FileSystemDatastore.new(path: path)
+ # datastore = Locomotive::Steam::FileSystemDatastore.new(path: path)
- app = Locomotive::Steam::Server.new(datastore, {
- serve_assets: true
- })
+ # app = Locomotive::Steam::Server.new(datastore, {
+ # serve_assets: true
+ # })
- server = Thin::Server.new('localhost', '3333', app)
- server.threaded = true
+ Locomotive::Steam.configure do |config|
+ config.mode = :test
+ end
+
+ Locomotive::Common.reset
+ Locomotive::Common.configure do |config|
+ path = File.join(path, 'log/steam.log')
+ config.notifier = Locomotive::Common::Logger.setup(path)
+ end
+
+ server = Locomotive::Steam::Server.new(path: path)
+
+ # THIN
+ # server = Thin::Server.new('localhost', '3333', foo)
+ # server.threaded = true
+
+ Rack::Handler::WEBrick.run server.to_app
Locomotive::Common::Logger.info 'Server started...'
server.start
locomotive/steam.rb b/lib/locomotive/steam.rb +7 -8
@@ @@ -1,5 +1,10 @@
require 'locomotive/common'
+ require 'active_support'
+ require 'active_support/concern'
+ require 'active_support/deprecation'
+ require 'active_support/core_ext'
+
require_relative 'steam/core_ext'
require_relative 'steam/exceptions'
require_relative 'steam/configuration'
@@ @@ -11,19 +16,11 @@ require_relative 'steam/repositories'
require_relative 'steam/services'
# TODO: move into a file named dependencies
- require 'sprockets'
- require 'sprockets-sass'
require 'haml'
require 'compass'
require 'mimetype_fu'
require 'mime-types'
require 'rack/csrf'
-
- require 'active_support'
- require 'active_support/concern'
- require 'active_support/deprecation'
- require 'active_support/core_ext'
-
require 'mime/types'
module Locomotive
@@ @@ -45,6 +42,8 @@ module Locomotive
def self.configure
yield(configuration)
+
+ require_relative 'steam/initializers'
end
# FIXME: not sure it will be ever needed
locomotive/steam/core_ext/hash.rb b/lib/locomotive/steam/core_ext/hash.rb +4 -0
@@ @@ -11,6 +11,10 @@ module HashConverter
convert(hash, :to_s)
end
+ def to_sym(hash)
+ convert(hash, :to_sym)
+ end
+
# FIXME: not sure it will be ever needed
# def to_camel_case hash
# convert hash, :camelize, :lower
locomotive/steam/initializers.rb b/lib/locomotive/steam/initializers.rb +3 -3
@@ @@ -2,6 +2,6 @@ require_relative 'initializers/sprockets.rb'
require_relative 'initializers/i18n.rb'
require_relative 'initializers/dragonfly.rb'
- Locomotive::Common.configure do |config|
- config.notifier = Locomotive::Common::Logger.setup
- end
+ # Locomotive::Common.configure do |config|
+ # config.notifier = Locomotive::Common::Logger.setup
+ # end
locomotive/steam/initializers/sprockets.rb b/lib/locomotive/steam/initializers/sprockets.rb +4 -1
@@ @@ -1 +1,4 @@
- Sprockets::Sass.add_sass_functions = false
\ No newline at end of file
+ require 'sprockets'
+ require 'sprockets-sass'
+
+ Sprockets::Sass.add_sass_functions = false
locomotive/steam/liquid/drops/i18n_base.rb b/lib/locomotive/steam/liquid/drops/i18n_base.rb +3 -2
@@ @@ -5,7 +5,8 @@ module Locomotive
class I18nBase < Base
def initialize(source, localized_attributes = [])
- decorated = Locomotive::Steam::Decorators::I18nDecorator.new(source, localized_attributes)
+ decorated = source if source.respond_to?(:__locale__)
+ decorated ||= Locomotive::Steam::Decorators::I18nDecorator.new(source, localized_attributes)
super(decorated)
end
@@ @@ -14,7 +15,7 @@ module Locomotive
@_source.__locale__ = locale
end
- @_source.__default_locale__ = context.registers[:site].default_locale
+ @_source.__default_locale__ = context.registers[:site].try(:default_locale)
super
end
locomotive/steam/liquid/drops/site.rb b/lib/locomotive/steam/liquid/drops/site.rb +1 -1
@@ @@ -2,7 +2,7 @@ module Locomotive
module Steam
module Liquid
module Drops
- class Site < Base
+ class Site < I18nBase
delegate :name, :domains, :seo_title, :meta_keywords, :meta_description, to: :@_source
locomotive/steam/liquid/tags/locale_switcher.rb b/lib/locomotive/steam/liquid/tags/locale_switcher.rb +1 -0
@@ @@ -2,6 +2,7 @@ module Locomotive
module Steam
module Liquid
module Tags
+
# Display the links to change the locale of the current page
#
# Usage:
locomotive/steam/middlewares.rb b/lib/locomotive/steam/middlewares.rb +18 -8
@@ @@ -1,15 +1,25 @@
- require_relative 'middlewares/base'
+ require_relative 'middlewares/threadsafe'
+ require_relative 'middlewares/helpers'
require_relative 'middlewares/favicon'
- require_relative 'middlewares/static_assets'
- require_relative 'middlewares/dynamic_assets'
+ require_relative 'middlewares/site'
+ require_relative 'middlewares/default_env'
+ require_relative 'middlewares/locale'
+ require_relative 'middlewares/timezone'
require_relative 'middlewares/logging'
- require_relative 'middlewares/entry_submission'
require_relative 'middlewares/path'
- require_relative 'middlewares/locale'
require_relative 'middlewares/page'
- require_relative 'middlewares/timezone'
- require_relative 'middlewares/templatized_page'
+
+ # require_relative 'middlewares/static_assets'
+ # require_relative 'middlewares/dynamic_assets'
+
+ # require_relative 'middlewares/entry_submission'
+
+
+
+
+ # require_relative 'middlewares/templatized_page'
+ # require_relative 'middlewares/site'
require_relative 'middlewares/renderer'
- require_relative 'middlewares/stack'
\ No newline at end of file
+ require_relative 'middlewares/stack'
locomotive/steam/middlewares/base.rb b/lib/locomotive/steam/middlewares/base.rb +71 -65
@@ @@ -1,65 +1,71 @@
- module Locomotive::Steam
- module Middlewares
-
- class Base
-
- attr_accessor :app, :request, :path
- attr_accessor :liquid_assigns, :services
- attr_accessor :site, :page, :content_entry, :locale
-
- def initialize(app = nil)
- @app = app
- end
-
- def call(env)
- if Locomotive::Steam.mode == :test
- _call(env)
- else
- dup._call(env) # thread-safe purpose
- end
- end
-
- def _call(env)
- code, headers, response = @app.call(env)
- self.set_accessors(env)
- [code, headers, [response]]
- end
-
- protected
-
- def set_accessors(env)
- %w(path site request page content_entry services locale).each do |name|
- self.send(:"#{name}=", env.fetch("steam.#{name}", nil))
- end
-
- env['steam.liquid_assigns'] ||= {}
- self.liquid_assigns = env.fetch('steam.liquid_assigns')
- end
-
- def params
- self.request.params.deep_symbolize_keys
- end
-
- def html?
- ['text/html', 'application/x-www-form-urlencoded'].include?(self.request.media_type) &&
- !self.request.xhr? &&
- !self.json?
- end
-
- def json?
- self.request.content_type == 'application/json' || File.extname(self.request.path) == '.json'
- end
-
- def redirect_to(location, type = 301)
- self.log "Redirected to #{location}"
- [type, { 'Content-Type' => 'text/html', 'Location' => location }, []]
- end
-
- def log(msg)
- Locomotive::Common::Logger.info msg
- end
-
- end
-
- end
- end
+ # module Locomotive::Steam
+ # module Middlewares
+
+ # class Base
+
+ # # attr_accessor :app, :request, :path
+ # # attr_accessor :liquid_assigns, :services
+ # # attr_accessor :site, :page, :content_entry, :locale
+
+ # # def initialize(app = nil)
+ # # puts "...creating #{self.class.name}... #{app.nil?}"
+ # # @app = app
+ # # end
+
+ # # def call(env)
+ # # dup._call(env) # thread-safe purpose
+ # # # _call(env)
+ # # # if Locomotive::Steam.configuration.mode == :test
+ # # # _call(env)
+ # # # else
+ # # # end
+ # # end
+
+ # # def _call(env)
+ # # code, headers, response = @app.call(env)
+ # # # self.set_accessors(env)
+ # # [code, headers, [response]]
+ # # end
+
+ # # protected
+
+ # # # def path
+ # # # @path ||= @env.fetch('steam.path', nil)
+ # # # end
+
+ # # # def set_accessors(env)
+ # # # %w(path site request page content_entry services locale).each do |name|
+ # # # self.send(:"#{name}=", env.fetch("steam.#{name}", nil))
+ # # # end
+
+ # # # env['steam.liquid_assigns'] ||= {}
+ # # # self.liquid_assigns = env.fetch('steam.liquid_assigns')
+ # # # end
+
+ # # def params
+ # # self.request.params.deep_symbolize_keys
+ # # end
+
+ # # def html?
+ # # ['text/html', 'application/x-www-form-urlencoded'].include?(self.request.media_type) &&
+ # # !self.request.xhr? &&
+ # # !self.json?
+ # # end
+
+ # # def json?
+ # # self.request.content_type == 'application/json' || File.extname(self.request.path) == '.json'
+ # # end
+
+ # # def redirect_to(location, type = 301)
+ # # self.log "Redirected to #{location}"
+ # # [type, { 'Content-Type' => 'text/html', 'Location' => location }, []]
+ # # end
+
+ # # def log(msg)
+ # # Locomotive::Common::Logger.info msg
+ # # end
+
+ # end
+
+ # end
+ # end
locomotive/steam/middlewares/default_env.rb b/lib/locomotive/steam/middlewares/default_env.rb +22 -0
@@ @@ -0,0 +1,22 @@
+ module Locomotive::Steam
+ module Middlewares
+
+ class DefaultEnv < Struct.new(:app, :options)
+
+ def call(env)
+ # time = Benchmark.realtime do
+ request = Rack::Request.new(env)
+
+ env['steam.request'] = request
+ env['steam.services'] = Locomotive::Steam::Services.build_instance(request, options)
+ # end
+
+ # puts "[Benchmark][DefaultEnv] Time elapsed #{time*1000} milliseconds"
+
+ app.call(env)
+ end
+
+ end
+
+ end
+ end
locomotive/steam/middlewares/favicon.rb b/lib/locomotive/steam/middlewares/favicon.rb +5 -2
@@ @@ -1,10 +1,13 @@
module Locomotive::Steam
module Middlewares
- class Favicon < Base
+ class Favicon < Struct.new(:app)
+
+ include Helpers
def call(env)
if env['PATH_INFO'] == '/favicon.ico'
+ log 'Default and empty Favicon rendered'
[200, { 'Content-Type' => 'image/vnd.microsoft.icon' }, ['']]
else
app.call(env)
@@ @@ -14,4 +17,4 @@ module Locomotive::Steam
end
end
- end
\ No newline at end of file
+ end
locomotive/steam/middlewares/helpers.rb b/lib/locomotive/steam/middlewares/helpers.rb +28 -0
@@ @@ -0,0 +1,28 @@
+ module Locomotive::Steam
+ module Middlewares
+
+ module Helpers
+
+ def html?
+ ['text/html', 'application/x-www-form-urlencoded'].include?(self.request.media_type) &&
+ !self.request.xhr? &&
+ !self.json?
+ end
+
+ def json?
+ self.request.content_type == 'application/json' || File.extname(self.request.path) == '.json'
+ end
+
+ def redirect_to(location, type = 301)
+ self.log "Redirected to #{location}"
+ [type, { 'Content-Type' => 'text/html', 'Location' => location }, []]
+ end
+
+ def log(msg)
+ Locomotive::Common::Logger.info msg
+ end
+
+ end
+
+ end
+ end
locomotive/steam/middlewares/locale.rb b/lib/locomotive/steam/middlewares/locale.rb +16 -16
@@ @@ -7,33 +7,33 @@ module Locomotive::Steam
# /fr/ => locale = :fr
# /index => locale = :en (default one)
#
- class Locale < Base
+ class Locale < ThreadSafe
- def _call(env)
- super
+ include Helpers
- self.set_locale!(env)
-
- app.call(env)
+ def _call
+ set_locale
end
protected
- def set_locale!(env)
- locale = site.default_locale
+ def set_locale
+ _locale = site.default_locale
+ _path = path
- if self.path =~ /^(#{self.site.locales.join('|')})+(\/|$)/
- locale = $1
- self.path = self.path.gsub($1 + $2, '')
- self.path = 'index' if self.path.blank?
+ if _path =~ /^(#{site.locales.join('|')})+(\/|$)/
+ _locale = $1
+ _path = _path.gsub($1 + $2, '')
+ _path = 'index' if _path.blank?
end
- ::I18n.locale = locale
+ log "Detecting locale #{_locale.upcase}"
- self.log "Detecting locale #{locale.upcase}"
+ services.current_locale = _locale
+ services.repositories.current_locale = _locale
- env['steam.locale'] = locale
- env['steam.path'] = self.path
+ env['steam.locale'] = _locale
+ env['steam.path'] = _path
end
end
locomotive/steam/middlewares/logging.rb b/lib/locomotive/steam/middlewares/logging.rb +4 -2
@@ @@ -3,7 +3,9 @@ module Locomotive::Steam
# Track the request into the current logger
#
- class Logging < Base
+ class Logging < Struct.new(:app)
+
+ include Helpers
def call(env)
now = Time.now
@@ @@ -29,4 +31,4 @@ module Locomotive::Steam
end
end
- end
\ No newline at end of file
+ end
locomotive/steam/middlewares/page.rb b/lib/locomotive/steam/middlewares/page.rb +41 -43
@@ @@ -1,65 +1,63 @@
module Locomotive::Steam
module Middlewares
- # Sanitize the path from the previous middleware in order
- # to make it work for the renderer.
+ # Retrieve a page from the path and the locale previously
+ # fetched from the request.
#
- class Page < Base
+ class Page < ThreadSafe
- def _call(env)
- super
- set_page!(env)
- app.call(env)
- end
-
- protected
+ include Helpers
- def set_page!(env)
- page = fetch_page env['steam.locale']
- if page
+ def _call
+ if page = fetch_page
log "Found page \"#{page.title}\" [#{page.fullpath}]"
end
env['steam.page'] = page
end
- def fetch_page locale
- decorated(locale) do
- Locomotive::Models[:pages].current_locale = locale
- Locomotive::Models[:pages].matching_paths(path_combinations(path)).tap do |pages|
- if pages.size > 1
- self.log "Found multiple pages: #{pages.all.collect(&:title).join(', ')}"
- end
- end.first
+ protected
+
+ def fetch_page
+ if (pages = services.page_finder.find(path)).size > 1
+ titles = pages.map { |p| p.attributes[:title][repository.current_locale] }
+ self.log "Found multiple pages: #{titles.join(', ')}"
end
- end
- def decorated(locale)
- entity = yield
- unless entity.nil?
- # Locomotive::Steam::Decorators::PageDecorator.new(
- # Locomotive::Decorators::I18nDecorator.new(entity, locale))
+ if page = pages.first
+ Locomotive::Steam::Decorators::I18nDecorator.new(page, page.localized_attributes, locale, default_locale)
+ else
+ nil
end
- end
- def path_combinations(path)
- self._path_combinations(path.split('/'))
+ # if page = services.page_finder.find(path)
+ # puts page.inspect
+ # Locomotive::Steam::Decorators::I18nDecorator.new(page, page.localized_attributes, locale, site.default_locale)
+ # else
+ # nil
+ # end
+
+ # decorated(locale) do
+ # Locomotive::Models[:pages].current_locale = locale
+ # Locomotive::Models[:pages].matching_paths(path_combinations(path)).tap do |pages|
+ # if pages.size > 1
+ # self.log "Found multiple pages: #{pages.all.collect(&:title).join(', ')}"
+ # end
+ # end.first
+ # end
end
- def _path_combinations(segments, can_include_template = true)
- return nil if segments.empty?
- segment = segments.shift
+ # def repository
+ # services.repositories.page
+ # end
- (can_include_template ? [segment, '*'] : [segment]).map do |_segment|
- if (_combinations = _path_combinations(segments.clone, can_include_template && _segment != '*'))
- [*_combinations].map do |_combination|
- File.join(_segment, _combination)
- end
- else
- [_segment]
- end
- end.flatten
- end
+ # def decorated(locale)
+ # entity = yield
+ # unless entity.nil?
+ # # Locomotive::Steam::Decorators::PageDecorator.new(
+ # # Locomotive::Decorators::I18nDecorator.new(entity, locale))
+ # end
+ # end
end
locomotive/steam/middlewares/path.rb b/lib/locomotive/steam/middlewares/path.rb +4 -7
@@ @@ -4,13 +4,10 @@ module Locomotive::Steam
# Sanitize the path from the previous middleware in order
# to make it work for the renderer.
#
- class Path < Base
-
- def _call(env)
- super
-
- self.set_path!(env)
+ class Path < Struct.new(:app)
+ def call(env)
+ set_path!(env)
app.call(env)
end
@@ @@ -31,4 +28,4 @@ module Locomotive::Steam
end
end
- end
\ No newline at end of file
+ end
locomotive/steam/middlewares/renderer.rb b/lib/locomotive/steam/middlewares/renderer.rb +28 -15
@@ @@ -1,25 +1,38 @@
module Locomotive::Steam
module Middlewares
- class Renderer < Base
+ class Renderer
- def _call(env)
- super
+ def call(env)
+ response = nil
- if page
- if page.redirect?
- redirect_to(page.redirect_url, page.redirect_type)
- else
- type = page.response_type || 'text/html'
- html = render_page
+ # time = Benchmark.realtime do
+ # puts "[Rendered] TODO"
+ # self.set_accessors(env)
+ response = [200, { 'Content-Type' => 'text/html' }, ['TODO']]
+ # end
- log 'Rendered liquid page template'
+ # puts "[Benchmark][Renderer] Time elapsed #{time*1000} milliseconds"
+ response
- [200, { 'Content-Type' => type }, [html]]
- end
- else
- [404, { 'Content-Type' => 'text/html' }, [render_404]]
- end
+ # if page
+ # if page.redirect?
+ # redirect_to(page.redirect_url, page.redirect_type)
+ # else
+ # type = page.response_type || 'text/html'
+ # html = render_page
+
+ # log 'Rendered liquid page template'
+
+ # [200, { 'Content-Type' => type }, [html]]
+ # end
+ # else
+ # [404, { 'Content-Type' => 'text/html' }, [render_404]]
+ # end
+ end
+
+ def self.call(env)
+ raise 'TODO'
end
protected
locomotive/steam/middlewares/site.rb b/lib/locomotive/steam/middlewares/site.rb +16 -0
@@ @@ -0,0 +1,16 @@
+ module Locomotive::Steam
+ module Middlewares
+
+ # Fetch a site using the site_finder service
+ #
+ class Site < ThreadSafe
+
+ def _call
+ site = services.site_finder.find
+ env['steam.site'] = services.repositories.current_site = site
+ end
+
+ end
+
+ end
+ end
locomotive/steam/middlewares/stack.rb b/lib/locomotive/steam/middlewares/stack.rb +55 -33
@@ @@ -15,61 +15,83 @@ module Locomotive
def create
options = @options
+ # _self = self
Rack::Builder.new do
use Rack::Lint
- use Middlewares::Favicon
+ use Steam::Middlewares::Favicon
- if options[:serve_assets]
- use Middlewares::StaticAssets, {
- urls: ['/images', '/fonts', '/samples', '/media']
- }
- use Middlewares::DynamicAssets
- end
+ # if options[:serve_assets]
+ # use Steam::Middlewares::StaticAssets, {
+ # urls: ['/images', '/fonts', '/samples', '/media']
+ # }
+ # use Steam::Middlewares::DynamicAssets
+ # end
- use Rack::Csrf,
- field: 'authenticity_token',
- skip_if: -> (request) {
- !(request.post? && request.params[:content_type_slug].present?)
- }
+ # use Rack::Csrf,
+ # field: 'authenticity_token',
+ # skip_if: -> (request) {
+ # !(request.post? && request.params[:content_type_slug].present?)
+ # }
- use ::Dragonfly::Middleware, :steam
+ # use ::Dragonfly::Middleware, :steam
- use Rack::Session::Moneta, options[:moneta]
+ # use Rack::Session::Moneta, options[:moneta]
- use_steam_middlewares(self)
+ # _self.send(:use_steam_middlewares, builder)
- run Middlewares::Renderer.new
+ use Middlewares::Logging
+ use Middlewares::Path
+
+ # foo = proc do |env|
+ # puts "[EndPoint] finishing here..."
+ # [ 200, {'Content-Type' => 'text/plain'}, ["b"] ]
+ # end
+
+ # run foo
+
+ run Steam::Middlewares::Renderer.new
end
end
protected
def use_steam_middlewares(builder)
- builder.instance_eval do
- use Middlewares::Logging
+ # builder.use Middlewares::Logging
+ # builder.use Middlewares::Site
+ # builder.use Middlewares::Path
- use Middlewares::EntrySubmission
+ # builder.run Steam::Middlewares::Renderer.new
- use Middlewares::Path
- use Middlewares::Locale
- use Middlewares::Timezone
+ # builder.instance_eval do
+ # use Middlewares::Logging
- use Middlewares::Page
- use Middlewares::TemplatizedPage
- end
- end
+ # use Middlewares::Site
+
+ # # use Middlewares::EntrySubmission
- def prepare_options(options)
- {
- serve_assets: false,
- moneta: {
- store: Moneta.new(:Memory, :expires => true)
- }
- }.merge(options)
+ # use Middlewares::Path
+
+ # nil
+ # # use Middlewares::Locale
+ # # use Middlewares::Timezone
+
+ # # use Middlewares::Page
+ # # use Middlewares::TemplatizedPage
+ # end
+ # nil
end
+ # def prepare_options(options)
+ # {
+ # serve_assets: false,
+ # moneta: {
+ # store: Moneta.new(:Memory, expires: true)
+ # }
+ # }.merge(options)
+ # end
+
end
end
locomotive/steam/middlewares/threadsafe.rb b/lib/locomotive/steam/middlewares/threadsafe.rb +57 -0
@@ @@ -0,0 +1,57 @@
+ module Locomotive::Steam::Middlewares
+
+ class ThreadSafe < Struct.new(:app)
+
+ attr_accessor :env
+
+ def call(env)
+ threadsafed = dup
+ threadsafed.env = env
+
+ # time = Benchmark.realtime do
+ threadsafed._call # thread-safe purpose
+ # end
+
+ # puts "[Benchmark][#{self.class.name}] Time elapsed #{time*1000} milliseconds"
+
+ threadsafed.next
+ end
+
+ def next
+ # avoid to be called twice
+ @next_response || (@next_response = app.call(env))
+ end
+
+ #= Shortcuts =
+
+ def services
+ @services ||= env.fetch('steam.services')
+ end
+
+ def request
+ @request ||= env.fetch('steam.request')
+ end
+
+ def site
+ @site ||= env.fetch('steam.site')
+ end
+
+ def path
+ @path ||= env.fetch('steam.path')
+ end
+
+ def locale
+ @locale ||= env.fetch('steam.locale')
+ end
+
+ def default_locale
+ site.default_locale
+ end
+
+ def params
+ @params ||= self.request.params #.deep_symbolize_keys
+ end
+
+ end
+
+ end
locomotive/steam/middlewares/timezone.rb b/lib/locomotive/steam/middlewares/timezone.rb +12 -7
@@ @@ -3,16 +3,21 @@ module Locomotive::Steam
# Set the timezone according to the settings of the site
#
- class Timezone < Base
+ class Timezone < ThreadSafe
- def _call(env)
- super
+ include Helpers
- Time.use_zone(site.try(:timezone) || 'UTC') do
- app.call(env)
- end
+ def _call
+ timezone = site.try(:timezone) || 'UTC'
+
+ log "Timezone: #{timezone.inspect}"
+
+ # DEBUG
+ # Time.use_zone(timezone) do
+ self.next
+ # end
end
end
end
- end
\ No newline at end of file
+ end
locomotive/steam/repositories.rb b/lib/locomotive/steam/repositories.rb +12 -10
@@ @@ -1,3 +1,4 @@
+ Dir[File.join(File.dirname(__FILE__), 'repositories', 'filesystem', '*.rb')].each { |lib| require lib }
Dir[File.join(File.dirname(__FILE__), 'repositories', '*.rb')].each { |lib| require lib }
require 'morphine'
@@ @@ -6,40 +7,41 @@ module Locomotive
module Steam
module Repositories
- def self.build_instance(site = nil)
- Registered.new(site)
+ def self.build_instance(site = nil, current_locale = nil)
+ Instance.new(site, current_locale)
end
- class Registered < Struct.new(:current_site)
+ class Instance < Struct.new(:current_site, :current_locale)
include Morphine
register :site do
- Repositories::Site.new
+ Steam::Repositories::Filesystem::Site.new
end
register :page do
- Repositories::Page.new(current_site)
+ Steam::Repositories::Filesystem::Page.new(current_site, current_locale)
+ # Steam::Repositories::Page.new(current_site, current_locale)
end
register :content_type do
- Repositories::ContentType.new(current_site)
+ Steam::Repositories::ContentType.new(current_site)
end
register :content_entry do
- Repositories::ContentEntry.new(current_site)
+ Steam::Repositories::ContentEntry.new(current_site)
end
register :snippet do
- Repositories::Snippet.new(current_site)
+ Steam::Repositories::Snippet.new(current_site)
end
register :theme_asset do
- Repositories::ThemeAsset.new(current_site)
+ Steam::Repositories::ThemeAsset.new(current_site)
end
register :translation do
- Repositories::Translation.new(current_site)
+ Steam::Repositories::Translation.new(current_site)
end
end
locomotive/steam/repositories/filesystem/memory_adapter.rb b/lib/locomotive/steam/repositories/filesystem/memory_adapter.rb +1 -0
@@ @@ -0,0 +1 @@
+ Dir[File.join(File.dirname(__FILE__), 'memory_adapter', '*.rb')].each { |lib| require lib }
locomotive/steam/repositories/filesystem/memory_adapter/condition.rb b/lib/locomotive/steam/repositories/filesystem/memory_adapter/condition.rb +101 -0
@@ @@ -0,0 +1,101 @@
+ module Locomotive
+ module Steam
+ module Repositories
+ module Filesystem
+ module MemoryAdapter
+ class Condition
+
+ class UnsupportedOperator < StandardError; end
+
+ OPERATORS = %i(== eq ne neq matches gt gte lt lte size all in nin).freeze
+
+ attr_reader :field, :operator, :value
+
+ def initialize(operator_and_field, value, locale)
+ @locale = locale.to_sym
+ @operator_and_field, @value = operator_and_field, value
+ @operator, @field = :==, nil
+
+ decode_operator_and_field!
+ end
+
+ def matches?(entry)
+ entry_value = entry_value(entry)
+
+ adapt_operator!(entry_value)
+ case @operator
+ when :== then entry_value == @value
+ when :eq then entry_value == @value
+ when :ne then entry_value != @value
+ when :neq then entry_value != @value
+ when :matches then @value =~ entry_value
+ when :gt then entry_value > @value
+ when :gte then entry_value >= @value
+ when :lt then entry_value < @value
+ when :lte then entry_value <= @value
+ when :size then entry_value.size == @value
+ when :all then array_contains?([*@value], entry_value)
+ when :in, :nin then value_is_in_entry_value?(entry_value)
+ else
+ raise UnknownConditionInScope.new("#{@operator} is unknown or not implemented.")
+ end
+ end
+
+ def to_s
+ "#{field} #{operator} #{@value.to_s}"
+ end
+
+ protected
+
+ def entry_value(entry)
+ case (value = entry.send(@field))
+ when Hash
+ value.fetch(@locale) { nil }
+ else
+ value
+ end
+ end
+
+ def decode_operator_and_field!
+ if match = @operator_and_field.match(/^(?<field>[a-z0-9_-]+)\.(?<operator>.*)$/)
+ @field = match[:field].to_sym
+ @operator = match[:operator].to_sym
+ check_operator!
+ end
+
+ @operator = :matches if @value.is_a?(Regexp)
+ end
+
+ def adapt_operator!(value)
+ case value
+ when Array
+ @operator = :in if @operator == :==
+ end
+ end
+
+ def value_is_in_entry_value?(value)
+ _matches = if value.is_a?(Array)
+ array_contains?([*value], [*@value])
+ else
+ [*@value].include?(value)
+ end
+ @operator == :in ? _matches : !_matches
+ end
+
+ private
+
+ def check_operator!
+ raise UnsupportedOperator.new unless OPERATORS.include?(@operator)
+ end
+
+ def array_contains?(source, target)
+ source & target == target
+ end
+
+ end
+
+ end
+ end
+ end
+ end
+ end
locomotive/steam/repositories/filesystem/memory_adapter/query.rb b/lib/locomotive/steam/repositories/filesystem/memory_adapter/query.rb +110 -0
@@ @@ -0,0 +1,110 @@
+ require 'forwardable'
+
+ module Locomotive
+ module Steam
+ module Repositories
+ module Filesystem
+ module MemoryAdapter
+
+ class Query
+
+ include Enumerable
+ extend Forwardable
+
+ def_delegators :all, :each, :to_s, :to_a, :empty?, :size
+
+ alias :length :size
+ alias :count :size
+
+ attr_reader :conditions
+
+ def initialize(dataset, locale=nil, &block)
+ @dataset = dataset
+ @conditions = []
+ @sorting = nil
+ @limit = nil
+ @offset = 0
+ @locale = locale
+ instance_eval(&block) if block_given?
+ end
+
+ def where(conditions = {})
+ @conditions += conditions.map { |name, value| Condition.new(name, value, @locale) }
+ self
+ end
+
+ def +(query)
+ @conditions += query.conditions
+ self
+ end
+
+ def order_by(order_string)
+ @sorting = order_string.downcase.split.map(&:to_sym) unless order_string.empty?
+ self
+ end
+
+ def limit(num)
+ @limit = num
+ self
+ end
+
+ def offset(num)
+ @offset = num
+ self
+ end
+
+ def ==(other)
+ if other.kind_of? Array
+ all == other
+ else
+ super
+ end
+ end
+
+ def all
+ limited sorted(filtered)
+ end
+
+ def sorted(entries)
+ return entries if @sorting.nil?
+
+ name, direction = @sorting.first, (@sorting.last || :asc)
+ if direction == :asc
+ entries.sort { |a, b| a.send(name) <=> b.send(name) }
+ else
+ entries.sort { |a, b| b.send(name) <=> a.send(name) }
+ end
+ end
+
+ def limited(entries)
+ return [] if @limit == 0
+ return entries if @offset == 0 && @limit.nil?
+
+ subentries = entries.drop(@offset || 0)
+ if @limit.kind_of? Integer
+ subentries.take(@limit)
+ else
+ subentries
+ end
+ end
+
+ def filtered
+ @dataset.to_a.dup.find_all do |entry|
+ accepted = true
+
+ @conditions.each do |_condition|
+ unless _condition.matches?(entry)
+ accepted = false
+ break # no to go further
+ end
+ end
+ accepted
+ end
+ end # filtered
+
+ end
+ end
+ end
+ end
+ end
+ end
locomotive/steam/repositories/filesystem/memory_adapter/yaml_loader.rb b/lib/locomotive/steam/repositories/filesystem/memory_adapter/yaml_loader.rb +93 -0
@@ @@ -0,0 +1,93 @@
+ module Locomotive
+ module Steam
+ module Repositories
+ module Filesystem
+ module MemoryAdapter
+
+ class YAMLLoader < Struct.new(:root_path)
+
+ attr_accessor :default_locale
+
+ TEMPLATE_EXTENSIONS = %w(liquid haml)
+
+ @@cache = {}
+
+ def self.instance(path = nil)
+ @@instance ||= self.new(path)
+ end
+
+ def simple(path)
+ @@cache[path] || load(File.join(root_path, path))
+ end
+
+ def tree(path)
+ @@cache[path] || load_tree(File.join(root_path, path)).values
+ end
+
+ private
+
+ def load(path, frontmatter = false)
+ yaml = File.open(path).read.force_encoding('utf-8')
+
+ if frontmatter
+ yaml =~ /^(---\s*\n.*?\n?)^(---\s*$\n?)(.*)/m
+ yaml = $1
+ end
+
+ raw_data = YAML.load(yaml)
+ HashConverter.to_sym(raw_data)
+ end
+
+ def load_tree(path)
+ {}.tap do |hash|
+ Dir.glob(File.join(path, '**', '*')).each do |filepath|
+ next unless filepath =~ /\.(#{TEMPLATE_EXTENSIONS.join('|')})$/
+
+ relative_path = filepath.gsub(path, '').gsub(/^\//, '')
+
+ fullpath, locale = relative_path.split('.')[0..1]
+ locale = default_locale if TEMPLATE_EXTENSIONS.include?(locale)
+
+ if leaf = hash[fullpath]
+ update_leaf(leaf, filepath, fullpath, locale.to_sym)
+ else
+ leaf = get_new_leaf(filepath, fullpath, locale.to_sym)
+ end
+
+ hash[fullpath] = leaf
+ end
+ end
+ end
+
+ def get_new_leaf(filepath, fullpath, locale)
+ slug = fullpath.split('/').last
+ attributes = load(filepath, true)
+
+ {
+ title: { locale => attributes.delete(:title) || (default_locale == locale ? slug.humanize : nil) },
+ slug: { locale => attributes.delete(:slug) || slug },
+ editable_elements: { locale => attributes.delete(:editable_elements) },
+ template_path: { locale => filepath },
+ _fullpath: fullpath
+ }.merge(attributes)
+ end
+
+ def update_leaf(leaf, filepath, fullpath, locale)
+ slug = fullpath.split('/').last
+ attributes = load(filepath, true)
+
+ leaf[:title][locale] = attributes.delete(:title) || slug.humanize
+ leaf[:slug][locale] = attributes.delete(:slug) || slug
+ leaf[:editable_elements][locale] = attributes.delete(:editable_elements)
+ leaf[:template_path][locale] = filepath
+
+ leaf.merge!(attributes)
+ end
+
+ end
+
+ end
+ end
+ end
+ end
+ end
locomotive/steam/repositories/filesystem/models/page.rb b/lib/locomotive/steam/repositories/filesystem/models/page.rb +49 -0
@@ @@ -0,0 +1,49 @@
+ module Locomotive
+ module Steam
+ module Repositories
+ module Filesystem
+ module Models
+
+ class Page < Struct.new(:attributes)
+
+ def initialize(attributes)
+ super({
+ listed: true,
+ published: false,
+ fullpath: {},
+ content_type: nil,
+ position: 100
+ }.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
+
+ def localized_attributes
+ self.class.localized_attributes
+ end
+
+ def self.localized_attributes
+ [:title, :slug, :permalink, :template_path, :fullpath, :seo, :meta_description, :meta_keywords]
+ end
+
+ def to_liquid
+ Steam::Liquids::Drops::Page.new(self, localized_attributes)
+ end
+
+ end
+
+ end
+ end
+ end
+ end
+ end
locomotive/steam/repositories/filesystem/models/site.rb b/lib/locomotive/steam/repositories/filesystem/models/site.rb +41 -0
@@ @@ -0,0 +1,41 @@
+ module Locomotive
+ module Steam
+ module Repositories
+ module Filesystem
+ module Models
+
+ class Site < Struct.new(:attributes)
+
+ attr_accessor :root_path
+
+ def method_missing(name, *args, &block)
+ if attributes.include?(name)
+ attributes[name.to_sym] # getter
+ else
+ super
+ end
+ end
+
+ def localized_attributes
+ [:seo, :meta_description, :meta_keywords]
+ end
+
+ def default_locale
+ self.locales.try(:first) || :en
+ end
+
+ def locales
+ attributes[:locales].map(&:to_sym)
+ end
+
+ def to_liquid
+ Steam::Liquids::Drops::Site.new(self, localized_attributes)
+ end
+
+ end
+
+ end
+ end
+ end
+ end
+ end
locomotive/steam/repositories/filesystem/page.rb b/lib/locomotive/steam/repositories/filesystem/page.rb +87 -0
@@ @@ -0,0 +1,87 @@
+ require_relative 'models/page'
+ require_relative 'sanitizers/page'
+
+ module Locomotive
+ module Steam
+ module Repositories
+ module Filesystem
+
+ class Page < Struct.new(:site, :current_locale)
+
+ def all(conditions = {})
+ raise 'TODO'
+ # site.pages.ordered_pages(conditions)
+ end
+
+ def by_handle(handle)
+ raise 'TODO'
+ # site.pages.where(handle: handle).first
+ end
+
+ def by_fullpath(path)
+ MemoryAdapter::Query.new(collection, current_locale) do
+ where(fullpath: path)
+ end.first
+ end
+
+ def matching_fullpath(list)
+ MemoryAdapter::Query.new(collection, current_locale) do
+ where('fullpath.in' => list)
+ end.all
+ end
+
+ def template_for(entry, handle = nil)
+ # criteria = site.pages.where(target_klass_name: entry.class.to_s, templatized: true)
+ # criteria = criteria.where(handle: handle) if handle
+ # criteria.first.tap do |page|
+ # page.content_entry = entry if page
+ # end
+ end
+
+ def root
+ # site.pages.root.first
+ end
+
+ def parent_of(page)
+ # page.parent
+ end
+
+ def ancestors_of(page)
+ # page.ancestors_and_self
+ end
+
+ def children_of(page)
+ # page.children
+ end
+
+ def editable_elements_of(page)
+ # page.editable_elements
+ end
+
+ def editable_element_for(page, block, slug)
+ # page.editable_elements.where(block: block, slug: slug).first
+ end
+
+ private
+
+ def collection
+ return @collection if @collection
+
+ loader = MemoryAdapter::YAMLLoader.instance
+ list = loader.tree('app/views/pages')
+
+ @collection = list.map do |attributes|
+ Models::Page.new(attributes)
+ end
+
+ Sanitizers::Page.new(@collection, site.locales).apply
+
+ @collection
+ end
+
+ end
+
+ end
+ end
+ end
+ end
locomotive/steam/repositories/filesystem/sanitizers/page.rb b/lib/locomotive/steam/repositories/filesystem/sanitizers/page.rb +88 -0
@@ @@ -0,0 +1,88 @@
+ module Locomotive
+ module Steam
+ module Repositories
+ module Filesystem
+ module Sanitizers
+
+ class Page < Struct.new(:collection, :locales)
+
+ def initialize(collection, locales)
+ super
+
+ @content_types = {}
+ @localized = {}
+ locales.each { |locale| @localized[locale] = {} }
+ end
+
+ def apply
+ sorted_collection.each do |page|
+ locales.each do |locale|
+ modify_if_templatized(page, locale)
+ set_fullpath_for(page, locale)
+ end
+ end
+ end
+
+ def modify_if_templatized(page, locale)
+ content_type = fetch_content_type(parent_fullpath(page))
+
+ if page.templatized? && content_type.nil?
+ # change the slug of a templatized page
+ page.attributes[:slug][locale] = 'content_type_template'
+
+ # make sure its children will have its content type
+ set_content_type(page._fullpath, page.content_type)
+ else
+ page.attributes[:content_type] = content_type
+ end
+ end
+
+ def set_fullpath_for(page, locale)
+ slug = fullpath = page.attributes[:slug][locale].try(:dasherize)
+
+ return if slug.blank?
+
+ if depth(page) > 1
+ base = parent_fullpath(page)
+ fullpath = (fetch_localized_fullpath(base, locale) || base) + '/' + slug
+ end
+
+ set_localized_fullpath(page._fullpath, fullpath, locale)
+ page.attributes[:fullpath][locale] = fullpath
+ end
+
+ def depth(page)
+ page._fullpath.split('/').size
+ end
+
+ def sorted_collection
+ collection.sort { |a, b| depth(a) <=> depth(b) }
+ end
+
+ def parent_fullpath(page)
+ page._fullpath.split('/')[0..-2].join('/')
+ end
+
+ def fetch_content_type(fullpath)
+ @content_types[fullpath]
+ end
+
+ def set_content_type(fullpath, value)
+ @content_types[fullpath] = value
+ end
+
+ def fetch_localized_fullpath(fullpath, locale)
+ @localized[locale][fullpath]
+ end
+
+ def set_localized_fullpath(fullpath, value, locale)
+ @localized[locale][fullpath] = value
+ end
+
+ end
+
+ end
+ end
+ end
+ end
+ end
locomotive/steam/repositories/filesystem/site.rb b/lib/locomotive/steam/repositories/filesystem/site.rb +24 -0
@@ @@ -0,0 +1,24 @@
+ require_relative 'models/site'
+
+ module Locomotive
+ module Steam
+ module Repositories
+ module Filesystem
+
+ class Site
+
+ def by_host(host, options = {})
+ loader = MemoryAdapter::YAMLLoader.instance(options[:path])
+ attributes = loader.simple('config/site.yml')
+
+ Models::Site.new(attributes).tap do |site|
+ loader.default_locale = site.default_locale.to_sym
+ end
+ end
+
+ end
+
+ end
+ end
+ end
+ end
locomotive/steam/repositories/page.rb b/lib/locomotive/steam/repositories/page.rb +1 -1
@@ @@ -2,7 +2,7 @@ module Locomotive
module Steam
module Repositories
- class Page < Struct.new(:site)
+ class Page < Struct.new(:site, :locale)
def all(conditions = {})
site.pages.ordered_pages(conditions)
locomotive/steam/repositories/site.rb b/lib/locomotive/steam/repositories/site.rb +10 -2
@@ @@ -4,14 +4,22 @@ module Locomotive
class Site
- def find_by_host(host)
- raise 'TODO'
+ def by_host(host, options = {})
+ raise "TODO (#{options.inspect})"
+
+ Locomotive::Site.where(:domains.in => host).first
+
+ # Locomotive::Site.first
# TODO multilocales
# query(:en) do
# where('domains.in' => host)
# end.first
end
+ def by_handle(handle)
+ Locomotive::Site.where(handle: handle).first
+ end
+
end
end
locomotive/steam/server.rb b/lib/locomotive/steam/server.rb +23 -35
@@ @@ -1,53 +1,41 @@
- require_relative 'core_ext'
- require_relative 'monkey_patches'
-
- require_relative 'repositories'
- require_relative 'services'
-
- require_relative 'liquid'
require_relative 'middlewares'
module Locomotive::Steam
class Server
- attr_reader :app, :options
+ attr_reader :options
def initialize(options = {})
- @options = options
-
- stack = Middlewares::Stack.new(options)
- @app = stack.create
- end
-
- def call(env)
- dup._call(env) # thread-safe purpose
+ @options = prepare_options(options)
end
- def _call(env)
- set_request(env)
-
- register_services(env)
+ def to_app
+ server = self
- # TODO: A middleware will take care of it.
- # fetch_site(env)
+ Rack::Builder.new do
+ use Rack::Lint
- @app.call(env)
- end
+ use Middlewares::Favicon
- protected
+ use Middlewares::DefaultEnv, server.options
+ use Middlewares::Logging
+ use Middlewares::Site
+ use Middlewares::Path
+ use Middlewares::Locale
+ use Middlewares::Timezone
+ use Middlewares::Page
- def set_request(env)
- env['steam.request'] = Rack::Request.new(env)
+ run Middlewares::Renderer.new
+ end
end
- # TODO: move it the right middleware
- # def fetch_site(env)
- # site = env['steam.services'].site_finder.find
- # env['steam.site'] = env['steam.services'].repositories.current_site = site
- # end
-
- def register_services(env)
- env['steam.services'] = Locomotive::Steam::Services.build_instance(env['steam.request'], options)
+ def prepare_options(options)
+ {
+ serve_assets: false,
+ moneta: {
+ store: Moneta.new(:Memory, expires: true)
+ }
+ }.merge(options)
end
end
locomotive/steam/services.rb b/lib/locomotive/steam/services.rb +22 -14
@@ @@ -7,65 +7,73 @@ module Locomotive
module Services
def self.build_instance(request = nil, options = {})
- Registered.new(request, options)
+ Instance.new(request, options)
end
- class Registered < Struct.new(:request, :options)
+ class Instance < Struct.new(:request, :options)
include Morphine
register :repositories do
- Repositories.build_instance
+ Steam::Repositories.build_instance
end
register :site_finder do
- Services::SiteFinder.new(request, repositories.site, options)
+ Steam::Services::SiteFinder.new(repositories.site, request, options)
+ end
+
+ register :page_finder do
+ Steam::Services::PageFinder.new(repositories.page)
end
register :url_builder do
- Services::UrlBuilder.new(current_site, I18n.locale)
+ Steam::Services::UrlBuilder.new(current_site, current_locale)
end
register :theme_asset_url do
- Services::ThemeAssetUrl.new(repositories.theme_asset, asset_host, configuration.theme_assets_checksum)
+ Steam::Services::ThemeAssetUrl.new(repositories.theme_asset, asset_host, configuration.theme_assets_checksum)
end
register :asset_host do
- Services::AssetHost.new(request, current_site, configuration.asset_host)
+ Steam::Services::AssetHost.new(request, current_site, configuration.asset_host)
end
register :image_resizer do
- Services::ImageResizer.new(::Dragonfly.app(:steam), configuration.assets_path)
+ Steam::Services::ImageResizer.new(::Dragonfly.app(:steam), configuration.assets_path)
end
register :translator do
- Services::Translator.new(repositories.translation, I18n.locale)
+ Steam::Services::Translator.new(repositories.translation, current_locale)
end
register :external_api do
- Services::ExternalAPI.new
+ Steam::Services::ExternalAPI.new
end
register :csrf_protection do
- Services::CsrfProtection.new(configuration.csrf_protection, Rack::Csrf.field, Rack::Csrf.token(request.env))
+ Steam::Services::CsrfProtection.new(configuration.csrf_protection, Rack::Csrf.field, Rack::Csrf.token(request.env))
end
register :cache do
- Services::NoCache.new
+ Steam::Services::NoCache.new
end
register :markdown do
- Services::Markdown.new
+ Steam::Services::Markdown.new
end
register :textile do
- Services::Textile.new
+ Steam::Services::Textile.new
end
register :configuration do
Locomotive::Steam.configuration
end
+ register :current_locale do
+ I18n.locale
+ end
+
def current_site
repositories.current_site
end
locomotive/steam/services/page_finder.rb b/lib/locomotive/steam/services/page_finder.rb +38 -0
@@ @@ -0,0 +1,38 @@
+ module Locomotive
+ module Steam
+ module Services
+
+ class PageFinder < Struct.new(:repository)
+
+ WILDCARD = 'content-type-template'
+
+ def find(path)
+ repository.matching_fullpath(path_combinations(path))
+ end
+
+ private
+
+ def path_combinations(path)
+ _path_combinations(path.split('/'))
+ end
+
+ def _path_combinations(segments, can_include_template = true)
+ return nil if segments.empty?
+ segment = segments.shift
+
+ (can_include_template ? [segment, WILDCARD] : [segment]).map do |_segment|
+ if (_combinations = _path_combinations(segments.clone, can_include_template && _segment != WILDCARD))
+ [*_combinations].map do |_combination|
+ File.join(_segment, _combination)
+ end
+ else
+ [_segment]
+ end
+ end.flatten
+ end
+
+ end
+
+ end
+ end
+ end
locomotive/steam/services/site_finder.rb b/lib/locomotive/steam/services/site_finder.rb +1 -1
@@ @@ -5,7 +5,7 @@ module Locomotive
class SiteFinder < Struct.new(:repository, :request, :options)
def find
- repository.find_by_host(request.host)
+ repository.by_host(request.host, options)
end
end
locomotivecms_steam.gemspec +1 -1
@@ @@ -34,7 +34,7 @@ Gem::Specification.new do |spec|
spec.add_dependency 'coffee-script', '~> 2.3.0'
spec.add_dependency 'compass', '~> 1.0.3'
- spec.add_dependency 'kaminari', '~> 0.16.2'
+ spec.add_dependency 'kaminari', '0.16.1'
spec.add_dependency 'kramdown', '~> 1.5.0'
spec.add_dependency 'RedCloth', '~> 4.2.9'
spec.add_dependency 'haml', '~> 4.0.6'
spec/integration/server/basic_spec.rb +118 -118
@@ @@ -1,169 +1,169 @@
- # require File.dirname(__FILE__) + '/../integration_helper'
-
- # describe Locomotive::Steam::Server do
-
- # include Rack::Test::Methods
+ require File.dirname(__FILE__) + '/../integration_helper'
+
+ describe Locomotive::Steam::Server do
+
+ include Rack::Test::Methods
- # def app
- # run_server
- # end
+ def app
+ run_server
+ end
- # it 'can render the index page', pending: true do
- # get '/index'
- # last_response.status.should 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', pending: true do
- # get '/index'
- # last_response.body.should =~ /Upcoming events/
- # end
+ # it 'shows the index page' do
+ # get '/index'
+ # expect(last_response.body).to match(/Upcoming events/)
+ # end
- # it 'shows the 404 page', pending: true do
- # get '/void'
- # last_response.status.should eq(404)
- # last_response.body.should =~ /page not found/
- # end
+ # it 'shows the 404 page', pending: true do
+ # get '/void'
+ # last_response.status.should eq(404)
+ # last_response.body.should =~ /page not found/
+ # end
- # it 'shows the 404 page with 200 status code when its called explicitly', pending: true do
- # get '/404'
- # last_response.status.should eq(200)
- # last_response.body.should =~ /page not found/
- # end
+ # it 'shows the 404 page with 200 status code when its called explicitly', pending: true do
+ # get '/404'
+ # last_response.status.should eq(200)
+ # last_response.body.should =~ /page not found/
+ # end
- # it 'shows content', pending: true do
- # get '/about-us/jane-doe'
- # last_response.body.should =~ /Lorem ipsum dolor sit amet/
- # end
+ # it 'shows content', pending: true do
+ # get '/about-us/jane-doe'
+ # last_response.body.should =~ /Lorem ipsum dolor sit amet/
+ # end
- # it 'shows a content type template', pending: true do
- # get '/songs/song-number-1'
- # last_response.body.should =~ /Song #1/
- # end
+ # it 'shows a content type template', pending: true do
+ # get '/songs/song-number-1'
+ # last_response.body.should =~ /Song #1/
+ # end
- # it 'renders a page under a templatized one', pending: true do
- # get '/songs/song-number-1/band'
- # last_response.body.should =~ /Song #1/
- # last_response.body.should =~ /Leader: Eddie/
- # end
+ # it 'renders a page under a templatized one', pending: true do
+ # get '/songs/song-number-1/band'
+ # last_response.body.should =~ /Song #1/
+ # last_response.body.should =~ /Leader: Eddie/
+ # end
- # it 'translates strings', pending: true do
- # get '/en'
- # last_response.body.should =~ /Powered by/
- # get '/fr'
- # last_response.body.should =~ /Propulsé par/
- # get '/nb'
- # last_response.body.should_not =~ /Powered by/
- # end
+ # it 'translates strings', pending: true do
+ # get '/en'
+ # last_response.body.should =~ /Powered by/
+ # get '/fr'
+ # last_response.body.should =~ /Propulsé par/
+ # get '/nb'
+ # last_response.body.should_not =~ /Powered by/
+ # end
- # it 'provides translation in scopes', pending: true do
- # get '/'
- # last_response.body.should =~ /scoped_translation=.French./
- # end
+ # it 'provides translation in scopes', pending: true do
+ # get '/'
+ # last_response.body.should =~ /scoped_translation=.French./
+ # end
- # it 'translates a page with link_to tags inside', pending: true do
- # get '/fr/notre-musique'
- # last_response.body.should =~ /<h3><a href="\/fr\/songs\/song-number-8">Song #8<\/a><\/h3>/
- # last_response.body.should =~ /Propulsé par/
- # end
+ # it 'translates a page with link_to tags inside', pending: true do
+ # get '/fr/notre-musique'
+ # last_response.body.should =~ /<h3><a href="\/fr\/songs\/song-number-8">Song #8<\/a><\/h3>/
+ # last_response.body.should =~ /Propulsé par/
+ # end
- # it 'returns all the pages', pending: true do
- # get '/all'
- # last_response.body.should =~ /Home page/
- # last_response.body.should =~ /<li>Home page<\/li>/
- # last_response.body.should =~ /<li>John-doe<\/li>/
- # last_response.body.should =~ /<li>Songs<\/li>/
- # last_response.body.should =~ /<li>A song template<\/li>/
- # end
+ # it 'returns all the pages', pending: true do
+ # get '/all'
+ # last_response.body.should =~ /Home page/
+ # last_response.body.should =~ /<li>Home page<\/li>/
+ # last_response.body.should =~ /<li>John-doe<\/li>/
+ # last_response.body.should =~ /<li>Songs<\/li>/
+ # last_response.body.should =~ /<li>A song template<\/li>/
+ # end
- # describe 'snippets', pending: true do
+ # describe 'snippets', pending: true do
- # it 'includes a basic snippet' do
- # get '/'
- # last_response.body.should =~ /All photos are licensed under Creative Commons\./
- # end
+ # it 'includes a basic snippet' do
+ # get '/'
+ # last_response.body.should =~ /All photos are licensed under Creative Commons\./
+ # end
- # it 'includes a snippet whose name is composed of dash' do
- # get '/'
- # last_response.body.should =~ /<p>A complicated one name indeed.<\/p>/
- # end
+ # it 'includes a snippet whose name is composed of dash' do
+ # get '/'
+ # last_response.body.should =~ /<p>A complicated one name indeed.<\/p>/
+ # end
- # end
+ # end
- # describe 'nav', pending: true do
+ # describe 'nav', pending: true do
- # subject { get '/all'; last_response.body }
+ # subject { get '/all'; last_response.body }
- # it { should_not match(/<nav id="nav">/) }
+ # it { should_not match(/<nav id="nav">/) }
- # it { should match(/<li id="about-us-link" class="link first"><a href="\/about-us">About Us<\/a><\/li>/) }
+ # it { should match(/<li id="about-us-link" class="link first"><a href="\/about-us">About Us<\/a><\/li>/) }
- # it { should match(/<li id="music-link" class="link"><a href="\/music">Music<\/a><\/li>/) }
+ # it { should match(/<li id="music-link" class="link"><a href="\/music">Music<\/a><\/li>/) }
- # it { should match(/<li id="store-link" class="link"><a href="\/store">Store<\/a><\/li>/) }
+ # it { should match(/<li id="store-link" class="link"><a href="\/store">Store<\/a><\/li>/) }
- # it { should match(/<li id="contact-link" class="link last"><a href="\/contact">Contact Us<\/a><\/li>/) }
+ # it { should match(/<li id="contact-link" class="link last"><a href="\/contact">Contact Us<\/a><\/li>/) }
- # it { should_not match(/<li id="events-link" class="link"><a href="\/events">Events<\/a><\/li>/) }
+ # it { should_not match(/<li id="events-link" class="link"><a href="\/events">Events<\/a><\/li>/) }
- # describe 'with wrapper' do
+ # describe 'with wrapper' do
- # subject { get '/tags/nav'; last_response.body }
+ # subject { get '/tags/nav'; last_response.body }
- # it { should match(/<nav id="nav">/) }
+ # it { should match(/<nav id="nav">/) }
- # end
+ # end
- # describe 'very deep' do
+ # describe 'very deep' do
- # subject { get '/tags/nav_in_deep'; last_response.body }
+ # subject { get '/tags/nav_in_deep'; last_response.body }
- # it { should match(/<li id=\"john-doe-link\" class=\"link first last\">/) }
+ # it { should match(/<li id=\"john-doe-link\" class=\"link first last\">/) }
- # end
+ # end
- # end
+ # end
- # describe 'contents with_scope', pending: true do
- # subject { get '/grunge_bands'; last_response.body }
+ # describe 'contents with_scope', pending: true do
+ # subject { get '/grunge_bands'; last_response.body }
- # it { should match(/Layne/)}
- # it { should_not match(/Peter/) }
- # end
+ # it { should match(/Layne/)}
+ # it { should_not match(/Peter/) }
+ # end
- # describe 'pages with_scope', pending: true do
- # subject { get '/unlisted_pages'; last_response.body }
- # it { subject.should match(/Page to test the nav tag/)}
- # it { should_not match(/About Us/)}
- # end
+ # describe 'pages with_scope', pending: true do
+ # subject { get '/unlisted_pages'; last_response.body }
+ # it { subject.should match(/Page to test the nav tag/)}
+ # it { should_not match(/About Us/)}
+ # end
- # describe 'theme assets', pending: true do
+ # describe 'theme assets', pending: true do
- # subject { get '/all'; last_response.body }
+ # subject { get '/all'; last_response.body }
- # it { should match(/<link href="\/stylesheets\/application.css" media="screen" rel="stylesheet" type="text\/css" \/>/) }
+ # it { should match(/<link href="\/stylesheets\/application.css" media="screen" rel="stylesheet" type="text\/css" \/>/) }
- # it { should match(/<script src="\/javascripts\/application.js" type='text\/javascript'><\/script>/) }
+ # it { should match(/<script src="\/javascripts\/application.js" type='text\/javascript'><\/script>/) }
- # it { should match(/<link rel="alternate" type="application\/atom\+xml" title="A title" href="\/foo\/bar" \/>/) }
+ # it { should match(/<link rel="alternate" type="application\/atom\+xml" title="A title" href="\/foo\/bar" \/>/) }
- # end
+ # end
- # describe 'session', pending: true do
+ # describe 'session', pending: true do
- # subject { get '/contest'; last_response.body }
+ # subject { get '/contest'; last_response.body }
- # it { should match(/Your code is: HELLO WORLD/) }
- # it { should_not match(/You've already participated to that contest ! Come back later./) }
+ # it { should match(/Your code is: HELLO WORLD/) }
+ # it { should_not match(/You've already participated to that contest ! Come back later./) }
- # describe 'assign tag' do
+ # describe 'assign tag' do
- # subject { 2.times { get '/contest' }; last_response.body }
+ # subject { 2.times { get '/contest' }; last_response.body }
- # it { should_not match(/Your code is: HELLO WORLD/) }
- # it { should match(/You've already participated to that contest ! Come back later./) }
+ # it { should_not match(/Your code is: HELLO WORLD/) }
+ # it { should match(/You've already participated to that contest ! Come back later./) }
- # end
+ # end
- # end
+ # end
- # end
+ end
spec/spec_helper.rb +3 -2
@@ @@ -13,9 +13,10 @@ SimpleCov.start do
add_group "Liquid Filters", "lib/locomotive/steam/liquid/filters"
add_group "Liquid Tags", "lib/locomotive/steam/liquid/tags"
- add_group "Liquid Drops", "lib/locomotive/steam/liquid/drops"
+ add_group "Liquid Drops", "lib/locomotive/steam/liquid/drops"
add_group "Repositories", "lib/locomotive/steam/repositories"
add_group "Services", "lib/locomotive/steam/services"
+ add_group "Middlewares", "lib/locomotive/steam/middlewares"
end
require 'rubygems'
@@ @@ -38,7 +39,7 @@ RSpec.configure do |config|
config.filter_run focused: true
config.run_all_when_everything_filtered = true
- config.before(:all) { remove_logs }
+ config.before(:all) { remove_logs; setup_common }
config.before { reset! }
config.after { reset! }
config.order = 'random'
spec/support/helpers.rb +6 -8
@@ @@ -1,7 +1,4 @@
require 'locomotive/common'
- # require 'locomotive/models'
- # require 'locomotive/adapters/memory_adapter'
- require_relative '../../lib/locomotive/steam/initializers'
module Spec
module Helpers
@@ @@ -14,17 +11,18 @@ module Spec
FileUtils.rm_rf(File.expand_path('../../fixtures/default/log', __FILE__))
end
- def run_server
+ def setup_common(logger_output = nil)
Locomotive::Common.reset
Locomotive::Common.configure do |config|
- path = File.join(default_fixture_site_path, 'log/locomotivecms.log')
- config.notifier = Locomotive::Common::Logger.setup(path)
+ config.notifier = Locomotive::Common::Logger.setup(logger_output)
end
+ end
- bootstrap_site_content
+ def run_server
+ setup_common(File.join(default_fixture_site_path, 'log/steam.log'))
Locomotive::Common::Logger.info 'Server started...'
- Locomotive::Steam::Server.new(path: default_fixture_site_path)
+ Locomotive::Steam::Server.new(path: default_fixture_site_path).to_app
end
def default_fixture_site_path