filesystem adapter: query now supports multiple directional ordering

did committed Feb 21, 2015
commit c28fb90364660fbf2b31ade4c620364bde22dd31
Showing 12 changed files with 219 additions and 72 deletions
locomotive/steam/adapters/filesystem.rb b/lib/locomotive/steam/adapters/filesystem.rb +31 -19
@@ @@ -1,4 +1,5 @@
require_relative 'filesystem/dataset'
+ require_relative 'filesystem/order'
require_relative 'filesystem/condition'
require_relative 'filesystem/query'
@@ @@ -10,7 +11,7 @@ require_relative 'filesystem/yaml_loaders/page'
module Locomotive::Steam
- class FilesystemAdapter
+ class FilesystemAdapter < Struct.new(:site_path)
include Morphine
@@ @@ -18,53 +19,64 @@ module Locomotive::Steam
Locomotive::Steam::Adapters::Filesystem::SimpleCacheStore.new
end
+ register :yaml_loaders do
+ build_yaml_loaders(cache)
+ end
+
def initialize(site_path)
- @site_path = site_path
- @datasets = {}
+ super
+ @datasets = {}
end
- def all(mapper)
- memoized_dataset(mapper)
+ def all(mapper, scope)
+ memoized_dataset(mapper, scope)
end
def query(mapper, scope, &block)
- _query(mapper, scope.locale, &block).tap do |default|
+ _query(mapper, scope, &block).tap do |default|
if scope.site
- default + _query(mapper) { where(site_id: scope.site.id) }
+ default.where(site_id: scope.site.id)
end
end
end
private
- def _query(mapper, locale = nil, &block)
- Locomotive::Steam::Adapters::Filesystem::Query.new(all(mapper), locale, &block)
+ def _query(mapper, scope, &block)
+ Locomotive::Steam::Adapters::Filesystem::Query.new(all(mapper, scope), scope.locale, &block)
end
- def memoized_dataset(mapper)
+ def memoized_dataset(mapper, scope)
return @datasets[mapper.name] if @datasets[mapper.name]
- dataset(mapper)
+ dataset(mapper, scope)
end
- def dataset(mapper)
+ def dataset(mapper, scope)
Locomotive::Steam::Adapters::Filesystem::Dataset.new(mapper.name).tap do |dataset|
@datasets[mapper.name] = dataset
- collection(mapper).each do |attributes|
+ collection(mapper, scope).each do |attributes|
entity = mapper.to_entity(attributes)
+
+ # assign the site_id to the entity + sanitize attributes
+ # specific to the Filesystem adapter
+ entity[:site_id] = scope.site.id if scope.site
+
dataset.insert(entity)
end
end
end
- def collection(mapper)
- yaml_loader(mapper.name).load
+ def collection(mapper, scope)
+ yaml_loaders[mapper.name].load(scope)
end
- def yaml_loader(name)
- _name = name.to_s.singularize.camelize
- klass = "Locomotive::Steam::Adapters::Filesystem::YAMLLoaders::#{_name}".constantize
- klass.new(@site_path, cache)
+ def build_yaml_loaders(cache)
+ %i(site page).inject({}) do |memo, name|
+ _name = name.to_s.singularize.camelize
+ klass = "Locomotive::Steam::Adapters::Filesystem::YAMLLoaders::#{_name}".constantize
+ memo[name] = klass.new(site_path, cache)
+ end
end
end
locomotive/steam/adapters/filesystem/order.rb b/lib/locomotive/steam/adapters/filesystem/order.rb +59 -0
@@ @@ -0,0 +1,59 @@
+ module Locomotive::Steam
+ module Adapters
+ module Filesystem
+
+ class Order
+
+ attr_reader :list
+
+ def initialize(*args)
+ strings = args.compact
+
+ @list = (case args.size
+ when 0 then []
+ when 1 then args.first.split(',').collect { |s| build(s.strip) }
+ else
+ args.collect { |s| build(s) }
+ end)
+ end
+
+ def empty?
+ @list.empty?
+ end
+
+ def apply_to(entry, locale)
+ @list.collect do |(name, direction)|
+ value = entry.send(name)
+ asc?(direction) ? Asc.new(value) : Desc.new(value)
+ end
+ end
+
+ def asc?(direction)
+ direction.nil? || direction == :asc
+ end
+
+ private
+
+ def build(string)
+ pattern = string.include?('.') ? '.' : ' '
+ string.downcase.split(pattern).map(&:to_sym)
+ end
+
+ class Direction
+ attr_reader :obj
+ def initialize(obj); @obj = obj; end
+ end
+
+ class Asc < Direction
+ def <=>(other); @obj <=> other.obj; end
+ end
+
+ class Desc < Direction
+ def <=>(other); other.obj <=> @obj; end
+ end
+
+ end
+
+ end
+ end
+ end
locomotive/steam/adapters/filesystem/query.rb b/lib/locomotive/steam/adapters/filesystem/query.rb +4 -13
@@ @@ -36,12 +36,8 @@ module Locomotive::Steam
self
end
- def order_by(order_string)
- unless order_string.blank?
- pattern = order_string.include?('.') ? '.' : ' '
- @sorting = order_string.downcase.split(pattern).map(&:to_sym)
- end
- self
+ def order_by(*args)
+ @sorting = Order.new(*args)
end
def limit(num)
@@ @@ -67,14 +63,9 @@ module Locomotive::Steam
end
def sorted(entries)
- return entries if @sorting.nil?
+ return entries if @sorting.empty?
- 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
+ entries.sort_by { |entry| @sorting.apply_to(entry, @locale) }
end
def limited(entries)
locomotive/steam/adapters/filesystem/yaml_loader.rb b/lib/locomotive/steam/adapters/filesystem/yaml_loader.rb +14 -0
@@ @@ -4,6 +4,20 @@ module Locomotive::Steam
module YAMLLoader
+ attr_reader :site_path, :cache
+
+ def initialize(site_path, cache)
+ @site_path, @cache = site_path, cache
+ end
+
+ def load(scope = nil)
+ @scope = scope
+ end
+
+ def default_locale
+ @scope.locale
+ end
+
def fetch(key, &block)
cache.nil? ? yield : cache.fetch(key, &block)
end
locomotive/steam/adapters/filesystem/yaml_loaders/page.rb b/lib/locomotive/steam/adapters/filesystem/yaml_loaders/page.rb +4 -4
@@ @@ -4,19 +4,19 @@ module Locomotive
module Filesystem
module YAMLLoaders
- # class Page < Struct.new(:root_path, :default_locale, :cache)
- class Page < Struct.new(:site_path, :default_locale, :cache)
+ class Page
include Adapters::Filesystem::YAMLLoader
- def load
+ def load(scope)
+ super
fetch('app/views/pages') { load_tree }
end
private
def path
- @path ||= File.join(root_path, 'app', 'views', 'pages')
+ @path ||= File.join(site_path, 'app', 'views', 'pages')
end
def load_tree
locomotive/steam/adapters/filesystem/yaml_loaders/site.rb b/lib/locomotive/steam/adapters/filesystem/yaml_loaders/site.rb +2 -2
@@ @@ -4,11 +4,11 @@ module Locomotive
module Filesystem
module YAMLLoaders
- class Site < Struct.new(:site_path, :cache)
+ class Site
include Adapters::Filesystem::YAMLLoader
- def load
+ def load(scope)
fetch('config/site') do
[_load(File.join(site_path, 'config', 'site.yml'))]
end
locomotive/steam/models/i18n_field.rb b/lib/locomotive/steam/models/i18n_field.rb +4 -0
@@ @@ -19,6 +19,10 @@ module Locomotive::Steam
@translations[locale]
end
+ def values
+ @translations.values
+ end
+
end
end
locomotive/steam/repositories/page_repository.rb b/lib/locomotive/steam/repositories/page_repository.rb +5 -3
@@ @@ -9,10 +9,12 @@ module Locomotive
set_localized_attributes :title, :slug, :permalink, :editable_elements, :template, :template_path, :redirect_url, :fullpath, :seo_title, :meta_description, :meta_keywords
end
- # Engine: site.pages.ordered_pages(conditions)
+ # Engine: site.pages.ordered_pages(conditions) [WIP]
def all(conditions = {})
- default_order = 'depth_and_position asc'
- query { where(conditions || {}).order_by(default_order) }.all
+ query do
+ where(conditions || {}).
+ order_by('depth.asc', 'position.asc')
+ end.all
end
# Engine: site.pages.where(handle: handle).first
spec/unit/adapters/filesystem/order_spec.rb +67 -0
@@ @@ -0,0 +1,67 @@
+ require 'spec_helper'
+
+ require_relative '../../../../lib/locomotive/steam/adapters/filesystem/order.rb'
+
+ describe Locomotive::Steam::Adapters::Filesystem::Order do
+
+ let(:order) { Locomotive::Steam::Adapters::Filesystem::Order.new(*input) }
+
+ describe '#list' do
+
+ subject { order.list }
+
+ let(:input) { nil }
+ it { is_expected.to eq [] }
+
+ context 'a string' do
+
+ let(:input) { 'name' }
+ it { is_expected.to eq [[:name]] }
+
+ end
+
+ context 'two strings' do
+
+ let(:input) { ['name', 'date.desc'] }
+ it { is_expected.to eq [[:name], [:date, :desc]] }
+
+ end
+
+ context 'a string with a comma' do
+
+ let(:input) { 'name, date desc' }
+ it { is_expected.to eq [[:name], [:date, :desc]] }
+
+ end
+
+ end
+
+ describe '#apply_to' do
+
+ subject { order.apply_to(entry, :en) }
+
+ let(:input) { 'title, date desc' }
+ let(:entry) { instance_double('Entry', title: 'foo', date: Time.now) }
+ it { expect(subject.map(&:class)).to eq([Locomotive::Steam::Adapters::Filesystem::Order::Asc, Locomotive::Steam::Adapters::Filesystem::Order::Desc]) }
+
+ end
+
+ describe 'sort' do
+
+ let(:array) {
+ [
+ instance_double('Entry1', id: 1, title: 'b', position: 1),
+ instance_double('Entry2', id: 2, title: 'b', position: 2),
+ instance_double('Entry3', id: 3, title: 'a', position: 3),
+ instance_double('Entry3', id: 4, title: 'c', position: 1)
+ ]
+ }
+ let(:input) { 'title, position desc' }
+
+ subject { array.sort_by { |entry| order.apply_to(entry, :en) } }
+
+ it { expect(subject.map(&:id)).to eq([3, 2, 1, 4]) }
+
+ end
+
+ end
spec/unit/adapters/filesystem/yaml_loaders/page_spec.rb +18 -14
@@ @@ -1,21 +1,25 @@
- # require 'spec_helper'
+ require 'spec_helper'
- # describe Locomotive::Steam::Repositories::Filesystem::YAMLLoaders::Page do
+ require_relative '../../../../../lib/locomotive/steam/adapters/filesystem/yaml_loader.rb'
+ require_relative '../../../../../lib/locomotive/steam/adapters/filesystem/yaml_loaders/page.rb'
- # let(:root_path) { default_fixture_site_path }
- # let(:default_locale) { :en }
- # let(:cache) { NoCacheStore.new }
- # let(:loader) { Locomotive::Steam::Repositories::Filesystem::YAMLLoaders::Page.new(root_path, default_locale, cache) }
+ describe Locomotive::Steam::Adapters::Filesystem::YAMLLoaders::Page do
- # describe '#list_of_attributes' do
+ let(:site_path) { default_fixture_site_path }
+ let(:cache) { NoCacheStore.new }
+ let(:loader) { Locomotive::Steam::Adapters::Filesystem::YAMLLoaders::Page.new(site_path, cache) }
- # subject { loader.list_of_attributes.sort { |a, b| a[:_fullpath] <=> b[:_fullpath] } }
+ describe '#load' do
- # it 'tests various stuff' do
- # expect(subject.size).to eq 21
- # expect(subject.first[:title]).to eq({ en: 'Page not found' })
- # end
+ let(:scope) { instance_double('Scope', locale: :en) }
- # end
+ subject { loader.load(scope).sort { |a, b| a[:_fullpath] <=> b[:_fullpath] } }
- # end
+ it 'tests various stuff' do
+ expect(subject.size).to eq 21
+ expect(subject.first[:title]).to eq({ en: 'Page not found' })
+ end
+
+ end
+
+ end
spec/unit/adapters/filesystem/yaml_loaders/site_spec.rb +5 -4
@@ @@ -1,16 +1,17 @@
require 'spec_helper'
- require_relative '../../../lib/locomotive/steam/adapters/filesystem/yaml_loaders/site.rb'
+ require_relative '../../../../../lib/locomotive/steam/adapters/filesystem/yaml_loader.rb'
+ require_relative '../../../../../lib/locomotive/steam/adapters/filesystem/yaml_loaders/site.rb'
describe Locomotive::Steam::Adapters::Filesystem::YAMLLoaders::Site do
- let(:root_path) { default_fixture_site_path }
+ let(:site_path) { default_fixture_site_path }
let(:cache) { NoCacheStore.new }
- let(:loader) { Locomotive::Steam::Adapters::Filesystem::YAMLLoaders::Site.new(root_path, cache) }
+ let(:loader) { Locomotive::Steam::Adapters::Filesystem::YAMLLoaders::Site.new(site_path, cache) }
describe '#load' do
- subject { loader.load }
+ subject { loader.load(nil) }
it { expect(subject.first[:name]).to eq 'Sample website' }
spec/unit/repositories/page_repository_spec.rb +6 -13
@@ @@ -4,23 +4,16 @@ require_relative '../../../lib/locomotive/steam/adapters/filesystem.rb'
describe Locomotive::Steam::PageRepository do
+ let(:pages) { [{ title: { en: 'Home' }, handle: 'home', slug: { en: 'index' }, _fullpath: 'index', template_path: { en: 'index.liquid' } }] }
+
let(:locale) { :en }
- let(:site) { instance_double('Site', _id: 1, default_locale: :en, locales: %i(en fr)) }
+ let(:site) { instance_double('Site', id: 1, default_locale: :en, locales: %i(en fr)) }
let(:adapter) { Locomotive::Steam::FilesystemAdapter.new(nil) }
let(:repository) { Locomotive::Steam::PageRepository.new(adapter, site, locale) }
- # describe '#collection' do
-
- # subject { repository.send(:collection).first }
-
- # it { expect(subject.class).to eq Locomotive::Steam::Repositories::Filesystem::Models::Page }
-
- # it 'applies the sanitizer' do
- # expect(subject[:fullpath]).to eq({ en: 'index' })
- # expect(subject.depth).to eq 0
- # end
-
- # end
+ before do
+ allow(adapter).to receive(:collection).and_return(pages)
+ end
describe '#all' do