close #34. Pagination for content entries implemented + do not use Kaminari anymore + fix a couple of tiny bugs (wrong field name for the default order_by field of a has_many relationship, automatically remove the order_by attribute from a query selector, ...etc)
did
committed Mar 20, 2015
commit 3b6daf8ee49801fc1b44d83c934d7ebcf9d9b6d8
Showing 31
changed files with
417 additions
and 368 deletions
Gemfile
+2
-0
| @@ | @@ -19,6 +19,8 @@ group :test do |
| gem 'pry-byebug', '~> 3.0.1' | |
| + | gem 'rack-test', '~> 0.6.3' |
| + | |
| gem 'codeclimate-test-reporter', '~> 0.4.7', require: false | |
| gem 'coveralls', '~> 0.7.11', require: false | |
| end | |
Gemfile.lock
+1
-29
| @@ | @@ -10,7 +10,6 @@ PATH |
| dragonfly (~> 1.0.7) | |
| haml (~> 4.0.6) | |
| httparty (~> 0.13.3) | |
| - | kaminari (~> 0.16.3) |
| kramdown (~> 1.6.0) | |
| locomotivecms-solid (~> 4.0.0.alpha2) | |
| locomotivecms_common (~> 0.0.2) | |
| @@ | @@ -30,19 +29,6 @@ GEM |
| remote: https://rubygems.org/ | |
| specs: | |
| RedCloth (4.2.9) | |
| - | actionpack (4.2.0) |
| - | actionview (= 4.2.0) |
| - | activesupport (= 4.2.0) |
| - | rack (~> 1.6.0) |
| - | rack-test (~> 0.6.2) |
| - | rails-dom-testing (~> 1.0, >= 1.0.5) |
| - | rails-html-sanitizer (~> 1.0, >= 1.0.1) |
| - | actionview (4.2.0) |
| - | activesupport (= 4.2.0) |
| - | builder (~> 3.1) |
| - | erubis (~> 2.7.0) |
| - | rails-dom-testing (~> 1.0, >= 1.0.5) |
| - | rails-html-sanitizer (~> 1.0, >= 1.0.1) |
| activesupport (4.2.0) | |
| i18n (~> 0.7) | |
| json (~> 1.7, >= 1.7.7) | |
| @@ | @@ -51,7 +37,6 @@ GEM |
| tzinfo (~> 1.1) | |
| addressable (2.3.7) | |
| bson (2.3.0) | |
| - | builder (3.2.2) |
| byebug (3.5.1) | |
| columnize (~> 0.8) | |
| debugger-linecache (~> 1.2) | |
| @@ | @@ -95,7 +80,6 @@ GEM |
| addressable (~> 2.3) | |
| multi_json (~> 1.0) | |
| rack | |
| - | erubis (2.7.0) |
| eventmachine (1.0.4) | |
| execjs (2.4.0) | |
| ffi (1.9.8) | |
| @@ | @@ -114,17 +98,12 @@ GEM |
| json_spec (1.1.4) | |
| multi_json (~> 1.0) | |
| rspec (>= 2.0, < 4.0) | |
| - | kaminari (0.16.3) |
| - | actionpack (>= 3.0.0) |
| - | activesupport (>= 3.0.0) |
| kramdown (1.6.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) | |
| mime-types (2.4.3) | |
| mimetype-fu (0.1.2) | |
| @@ | @@ -160,14 +139,6 @@ GEM |
| rack (>= 1.0) | |
| rack_csrf (2.5.0) | |
| rack (>= 1.1.0) | |
| - | rails-deprecated_sanitizer (1.0.3) |
| - | activesupport (>= 4.2.0.alpha) |
| - | rails-dom-testing (1.0.5) |
| - | activesupport (>= 4.2.0.beta, < 5.0) |
| - | nokogiri (~> 1.6.0) |
| - | rails-deprecated_sanitizer (>= 1.0.1) |
| - | rails-html-sanitizer (1.0.2) |
| - | loofah (~> 2.0) |
| rake (10.4.2) | |
| rb-fsevent (0.9.4) | |
| rb-inotify (0.9.5) | |
| @@ | @@ -235,6 +206,7 @@ DEPENDENCIES |
| moped (~> 2.0.4) | |
| origin (~> 2.1.1) | |
| pry-byebug (~> 3.0.1) | |
| + | rack-test (~> 0.6.3) |
| rake (~> 10.4.2) | |
| rspec (~> 3.2.0) | |
| thin | |
locomotive/steam.rb b/lib/locomotive/steam.rb
+0
-1
| @@ | @@ -7,7 +7,6 @@ require 'active_support/core_ext' |
| require_relative 'steam/core_ext' | |
| require_relative 'steam/configuration' | |
| - | require_relative_all 'steam/monkey_patches' |
| require_relative_all 'steam/decorators' | |
| require_relative 'steam/liquid' | |
locomotive/steam/adapters/filesystem.rb b/lib/locomotive/steam/adapters/filesystem.rb
+4
-0
| @@ | @@ -50,6 +50,10 @@ module Locomotive::Steam |
| '' | |
| end | |
| + | def count(mapper, scope, &block) |
| + | query(mapper, scope, &block).count |
| + | end |
| + | |
| private | |
| def _query(mapper, scope, &block) | |
locomotive/steam/adapters/filesystem/yaml_loaders/content_entry.rb b/lib/locomotive/steam/adapters/filesystem/yaml_loaders/content_entry.rb
+1
-1
| @@ | @@ -50,7 +50,7 @@ module Locomotive |
| attributes[:"#{field.name}_id"] = attributes.delete(field.name.to_sym) | |
| # _position_in_<name> | |
| - | attributes[:"_position_in_#{field.name}"] = attributes[:_position] |
| + | attributes[:"position_in_#{field.name}"] = attributes[:_position] |
| end | |
| def modify_many_to_many_association(field, attributes) | |
locomotive/steam/adapters/mongodb.rb b/lib/locomotive/steam/adapters/mongodb.rb
+9
-0
| @@ | @@ -18,6 +18,15 @@ module Locomotive::Steam |
| all(mapper, query) | |
| end | |
| + | def count(mapper, scope, &block) |
| + | query = query_klass.new(scope, mapper.localized_attributes, &block) |
| + | query.against(collection(mapper)).count |
| + | end |
| + | |
| + | def find(mapper, scope, id) |
| + | query(mapper, scope) { where(_id: BSON::ObjectId.from_string(id)) }.first |
| + | end |
| + | |
| def key(name, operator) | |
| name.__send__(operator) | |
| end | |
locomotive/steam/adapters/mongodb/query.rb b/lib/locomotive/steam/adapters/mongodb/query.rb
+13
-3
| @@ | @@ -7,7 +7,7 @@ module Locomotive::Steam |
| attr_reader :criteria, :sort | |
| def initialize(scope, localized_attributes, &block) | |
| - | @criteria, @sort, @fields = {}, nil, nil |
| + | @criteria, @sort, @fields, @skip, @limit = {}, nil, nil, nil, nil |
| @scope, @localized_attributes = scope, localized_attributes | |
| apply_default_scope | |
| @@ | @@ -33,13 +33,23 @@ module Locomotive::Steam |
| end | |
| end | |
| + | def offset(offset) |
| + | self.tap { @skip = offset } |
| + | end |
| + | |
| + | def limit(limit) |
| + | self.tap { @limit = limit } |
| + | end |
| + | |
| def against(collection) | |
| _query = to_origin | |
| selector, fields, sort = _query.selector, _query.options[:fields], _query.options[:sort] | |
| collection.find(selector).tap do |results| | |
| - | results.sort(sort) if sort |
| - | results.select(fields) if fields |
| + | results.sort(sort) if sort |
| + | results.select(fields) if fields |
| + | results.skip(@skip) if @skip |
| + | results.limit(@limit) if @limit |
| end | |
| end | |
locomotive/steam/entities/content_type_field.rb b/lib/locomotive/steam/entities/content_type_field.rb
+6
-3
| @@ | @@ -24,9 +24,12 @@ module Locomotive::Steam |
| end | |
| def order_by | |
| - | return self[:order_by] if self[:order_by] |
| - | |
| - | type == :has_many ? "position_in_#{self[:inverse_of]}" : nil |
| + | if (order_by = self[:order_by]).present? |
| + | name, direction = order_by.split |
| + | { name.to_sym => direction || 'asc' } |
| + | else |
| + | type == :has_many ? { :"position_in_#{self[:inverse_of]}" => 'asc' } : nil |
| + | end |
| end | |
| alias :target :class_name | |
locomotive/steam/liquid.rb b/lib/locomotive/steam/liquid.rb
+0
-1
| @@ | @@ -4,6 +4,5 @@ require_relative 'liquid/errors' |
| require_relative 'liquid/patches' | |
| require_relative 'liquid/drops/base' | |
| require_relative 'liquid/drops/i18n_base' | |
| - | require_relative 'liquid/drops/proxy_collection' |
| require_relative 'liquid/tags/hybrid' | |
| require_relative_all %w(. drops filters tags/concerns tags), 'liquid' | |
locomotive/steam/liquid/drops/content_entry_collection.rb b/lib/locomotive/steam/liquid/drops/content_entry_collection.rb
+77
-0
| @@ | @@ -0,0 +1,77 @@ |
| + | module Locomotive |
| + | module Steam |
| + | module Liquid |
| + | module Drops |
| + | |
| + | class ContentEntryCollection < ::Liquid::Drop |
| + | |
| + | delegate :first, :last, :each, :each_with_index, :empty?, :any?, to: :collection |
| + | |
| + | def initialize(content_type, repository = nil) |
| + | @content_type = content_type |
| + | @repository = repository |
| + | end |
| + | |
| + | def all |
| + | collection |
| + | end |
| + | |
| + | def count |
| + | repository.count(conditions) |
| + | end |
| + | |
| + | alias :size :count |
| + | alias :length :count |
| + | |
| + | def public_submission_url |
| + | services.url_builder.public_submission_url_for(@content_type) |
| + | end |
| + | |
| + | def api |
| + | Locomotive::Common::Logger.warn "[Liquid template] the api for content_types has been deprecated and replaced by public_submission_url instead." |
| + | { 'create' => public_submission_url } |
| + | end |
| + | |
| + | def before_method(meth) |
| + | if (meth.to_s =~ /^group_by_(.+)$/) == 0 |
| + | repository.group_by_select_option(@content_type, $1) |
| + | elsif (meth.to_s =~ /^(.+)_options$/) == 0 |
| + | content_type_repository.select_options(@content_type, $1) |
| + | else |
| + | Locomotive::Common::Logger.warn "[Liquid template] trying to call #{meth} on a content_type object" |
| + | nil |
| + | end |
| + | end |
| + | |
| + | protected |
| + | |
| + | def slice(index, length) |
| + | repository.all(conditions) { offset(index).limit(length) } |
| + | end |
| + | |
| + | def collection |
| + | @collection ||= repository.all(conditions) |
| + | end |
| + | |
| + | def conditions |
| + | @context['with_scope'] |
| + | end |
| + | |
| + | def services |
| + | @context.registers[:services] |
| + | end |
| + | |
| + | def content_type_repository |
| + | services.repositories.content_type |
| + | end |
| + | |
| + | def repository |
| + | @repository || services.repositories.content_entry.with(@content_type) |
| + | end |
| + | |
| + | end |
| + | |
| + | end |
| + | end |
| + | end |
| + | end |
locomotive/steam/liquid/drops/content_types.rb b/lib/locomotive/steam/liquid/drops/content_types.rb
+1
-52
| @@ | @@ -8,7 +8,7 @@ module Locomotive |
| repository = @context.registers[:services].repositories.content_type | |
| if content_type = repository.by_slug(meth.to_s) | |
| - | ContentTypeProxyCollection.new(content_type) |
| + | ContentEntryCollection.new(content_type) |
| else | |
| nil | |
| end | |
| @@ | @@ -16,57 +16,6 @@ module Locomotive |
| end | |
| - | class ContentTypeProxyCollection < ProxyCollection |
| - | |
| - | def initialize(content_type) |
| - | @content_type = content_type |
| - | super(nil) |
| - | end |
| - | |
| - | def public_submission_url |
| - | services.url_builder.public_submission_url_for(@content_type) |
| - | end |
| - | |
| - | def api |
| - | Locomotive::Common::Logger.warn "[Liquid template] the api for content_types has been deprecated and replaced by public_submission_url instead." |
| - | { 'create' => public_submission_url } |
| - | end |
| - | |
| - | def before_method(meth) |
| - | if (meth.to_s =~ /^group_by_(.+)$/) == 0 |
| - | repository.group_by_select_option(@content_type, $1) |
| - | elsif (meth.to_s =~ /^(.+)_options$/) == 0 |
| - | content_type_repository.select_options(@content_type, $1) |
| - | else |
| - | Locomotive::Common::Logger.warn "[Liquid template] trying to call #{meth} on a content_type object" |
| - | nil |
| - | end |
| - | end |
| - | |
| - | protected |
| - | |
| - | def paginate(options = {}) |
| - | raise "TODO #{options.inspect}" |
| - | end |
| - | |
| - | def services |
| - | @context.registers[:services] |
| - | end |
| - | |
| - | def content_type_repository |
| - | services.repositories.content_type |
| - | end |
| - | |
| - | def collection |
| - | @collection ||= repository.all(@context['with_scope']) |
| - | end |
| - | |
| - | def repository |
| - | services.repositories.content_entry.with(@content_type) |
| - | end |
| - | |
| - | end |
| - | |
| end | |
| end | |
| end | |
locomotive/steam/liquid/drops/page.rb b/lib/locomotive/steam/liquid/drops/page.rb
+1
-1
| @@ | @@ -41,7 +41,7 @@ module Locomotive |
| if @_source.content_type | |
| # content_type can be either the slug of a content type or a content type | |
| content_type = content_type_repository.by_slug(@_source.content_type) | |
| - | ContentTypeProxyCollection.new(content_type) |
| + | ContentEntryCollection.new(content_type) |
| else | |
| nil | |
| end | |
locomotive/steam/liquid/drops/proxy_collection.rb b/lib/locomotive/steam/liquid/drops/proxy_collection.rb
+0
-33
| @@ | @@ -1,33 +0,0 @@ |
| - | module Locomotive |
| - | module Steam |
| - | module Liquid |
| - | module Drops |
| - | |
| - | class ProxyCollection < ::Liquid::Drop |
| - | |
| - | attr_reader :collection |
| - | |
| - | delegate :first, :last, :each, :each_with_index, :empty?, :any?, to: :collection |
| - | |
| - | def initialize(collection) |
| - | @collection = collection |
| - | end |
| - | |
| - | def count |
| - | @count ||= collection.count |
| - | end |
| - | |
| - | def all |
| - | collection |
| - | self |
| - | end |
| - | |
| - | alias :size :count |
| - | alias :length :count |
| - | |
| - | end |
| - | |
| - | end |
| - | end |
| - | end |
| - | end |
locomotive/steam/liquid/tags/paginate.rb b/lib/locomotive/steam/liquid/tags/paginate.rb
+3
-7
| @@ | @@ -56,16 +56,12 @@ module Locomotive |
| collection = context[@collection_name] | |
| current_page = context['current_page'] | |
| - | raise ::Liquid::ArgumentError.new("Cannot paginate array '#{@collection_name}'. Not found.") if collection.nil? |
| + | raise ::Liquid::ArgumentError.new("Cannot paginate '#{@collection_name}'. Not found.") if collection.nil? |
| - | pagination = (if collection.is_a?(Array) |
| - | Kaminari.paginate_array(collection).page(current_page).per(@per_page) |
| - | else |
| - | collection.send(:paginate, page: current_page, per_page: @per_page) |
| - | end) |
| + | pager = Locomotive::Steam::Models::Pager.new(collection, current_page, @per_page) |
| # make sure the pagination object is a hash with strings as keys (and not symbol) | |
| - | HashConverter.to_string(pagination.to_liquid).tap do |_pagination| |
| + | HashConverter.to_string(pager.to_liquid).tap do |_pagination| |
| _pagination['parts'] = [] | |
| end | |
| end | |
locomotive/steam/models.rb b/lib/locomotive/steam/models.rb
+1
-0
| @@ | @@ -9,3 +9,4 @@ require_relative 'models/entity' |
| require_relative 'models/mapper' | |
| require_relative 'models/scope' | |
| require_relative 'models/repository' | |
| + | require_relative 'models/pager' |
locomotive/steam/models/associations/has_many.rb b/lib/locomotive/steam/models/associations/has_many.rb
+0
-1
| @@ | @@ -1,7 +1,6 @@ |
| module Locomotive::Steam | |
| module Models | |
| - | # Note: represents an embedded collection |
| class HasManyAssociation < ReferencedAssociation | |
| def __load__ | |
locomotive/steam/models/associations/many_to_many.rb b/lib/locomotive/steam/models/associations/many_to_many.rb
+0
-1
| @@ | @@ -1,7 +1,6 @@ |
| module Locomotive::Steam | |
| module Models | |
| - | # Note: represents an embedded collection |
| class ManyToManyAssociation < ReferencedAssociation | |
| def __load__ | |
locomotive/steam/models/pager.rb b/lib/locomotive/steam/models/pager.rb
+53
-0
| @@ | @@ -0,0 +1,53 @@ |
| + | module Locomotive::Steam |
| + | module Models |
| + | |
| + | class Pager |
| + | |
| + | DEFAULT_PER_PAGE = 10.freeze |
| + | |
| + | attr_reader :collection, :current_page, :per_page, :total_pages, :total_entries |
| + | |
| + | def initialize(source, page, per_page) |
| + | @current_page, @per_page = page || 1, per_page || DEFAULT_PER_PAGE |
| + | |
| + | @total_entries = source.count |
| + | @total_pages = (@total_entries.to_f / @per_page).ceil |
| + | |
| + | index = (@current_page - 1) * @per_page |
| + | offset = (index + @per_page - 1) >= @total_entries ? @total_entries : (index + @per_page - 1) |
| + | |
| + | @collection = paginate(source, index, offset) |
| + | end |
| + | |
| + | def previous_page |
| + | current_page <= 1 ? nil : current_page - 1 |
| + | end |
| + | |
| + | def next_page |
| + | current_page >= total_pages ? nil : current_page + 1 |
| + | end |
| + | |
| + | def to_liquid |
| + | { |
| + | collection: collection, |
| + | current_page: current_page, |
| + | per_page: per_page, |
| + | previous_page: previous_page, |
| + | next_page: next_page, |
| + | total_entries: total_entries, |
| + | total_pages: total_pages |
| + | } |
| + | end |
| + | |
| + | private |
| + | |
| + | def paginate(source, index, offset) |
| + | limit = offset - index + 1 |
| + | limit = 0 if limit < 1 |
| + | source.send(:slice, index, limit) || [] |
| + | end |
| + | |
| + | end |
| + | |
| + | end |
| + | end |
locomotive/steam/models/repository.rb b/lib/locomotive/steam/models/repository.rb
+9
-3
| @@ | @@ -39,6 +39,10 @@ module Locomotive::Steam |
| adapter.query(mapper, scope, &block) | |
| end | |
| + | def count(&block) |
| + | adapter.count(mapper, scope, &block) |
| + | end |
| + | |
| def first(&block) | |
| adapter.query(mapper, scope, &block).first | |
| end | |
| @@ | @@ -66,12 +70,14 @@ module Locomotive::Steam |
| end | |
| def prepare_conditions(*conditions) | |
| - | first = { order_by: @local_conditions.delete(:order_by) }.delete_if { |_, v| v.blank? } |
| + | _local_conditions = @local_conditions.dup |
| + | |
| + | first = { order_by: _local_conditions.delete(:order_by) }.delete_if { |_, v| v.blank? } |
| - | [first, *conditions].inject({}) do |memo, hash| |
| + | [first, *conditions.flatten].inject({}) do |memo, hash| |
| memo.merge!(hash) unless hash.blank? | |
| memo | |
| - | end.merge(@local_conditions) |
| + | end.merge(_local_conditions) |
| end | |
| # TODO: not sure about that. could it be used further in the dev | |
locomotive/steam/monkey_patches/haml.rb b/lib/locomotive/steam/monkey_patches/haml.rb
+0
-17
| @@ | @@ -1,17 +0,0 @@ |
| - | # require 'haml' |
| - | |
| - | # module Haml::Filters |
| - | |
| - | # remove_filter("Markdown") #remove the existing Markdown filter |
| - | |
| - | # module Markdown # the contents of this are as before, but without the lazy_require call |
| - | |
| - | # include Haml::Filters::Base |
| - | |
| - | # def render text |
| - | # Locomotive::Steam::Markdown.new.render text |
| - | # end |
| - | |
| - | # end |
| - | |
| - | # end |
locomotive/steam/monkey_patches/kaminari.rb b/lib/locomotive/steam/monkey_patches/kaminari.rb
+0
-45
| @@ | @@ -1,45 +0,0 @@ |
| - | # Note: avoid this issue https://github.com/amatsuda/kaminari/issues/518 |
| - | require 'kaminari/config' |
| - | require 'kaminari/models/configuration_methods' |
| - | require 'kaminari/models/page_scope_methods' |
| - | require 'kaminari/models/array_extension' |
| - | |
| - | module Kaminari |
| - | |
| - | module PageScopeMethods |
| - | |
| - | def to_liquid(options = {}) |
| - | { |
| - | collection: to_a, |
| - | current_page: current_page, |
| - | previous_page: first_page? ? nil : current_page - 1, |
| - | total_entries: total_count, |
| - | per_page: limit_value |
| - | }.tap do |hash| |
| - | # note: very important to avoid extra and useless mongodb requests |
| - | hash[:total_pages] = (hash[:total_entries].to_f / limit_value).ceil |
| - | hash[:next_page] = current_page >= hash[:total_pages] ? nil : current_page + 1 |
| - | end |
| - | end |
| - | |
| - | end |
| - | |
| - | # FIXME: it does not seem to be called |
| - | # class PaginatableArray < Array |
| - | |
| - | # def to_liquid(options = {}) |
| - | # puts "PaginatableArray.instance.to_liquid" |
| - | # { |
| - | # collection: to_a, |
| - | # current_page: current_page, |
| - | # previous_page: first_page? ? nil : current_page - 1, |
| - | # next_page: last_page? ? nil : current_page + 1, |
| - | # total_entries: total_count, |
| - | # total_pages: num_pages, |
| - | # per_page: limit_value |
| - | # } |
| - | # end |
| - | |
| - | # end |
| - | |
| - | end |
locomotive/steam/repositories/content_entry_repository.rb b/lib/locomotive/steam/repositories/content_entry_repository.rb
+30
-7
| @@ | @@ -32,29 +32,38 @@ module Locomotive |
| self # chainable | |
| end | |
| - | def all(conditions = {}) |
| - | conditions = prepare_conditions({ _visible: true }, conditions) |
| + | def all(conditions = {}, &block) |
| + | conditions, order_by = conditions_without_order_by(conditions) |
| # priority: | |
| # 1/ order_by passed in the conditions parameter | |
| # 2/ the default order (_position) defined in the content type | |
| - | order_by = conditions.delete(:order_by)|| conditions.delete('order_by') || content_type.order_by |
| + | order_by ||= content_type.order_by |
| - | query { where(conditions).order_by(order_by) }.all |
| + | query { |
| + | (block_given? ? instance_eval(&block) : where). |
| + | where(conditions). |
| + | order_by(order_by) |
| + | }.all |
| + | end |
| + | |
| + | def count(conditions = {}) |
| + | conditions, _ = conditions_without_order_by(conditions) |
| + | super() { where(conditions) } |
| end | |
| def find(id) | |
| - | conditions = prepare_conditions(_id: id) |
| + | conditions, _ = conditions_without_order_by(_id: id) |
| first { where(conditions) } | |
| end | |
| def exists?(conditions = {}) | |
| - | conditions = prepare_conditions(conditions) |
| + | conditions, _ = conditions_without_order_by(conditions) |
| query { where(conditions) }.all.size > 0 | |
| end | |
| def by_slug(slug) | |
| - | conditions = prepare_conditions(_slug: slug) |
| + | conditions, _ = conditions_without_order_by(_slug: slug) |
| first { where(conditions) } | |
| end | |
| @@ | @@ -97,6 +106,10 @@ module Locomotive |
| end | |
| end | |
| + | def to_liquid |
| + | Locomotive::Steam::Liquid::Drops::ContentEntryCollection.new(content_type, self) |
| + | end |
| + | |
| private | |
| def mapper | |
| @@ | @@ -110,6 +123,16 @@ module Locomotive |
| end | |
| end | |
| + | def conditions_without_order_by(conditions = {}) |
| + | _conditions = prepare_conditions(conditions) |
| + | order_by = _conditions.delete(:order_by) || _conditions.delete('order_by') |
| + | [_conditions, order_by] |
| + | end |
| + | |
| + | def prepare_conditions(*conditions) |
| + | super({ _visible: true }, conditions) |
| + | end |
| + | |
| def add_localized_fields_to_mapper(mapper) | |
| unless self.content_type.localized_names.blank? | |
| mapper.localized_attributes(*self.content_type.localized_names) | |
locomotivecms_steam.gemspec
+0
-1
| @@ | @@ -40,7 +40,6 @@ 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.3' |
| spec.add_dependency 'kramdown', '~> 1.6.0' | |
| spec.add_dependency 'RedCloth', '~> 4.2.9' | |
| spec.add_dependency 'haml', '~> 4.0.6' | |
spec/integration/liquid/tags/paginate_spec.rb
+33
-74
| @@ | @@ -13,9 +13,10 @@ describe Locomotive::Steam::Liquid::Tags::Paginate do |
| EOF | |
| } | |
| + | let(:page) { nil } |
| let(:site) { Locomotive::Steam::Site.new(_id: site_id, locales: %w(en fr nb)) } | |
| let(:services) { Locomotive::Steam::Services.build_instance } | |
| - | let(:assigns) { { 'contents' => Locomotive::Steam::Liquid::Drops::ContentTypes.new } } |
| + | let(:assigns) { { 'contents' => Locomotive::Steam::Liquid::Drops::ContentTypes.new, 'fullpath' => '/', 'current_page' => page } } |
| let(:context) { ::Liquid::Context.new(assigns, {}, { services: services }) } | |
| before { | |
| @@ | @@ -26,95 +27,53 @@ EOF |
| subject { render_template(source, context) } | |
| - | context 'Filesystem' do |
| - | |
| - | let(:site_id) { 1 } |
| - | let(:adapter) { Locomotive::Steam::FilesystemAdapter.new(default_fixture_site_path) } |
| - | |
| - | it { is_expected.to eq '!RoR!MongoDB!Liquid!ReactJS!DCI' } |
| - | |
| - | end |
| - | |
| - | |
| - | |
| - | |
| - | # describe 'simple array' do |
| - | |
| - | # subject { output } |
| - | |
| - | # it { is_expected.to include '!RoR!MongoDB!Liquid!ReactJS!DCI' } |
| - | # it { is_expected.not_to include '!Bootstrap' } |
| + | shared_examples_for 'pagination' do |
| - | # describe 'second page of results: display the last item' do |
| + | it { is_expected.to match '!Song #1!Song #2!Song #3!Song #4!Song #5' } |
| - | # let(:page) { 2 } |
| - | # it { is_expected.to include '!Bootstrap' } |
| - | # it { is_expected.not_to include '!RoR!MongoDB!Liquid!ReactJS!DCI' } |
| + | describe 'second page' do |
| + | let(:page) { 2 } |
| + | it { is_expected.to match '!Song #6!Song #7!Song #8' } |
| + | end |
| - | # end |
| + | describe 'pagination of a has_many association' do |
| - | # end |
| - | |
| - | # describe 'array from a db collection' do |
| - | |
| - | # let(:projects) { KindaDBCollection.new(['RoR', 'MongoDB', 'Liquid', 'ReactJS', 'DCI', 'Bootstrap']) } |
| - | |
| - | # subject { output } |
| - | |
| - | # it { is_expected.to include '!RoR!MongoDB!Liquid!ReactJS!DCI' } |
| - | # it { is_expected.not_to include '!Bootstrap' } |
| - | |
| - | # end |
| + | let(:source) { <<-EOF |
| + | {% with_scope _slug: 'the-who' %} |
| + | {% assign band = contents.bands.first %} |
| + | {% endwith_scope %} |
| + | {% paginate band.songs by 1 %} |
| + | -{% for song in paginate.collection %}!{{ song.title }}{% endfor %}- |
| + | {% endpaginate %}' |
| + | EOF |
| + | } |
| - | # describe 'a very big collection' do |
| + | it { is_expected.to match '-!Song #5-' } |
| - | # let(:projects) { (1..100).to_a } |
| - | # let(:page) { 20 } |
| - | # let(:source) { '{% paginate projects by 2, window_size: 10 %}{% assign _pagination = paginate %}{% endpaginate %}' } |
| + | end |
| - | # before { output } |
| - | # subject { context['_pagination']['parts'] } |
| + | end |
| - | # it { expect(subject.first['title']).to eq 1 } |
| - | # it { expect(subject[1]['title']).to eq '…' } |
| - | # it { expect(subject[2]['title']).to eq 11 } |
| - | # it { expect(subject[21]['title']).to eq '…' } |
| - | # it { expect(subject.last['title']).to eq 50 } |
| + | context 'Filesystem' do |
| - | # end |
| + | it_should_behave_like 'pagination' do |
| - | # describe '' |
| + | let(:site_id) { 1 } |
| + | let(:adapter) { Locomotive::Steam::FilesystemAdapter.new(default_fixture_site_path) } |
| - | # end |
| + | end |
| - | # class KindaDBCollection < Struct.new(:collection) |
| + | end |
| - | # def paginate(options = {}) |
| - | # total_pages = (collection.size.to_f / options[:per_page].to_f).to_f.ceil + 1 |
| - | # offset = (options[:page] - 1) * options[:per_page] |
| + | context 'MongoDB' do |
| - | # { |
| - | # collection: collection[offset..(offset + options[:per_page]) - 1], |
| - | # current_page: options[:page], |
| - | # previous_page: options[:page] == 1 ? 1 : options[:page] - 1, |
| - | # next_page: options[:page] == total_pages ? total_pages : options[:page] + 1, |
| - | # total_entries: collection.size, |
| - | # total_pages: total_pages, |
| - | # per_page: options[:per_page] |
| - | # } |
| - | # end |
| + | it_should_behave_like 'pagination' do |
| - | # def each(&block) |
| - | # collection.each(&block) |
| - | # end |
| + | let(:site_id) { BSON::ObjectId.from_string('54eb49c12475804b2b000002') } |
| + | let(:adapter) { Locomotive::Steam::MongoDBAdapter.new(database: 'steam_test', hosts: ['127.0.0.1:27017']) } |
| - | # def method_missing(method, *args) |
| - | # collection.send(method, *args) |
| - | # end |
| + | end |
| - | # def to_liquid |
| - | # self |
| - | # end |
| - | # end |
| + | end |
| end | |
spec/integration/repositories/content_entry_repository_spec.rb
+5
-0
| @@ | @@ -18,6 +18,11 @@ describe Locomotive::Steam::ContentEntryRepository do |
| it { expect(subject.size).to eq 3 } | |
| end | |
| + | describe '#count' do |
| + | subject { repository.count } |
| + | it { is_expected.to eq 3 } |
| + | end |
| + | |
| describe '#by_slug' do | |
| subject { repository.by_slug('alice-in-chains') } | |
| it { expect(subject.name).to eq 'Alice in Chains' } | |
spec/unit/adapters/filesystem/yaml_loaders/content_entry_spec.rb
+1
-1
| @@ | @@ -28,7 +28,7 @@ describe Locomotive::Steam::Adapters::Filesystem::YAMLLoaders::ContentEntry do |
| it 'adds a new attribute for the foreign key' do | |
| expect(subject.first[:band_id]).to eq 'pearl-jam' | |
| expect(subject.first[:band]).to eq nil | |
| - | expect(subject.first[:_position_in_band]).to eq 0 |
| + | expect(subject.first[:position_in_band]).to eq 0 |
| end | |
| end | |
spec/unit/entities/content_type_field_spec.rb
+3
-3
| @@ | @@ -20,12 +20,12 @@ describe Locomotive::Steam::ContentTypeField do |
| context 'has_many field' do | |
| let(:attributes) { { name: 'articles', type: 'has_many', inverse_of: 'author' } } | |
| - | it { is_expected.to eq 'position_in_author' } |
| + | it { is_expected.to eq(position_in_author: 'asc') } |
| context 'order_by is specified' do | |
| let(:attributes) { { name: 'articles', type: 'has_many', inverse_of: 'author', order_by: 'name asc' } } | |
| - | it { is_expected.to eq 'name asc' } |
| + | it { is_expected.to eq(name: 'asc') } |
| end | |
| @@ | @@ -60,7 +60,7 @@ describe Locomotive::Steam::ContentTypeField do |
| subject { content_type.association_options } | |
| - | it { is_expected.to eq({ target_id: 'articles', inverse_of: 'author', order_by: 'position_in_author' }) } |
| + | it { is_expected.to eq(target_id: 'articles', inverse_of: 'author', order_by: { position_in_author: 'asc' }) } |
| end | |
spec/unit/liquid/drops/content_entry_collection_spec.rb
+81
-0
| @@ | @@ -0,0 +1,81 @@ |
| + | require 'spec_helper' |
| + | |
| + | describe Locomotive::Steam::Liquid::Drops::ContentEntryCollection do |
| + | |
| + | let(:assigns) { {} } |
| + | let(:content_type) { instance_double('ContentType', slug: 'articles') } |
| + | let(:services) { Locomotive::Steam::Services.build_instance } |
| + | let(:context) { ::Liquid::Context.new(assigns, {}, { services: services }) } |
| + | let(:drop) { described_class.new(content_type).tap { |d| d.context = context } } |
| + | |
| + | describe '#public_submission_url' do |
| + | it { expect(drop.public_submission_url).to eq '/entry_submissions/articles' } |
| + | end |
| + | |
| + | describe '#api' do |
| + | it { expect(drop.api).to eq({ 'create' => '/entry_submissions/articles' }) } |
| + | end |
| + | |
| + | describe 'acts as a collection' do |
| + | |
| + | before do |
| + | allow(services.repositories.content_entry).to receive(:all).with(nil).and_return(['a', 'b']) |
| + | end |
| + | |
| + | describe '#first' do |
| + | it { expect(drop.first).to eq('a') } |
| + | end |
| + | |
| + | describe '#last' do |
| + | it { expect(drop.last).to eq('b') } |
| + | end |
| + | |
| + | context 'with a scope' do |
| + | |
| + | let(:assigns) { { 'with_scope' => { 'visible' => true } } } |
| + | |
| + | describe '#first' do |
| + | before do |
| + | expect(services.repositories.content_entry).to receive(:all).with({ 'visible' => true }).and_return(['a', 'b']) |
| + | end |
| + | it { expect(drop.first).to eq('a') } |
| + | end |
| + | |
| + | describe '#count' do |
| + | before do |
| + | expect(services.repositories.content_entry).to receive(:count).with({ 'visible' => true }).and_return(2) |
| + | end |
| + | it { expect(drop.count).to eq 2 } |
| + | end |
| + | |
| + | end |
| + | |
| + | end |
| + | |
| + | describe 'get options of a select field' do |
| + | |
| + | before do |
| + | expect(services.repositories.content_type).to receive(:select_options).with(content_type, 'category').and_return(['a', 'b']) |
| + | end |
| + | |
| + | it { expect(drop.before_method(:category_options)).to eq ['a', 'b'] } |
| + | |
| + | end |
| + | |
| + | describe 'group entries by a select/belongs_to field' do |
| + | |
| + | before do |
| + | expect(services.repositories.content_entry).to receive(:group_by_select_option).with(content_type, 'category').and_return([['a', [1, 2]]]) |
| + | end |
| + | |
| + | it { expect(drop.before_method(:group_by_category)).to eq [['a', [1, 2]]] } |
| + | |
| + | end |
| + | |
| + | describe 'unknown method' do |
| + | |
| + | it { expect(drop.before_method(:foo)).to eq nil } |
| + | |
| + | end |
| + | |
| + | end |
spec/unit/liquid/drops/content_type_proxy_collection_spec.rb
+0
-83
| @@ | @@ -1,83 +0,0 @@ |
| - | require 'spec_helper' |
| - | |
| - | describe Locomotive::Steam::Liquid::Drops::ContentTypeProxyCollection do |
| - | |
| - | let(:assigns) { {} } |
| - | let(:content_type) { instance_double('ContentType', slug: 'articles') } |
| - | let(:services) { Locomotive::Steam::Services.build_instance } |
| - | let(:context) { ::Liquid::Context.new(assigns, {}, { services: services }) } |
| - | let(:drop) { described_class.new(content_type).tap { |d| d.context = context } } |
| - | |
| - | describe '#public_submission_url' do |
| - | it { expect(drop.public_submission_url).to eq '/entry_submissions/articles' } |
| - | end |
| - | |
| - | describe '#api' do |
| - | it { expect(drop.api).to eq({ 'create' => '/entry_submissions/articles' }) } |
| - | end |
| - | |
| - | describe 'acts as a collection' do |
| - | |
| - | before do |
| - | allow(services.repositories.content_entry).to receive(:all).with(nil).and_return(['a', 'b']) |
| - | end |
| - | |
| - | describe '#first' do |
| - | it { expect(drop.first).to eq('a') } |
| - | end |
| - | |
| - | describe '#last' do |
| - | it { expect(drop.last).to eq('b') } |
| - | end |
| - | |
| - | describe '#count' do |
| - | it { expect(drop.count).to eq 2 } |
| - | end |
| - | |
| - | context 'with a scope' do |
| - | |
| - | let(:assigns) { { 'with_scope' => { 'visible' => true } } } |
| - | |
| - | before do |
| - | expect(services.repositories.content_entry).to receive(:all).with({ 'visible' => true }).and_return(['a', 'b']) |
| - | end |
| - | |
| - | describe '#first' do |
| - | it { expect(drop.first).to eq('a') } |
| - | end |
| - | |
| - | describe '#count' do |
| - | it { expect(drop.count).to eq 2 } |
| - | end |
| - | |
| - | end |
| - | |
| - | end |
| - | |
| - | describe 'get options of a select field' do |
| - | |
| - | before do |
| - | expect(services.repositories.content_type).to receive(:select_options).with(content_type, 'category').and_return(['a', 'b']) |
| - | end |
| - | |
| - | it { expect(drop.before_method(:category_options)).to eq ['a', 'b'] } |
| - | |
| - | end |
| - | |
| - | describe 'group entries by a select/belongs_to field' do |
| - | |
| - | before do |
| - | expect(services.repositories.content_entry).to receive(:group_by_select_option).with(content_type, 'category').and_return([['a', [1, 2]]]) |
| - | end |
| - | |
| - | it { expect(drop.before_method(:group_by_category)).to eq [['a', [1, 2]]] } |
| - | |
| - | end |
| - | |
| - | describe 'unknown method' do |
| - | |
| - | it { expect(drop.before_method(:foo)).to eq nil } |
| - | |
| - | end |
| - | |
| - | end |
spec/unit/liquid/tags/paginate_spec.rb
+1
-1
| @@ | @@ -45,7 +45,7 @@ EOF |
| subject { output } | |
| - | it { expect { subject }.to raise_error(::Liquid::ArgumentError, "Liquid error: Cannot paginate array 'projects'. Not found.") } |
| + | it { expect { subject }.to raise_error(::Liquid::ArgumentError, "Liquid error: Cannot paginate 'projects'. Not found.") } |
| end | |
spec/unit/models/pager_spec.rb
+82
-0
| @@ | @@ -0,0 +1,82 @@ |
| + | require 'spec_helper' |
| + | |
| + | describe Locomotive::Steam::Models::Pager do |
| + | |
| + | let(:page) { 1 } |
| + | let(:per_page) { 2 } |
| + | let(:source) { ['MongoDB', 'Rails', 'Liquid', 'Rack', 'Devise'] } |
| + | let(:pager) { described_class.new(source, page, per_page) } |
| + | |
| + | describe '#collection' do |
| + | |
| + | subject { pager.collection } |
| + | |
| + | it { is_expected.to eq ['MongoDB', 'Rails'] } |
| + | |
| + | describe 'last page' do |
| + | let(:page) { 3 } |
| + | it { is_expected.to eq ['Devise'] } |
| + | end |
| + | |
| + | describe 'per_page is 1' do |
| + | let(:per_page) { 1 } |
| + | it { is_expected.to eq ['MongoDB'] } |
| + | end |
| + | |
| + | describe 'per_page is > to the number of total entries' do |
| + | let(:per_page) { 10 } |
| + | it { is_expected.to eq ['MongoDB', 'Rails', 'Liquid', 'Rack', 'Devise'] } |
| + | end |
| + | |
| + | describe 'page is > to the total number of pages' do |
| + | let(:page) { 4 } |
| + | it { is_expected.to eq [] } |
| + | end |
| + | |
| + | end |
| + | |
| + | describe '#previous_page' do |
| + | |
| + | subject { pager.previous_page } |
| + | |
| + | it { is_expected.to eq nil } |
| + | |
| + | describe 'another page' do |
| + | let(:page) { 2 } |
| + | it { is_expected.to eq 1 } |
| + | end |
| + | |
| + | end |
| + | |
| + | describe '#next_page' do |
| + | |
| + | subject { pager.next_page } |
| + | |
| + | it { is_expected.to eq 2 } |
| + | |
| + | describe 'another page' do |
| + | let(:page) { 3 } |
| + | it { is_expected.to eq nil } |
| + | end |
| + | |
| + | end |
| + | |
| + | describe '#to_liquid' do |
| + | |
| + | subject { pager.to_liquid } |
| + | |
| + | it do |
| + | is_expected.to eq({ |
| + | collection: ['MongoDB', 'Rails'], |
| + | current_page: 1, |
| + | per_page: 2, |
| + | previous_page: nil, |
| + | next_page: 2, |
| + | total_entries: 5, |
| + | total_pages: 3 |
| + | }) |
| + | end |
| + | |
| + | end |
| + | |
| + | end |