This commit is contained in:
Didier Lafforgue 2012-04-05 17:12:26 +02:00
parent 6bd1154886
commit 64168cad37
10 changed files with 739 additions and 270 deletions

View File

@ -8,6 +8,7 @@ gemspec # Include gemspec dependencies
# The rest of the dependencies are for use when in the locomotive development environment # The rest of the dependencies are for use when in the locomotive development environment
group :development do group :development do
# gem 'locomotive-mongoid-tree', :path => '../gems/custom_fields' # for Developers
# gem 'custom_fields', :path => '../gems/custom_fields' # for Developers # gem 'custom_fields', :path => '../gems/custom_fields' # for Developers
gem 'custom_fields', :git => 'git://github.com/locomotivecms/custom_fields.git', :branch => '2.0.0.rc' # Branch on Github gem 'custom_fields', :git => 'git://github.com/locomotivecms/custom_fields.git', :branch => '2.0.0.rc' # Branch on Github

View File

@ -0,0 +1,135 @@
module Locomotive
module Extensions
module Page
module Fullpath
extend ActiveSupport::Concern
included do
## fields ##
field :fullpath, :localize => true
field :wildcard, :type => Boolean, :default => false
field :wildcards, :type => Array
## callbacks ##
before_validation :get_wildcards_from_parent
before_validation :add_slug_to_wildcards
before_save :build_fullpath
# before_rearrange :foo #propagate_fullpath_changes
# after_save :propagate_fullpath_changes
## scopes ##
# scope :fullpath, lambda { |fullpath| { :where => { :fullpath => fullpath } } } # used ?
## virtual attributes ##
attr_accessor :wildcards_map
end
# def foo
# Rails.logger.debug "----> rearranging #{self.slug}.......\n\n"
# puts "[rearranging]"
# end
# This method returns true if the fullpath is enhanced
# by wildcards. It is different from the wildcard? method
# because it includes the ancestors when determining if
# the current page has wildcards or not.
#
def has_wildcards?
!self.fullpath.try(:index, '*').nil?
end
# It returns a pretty output of the fullpath. The "*" characters
# are replaced by the following pattern ":<slug>" like you can find
# in the Ruby on Rails routes.
#
def pretty_fullpath
return self.fullpath unless self.has_wildcards?
index = 0
self.fullpath.split('/').map do |segment|
if segment == '*'
":#{self.wildcards[index]}".tap { index += 1 }
else
segment
end
end.join('/')
end
protected
def get_wildcards_from_parent
return true if self.parent.nil?
if self.parent.has_wildcards?
puts "[get_wildcards_from_parent] #{self.slug} - #{self.parent.wildcards.inspect}"
self.wildcards = self.parent.wildcards
elsif !self.wildcard?
self.wildcards = nil
end
true
end
def add_slug_to_wildcards
(self.wildcards ||= []) << self.slug if self.wildcard?
end
def build_fullpath
if self.index? || self.not_found?
self.fullpath = self.slug
else
slugs = self.ancestors_and_self.map { |page| page.wildcard? ? '*' : page.slug }
slugs.shift unless slugs.size == 1
self.fullpath = File.join slugs.compact
end
end
def propagate_fullpath_changes
return true unless self.wildcard_changed? || self.slug_changed?
parent_identities = { self._id => self }
Rails.logger.debug "[propagate_fullpath_changes] BEGIN page #{self.slug} #{self.fullpath} / #{self.wildcards.inspect} / #{self._parent.try(:has_wildcards?).inspect}"
puts "[propagate_fullpath_changes] BEGIN page #{self.slug} #{self.fullpath} / #{self.wildcards.inspect} / #{self._parent.try(:has_wildcards?).inspect}"
self.descendants.order_by([[:depth, :asc]]).each do |page|
_parent = parent_identities[page.parent_id]
_fullpath = {}
_wildcards = nil
puts "[propagate_fullpath_changes] #{page.fullpath} / #{page.wildcards.inspect} / #{page._parent.try(:has_wildcards?).inspect}"
if _parent.has_wildcards?
_wildcards = _parent.wildcards + (page.wildcard? ? [page.slug] : [])
end
self.site.locales.each do |locale|
base_fullpath = _parent.fullpath_translations[locale]
slug = page.wildcard? ? '*' : page.slug_translations[locale]
next if base_fullpath.blank?
_fullpath[locale] = File.join(base_fullpath, slug)
end
selector = { 'id' => page._id }
operations = {
'$set' => {
'wildcards' => _wildcards,
'fullpath' => _fullpath
}
}
self.collection.update selector, operations
parent_identities[page._id] = page
end
end
end
end
end
end

View File

@ -23,6 +23,7 @@ module Locomotive
## scopes ## ## scopes ##
scope :pages, lambda { |domain| { :any_in => { :domains => [*domain] } } } scope :pages, lambda { |domain| { :any_in => { :domains => [*domain] } } }
scope :dependent_from, lambda { |id| { :where => { :template_dependencies.in => [id] } } }
end end
def template def template

View File

@ -56,9 +56,7 @@ module Locomotive
# Calculate all the combinations possible based on the # Calculate all the combinations possible based on the
# fact that one of the segment of the path could be # fact that one of the segment of the path could be
# a content type from a templatized page. # a wildcard.
# We postulate that there is only one templatized page in a path
# (ie: no nested templatized pages)
# #
# @param [ String ] path The path to the page # @param [ String ] path The path to the page
# #
@ -69,13 +67,13 @@ module Locomotive
end end
#:nodoc: #:nodoc:
def _path_combinations(segments, can_include_template = true) def _path_combinations(segments)
return nil if segments.empty? return nil if segments.empty?
segment = segments.shift segment = segments.shift
(can_include_template ? [segment, 'content_type_template'] : [segment]).map do |_segment| [segment, '*'].map do |_segment|
if (_combinations = _path_combinations(segments.clone, can_include_template && _segment != 'content_type_template')) if (_combinations = _path_combinations(segments.clone))
[*_combinations].map do |_combination| [*_combinations].map do |_combination|
File.join(_segment, _combination) File.join(_segment, _combination)
end end

View File

@ -1,136 +1,136 @@
module Locomotive # module Locomotive
module Extensions # module Extensions
module Page # module Page
module Templatized # module Templatized
#
extend ActiveSupport::Concern # extend ActiveSupport::Concern
#
included do # included do
#
## fields ## # ## fields ##
field :templatized, :type => Boolean, :default => false # field :templatized, :type => Boolean, :default => false
field :templatized_from_parent, :type => Boolean, :default => false # field :templatized_from_parent, :type => Boolean, :default => false
field :target_klass_name # field :target_klass_name
#
## validations ## # ## validations ##
validates_presence_of :target_klass_name, :if => :templatized? # validates_presence_of :target_klass_name, :if => :templatized?
validate :ensure_target_klass_name_security # validate :ensure_target_klass_name_security
#
## callbacks ## # ## callbacks ##
before_validation :get_templatized_from_parent # before_validation :get_templatized_from_parent
before_validation :set_slug_if_templatized # before_validation :set_slug_if_templatized
before_validation :ensure_target_klass_name_security # before_validation :ensure_target_klass_name_security
after_save :propagate_templatized # after_save :propagate_templatized
#
## scopes ## # ## scopes ##
scope :templatized, :where => { :templatized => true } # scope :templatized, :where => { :templatized => true }
#
## virtual attributes ## # ## virtual attributes ##
attr_accessor :content_entry # attr_accessor :content_entry
end # end
#
# Returns the class specified by the target_klass_name property # # Returns the class specified by the target_klass_name property
# # #
# @example # # @example
# # #
# page.target_klass_name = 'Locomotive::Entry12345' # # page.target_klass_name = 'Locomotive::Entry12345'
# page.target_klass = Locomotive::Entry12345 # # page.target_klass = Locomotive::Entry12345
# # #
# @return [ Class ] The target class # # @return [ Class ] The target class
# # #
def target_klass # def target_klass
target_klass_name.constantize # target_klass_name.constantize
end # end
#
# Gives the name which can be used in a liquid template in order # # Gives the name which can be used in a liquid template in order
# to reference an entry. It uses the slug property if the target klass # # to reference an entry. It uses the slug property if the target klass
# is a Locomotive content type or the class name itself for the other classes. # # is a Locomotive content type or the class name itself for the other classes.
# # #
# @example # # @example
# # #
# page.target_klass_name = 'Locomotive::Entry12345' # related to the content type Articles # # page.target_klass_name = 'Locomotive::Entry12345' # related to the content type Articles
# page.target_entry_name = 'article' # # page.target_entry_name = 'article'
# # #
# page.target_klass_name = 'OurProduct' # # page.target_klass_name = 'OurProduct'
# page.target_entry_name = 'our_product' # # page.target_entry_name = 'our_product'
# # #
# @return [ String ] The name in lowercase and underscored # # @return [ String ] The name in lowercase and underscored
# # #
def target_entry_name # def target_entry_name
if self.target_klass_name =~ /^Locomotive::Entry([a-z0-9]+)$/ # if self.target_klass_name =~ /^Locomotive::Entry([a-z0-9]+)$/
@content_type ||= self.site.content_types.find($1) # @content_type ||= self.site.content_types.find($1)
@content_type.slug.singularize # @content_type.slug.singularize
else # else
self.target_klass_name.underscore # self.target_klass_name.underscore
end # end
end # end
#
# Finds the entry both specified by the target klass and identified by the permalink # # Finds the entry both specified by the target klass and identified by the permalink
# # #
# @param [ String ] permalink The permalink of the entry # # @param [ String ] permalink The permalink of the entry
# # #
# @return [ Object ] The document # # @return [ Object ] The document
# # #
def fetch_target_entry(permalink) # def fetch_target_entry(permalink)
target_klass.find_by_permalink(permalink) # target_klass.find_by_permalink(permalink)
end # end
#
protected # protected
#
def get_templatized_from_parent # def get_templatized_from_parent
return if self.parent.nil? # return if self.parent.nil?
#
if self.parent.templatized? # if self.parent.templatized?
self.templatized = self.templatized_from_parent = true # self.templatized = self.templatized_from_parent = true
self.target_klass_name = self.parent.target_klass_name # self.target_klass_name = self.parent.target_klass_name
elsif !self.templatized? # elsif !self.templatized?
self.templatized = self.templatized_from_parent = false # self.templatized = self.templatized_from_parent = false
self.target_klass_name = nil # self.target_klass_name = nil
end # end
end # end
#
def set_slug_if_templatized # def set_slug_if_templatized
self.slug = 'content_type_template' if self.templatized? && !self.templatized_from_parent? # self.slug = 'content_type_template' if self.templatized? && !self.templatized_from_parent?
end # end
#
# Makes sure the target_klass is owned by the site OR # # Makes sure the target_klass is owned by the site OR
# if it belongs to the models allowed by the application # # if it belongs to the models allowed by the application
# thanks to the models_for_templatization option. # # thanks to the models_for_templatization option.
# # #
def ensure_target_klass_name_security # def ensure_target_klass_name_security
return if !self.templatized? || self.target_klass_name.blank? # return if !self.templatized? || self.target_klass_name.blank?
#
if self.target_klass_name =~ /^Locomotive::Entry([a-z0-9]+)$/ # if self.target_klass_name =~ /^Locomotive::Entry([a-z0-9]+)$/
content_type = Locomotive::ContentType.find($1) # content_type = Locomotive::ContentType.find($1)
#
if content_type.site_id != self.site_id # if content_type.site_id != self.site_id
self.errors.add :target_klass_name, :security # self.errors.add :target_klass_name, :security
end # end
elsif !Locomotive.config.models_for_templatization.include?(self.target_klass_name) # elsif !Locomotive.config.models_for_templatization.include?(self.target_klass_name)
self.errors.add :target_klass_name, :security # self.errors.add :target_klass_name, :security
end # end
end # end
#
# Sets the templatized, templatized_from_parent properties of # # Sets the templatized, templatized_from_parent properties of
# the children of the current page ONLY IF the templatized # # the children of the current page ONLY IF the templatized
# attribute got changed. # # attribute got changed.
# # #
def propagate_templatized # def propagate_templatized
return unless self.templatized_changed? # return unless self.templatized_changed?
#
selector = { 'parent_ids' => { '$in' => [self._id] } } # selector = { 'parent_ids' => { '$in' => [self._id] } }
operations = { # operations = {
'$set' => { # '$set' => {
'templatized' => self.templatized, # 'templatized' => self.templatized,
'templatized_from_parent' => self.templatized, # 'templatized_from_parent' => self.templatized,
'target_klass_name' => self.target_klass_name # 'target_klass_name' => self.target_klass_name
} # }
} # }
#
self.collection.update selector, operations, :multi => true # self.collection.update selector, operations, :multi => true
end # end
#
end # end
end # end
end # end
end # end

View File

@ -0,0 +1,213 @@
# module Locomotive
# module Extensions
# module Page
# module Templatized
#
# extend ActiveSupport::Concern
#
# included do
#
# ## fields ##
# field :wildcards, :type => Array
# field :with_wildcards, :type => Boolean, :default => false
# field :fullpath_with_wildcards, :default => false, :localize => true
#
# ## callbacks ##
# before_validation :get_wildcards_from_parent
# before_validation :add_slug_to_wildcards
# before_save :build_fullpath_with_wildcards
# after_save :propagate_wildcards
#
# ## scopes ##
#
# ## virtual attributes ##
# attr_accessor :wildcards_map
#
# end
#
# protected
#
# def get_wildcards_from_parent
# return if self.parent.nil?
#
# if self.parent.with_wildcards?
# self.wildcards = self.parent.wildcards
# self.with_wildcards = true
# elsif !self.with_wildcards?
# self.wildcards = []
# self.with_wildcards = false
# end
# end
#
# def add_slug_to_wildcards
# (self.wildcards ||= []) << self.slug if self.will_wildcards?
# end
#
# def build_fullpath_with_wildcards
# if self.index? || self.not_found?
# self.fullpath_with_wildcards = self.slug
# else
# slugs = self.ancestors_and_self.map { |page| page.with_wildcards? ? '*' : page.slug }
# slugs.shift unless slugs.size == 1
# self.fullpath_with_wildcards = File.join slugs.compact
# end
# end
#
# def propagate_wildcards
# return unless self.with_wildcards_changed? || (self.with_wildcards? && self.slug_changed?)
#
# parent_identities = { self._id => self }
#
# self.descendants.order_by([[:depth, :asc]]).each do |page|
# _parent = parent_identities[page._id]
# _wildcards = _parent.wildcards + (page.wildcards? ? [page.slug] : [])
# _fullpath_with_wildcards = File.join(_parent.fullpath_with_wildcards, page.wildcards? ? '*' : page.slug)
#
# # TODO: fullpath_with_wildcards is localized !!!!
#
# selector = { 'id' => page._id }
# operations = {
# '$set' => {
# 'wildcards' => _wildcards,
# 'with_wildcards' => true,
# 'fullpath_with_wildcards' => _fullpath_with_wildcards
# }
# }
# self.collection.update selector, operations
#
# parent_identities[page._id] = page
# end
# end
#
# end
# end
# end
# end
#
#
#
# # field :templatized_from_parent, :type => Boolean, :default => false
# # field :target_klass_name
# #
# # ## validations ##
# # validates_presence_of :target_klass_name, :if => :templatized?
# # validate :ensure_target_klass_name_security
# #
# # ## callbacks ##
# # before_validation :get_templatized_from_parent
# # before_validation :set_slug_if_templatized
# # before_validation :ensure_target_klass_name_security
# # after_save :propagate_templatized
# #
# # ## scopes ##
# # scope :templatized, :where => { :templatized => true }
# #
# # ## virtual attributes ##
# # attr_accessor :content_entry
# # end
# #
# # # Returns the class specified by the target_klass_name property
# # #
# # # @example
# # #
# # # page.target_klass_name = 'Locomotive::Entry12345'
# # # page.target_klass = Locomotive::Entry12345
# # #
# # # @return [ Class ] The target class
# # #
# # def target_klass
# # target_klass_name.constantize
# # end
# #
# # # Gives the name which can be used in a liquid template in order
# # # to reference an entry. It uses the slug property if the target klass
# # # is a Locomotive content type or the class name itself for the other classes.
# # #
# # # @example
# # #
# # # page.target_klass_name = 'Locomotive::Entry12345' # related to the content type Articles
# # # page.target_entry_name = 'article'
# # #
# # # page.target_klass_name = 'OurProduct'
# # # page.target_entry_name = 'our_product'
# # #
# # # @return [ String ] The name in lowercase and underscored
# # #
# # def target_entry_name
# # if self.target_klass_name =~ /^Locomotive::Entry([a-z0-9]+)$/
# # @content_type ||= self.site.content_types.find($1)
# # @content_type.slug.singularize
# # else
# # self.target_klass_name.underscore
# # end
# # end
# #
# # # Finds the entry both specified by the target klass and identified by the permalink
# # #
# # # @param [ String ] permalink The permalink of the entry
# # #
# # # @return [ Object ] The document
# # #
# # def fetch_target_entry(permalink)
# # target_klass.find_by_permalink(permalink)
# # end
# #
# # protected
# #
# # def get_templatized_from_parent
# # return if self.parent.nil?
# #
# # if self.parent.templatized?
# # self.templatized = self.templatized_from_parent = true
# # self.target_klass_name = self.parent.target_klass_name
# # elsif !self.templatized?
# # self.templatized = self.templatized_from_parent = false
# # self.target_klass_name = nil
# # end
# # end
# #
# # def set_slug_if_templatized
# # self.slug = 'content_type_template' if self.templatized? && !self.templatized_from_parent?
# # end
# #
# # # Makes sure the target_klass is owned by the site OR
# # # if it belongs to the models allowed by the application
# # # thanks to the models_for_templatization option.
# # #
# # def ensure_target_klass_name_security
# # return if !self.templatized? || self.target_klass_name.blank?
# #
# # if self.target_klass_name =~ /^Locomotive::Entry([a-z0-9]+)$/
# # content_type = Locomotive::ContentType.find($1)
# #
# # if content_type.site_id != self.site_id
# # self.errors.add :target_klass_name, :security
# # end
# # elsif !Locomotive.config.models_for_templatization.include?(self.target_klass_name)
# # self.errors.add :target_klass_name, :security
# # end
# # end
# #
# # # Sets the templatized, templatized_from_parent properties of
# # # the children of the current page ONLY IF the templatized
# # # attribute got changed.
# # #
# # def propagate_templatized
# # return unless self.templatized_changed?
# #
# # selector = { 'parent_ids' => { '$in' => [self._id] } }
# # operations = {
# # '$set' => {
# # 'templatized' => self.templatized,
# # 'templatized_from_parent' => self.templatized,
# # 'target_klass_name' => self.target_klass_name
# # }
# # }
# #
# # self.collection.update selector, operations, :multi => true
# # end
# #
# # end
# # end
# # end
# # end

View File

@ -8,7 +8,7 @@ module Locomotive
include Extensions::Page::EditableElements include Extensions::Page::EditableElements
include Extensions::Page::Parse include Extensions::Page::Parse
include Extensions::Page::Render include Extensions::Page::Render
include Extensions::Page::Templatized include Extensions::Page::Fullpath
include Extensions::Page::Redirect include Extensions::Page::Redirect
include Extensions::Page::Listed include Extensions::Page::Listed
include Extensions::Shared::Seo include Extensions::Shared::Seo
@ -16,7 +16,6 @@ module Locomotive
## fields ## ## fields ##
field :title, :localize => true field :title, :localize => true
field :slug, :localize => true field :slug, :localize => true
field :fullpath, :localize => true
field :handle field :handle
field :raw_template, :localize => true field :raw_template, :localize => true
field :locales, :type => Array field :locales, :type => Array
@ -35,7 +34,6 @@ module Locomotive
## callbacks ## ## callbacks ##
after_initialize :set_default_raw_template after_initialize :set_default_raw_template
before_validation :normalize_slug before_validation :normalize_slug
before_save :build_fullpath
before_save :record_current_locale before_save :record_current_locale
before_destroy :do_not_remove_index_and_404_pages before_destroy :do_not_remove_index_and_404_pages
@ -50,10 +48,8 @@ module Locomotive
scope :root, :where => { :slug => 'index', :depth => 0 } scope :root, :where => { :slug => 'index', :depth => 0 }
scope :not_found, :where => { :slug => '404', :depth => 0 } scope :not_found, :where => { :slug => '404', :depth => 0 }
scope :published, :where => { :published => true } scope :published, :where => { :published => true }
scope :fullpath, lambda { |fullpath| { :where => { :fullpath => fullpath } } }
scope :handle, lambda { |handle| { :where => { :handle => handle } } } scope :handle, lambda { |handle| { :where => { :handle => handle } } }
scope :minimal_attributes, lambda { |attrs = []| { :only => (attrs || []) + %w(title slug fullpath position depth published templatized redirect listed response_type parent_id site_id created_at updated_at) } } scope :minimal_attributes, lambda { |attrs = []| { :only => (attrs || []) + %w(title slug fullpath position depth published with_wildcards redirect listed response_type parent_id site_id created_at updated_at) } }
scope :dependent_from, lambda { |id| { :where => { :template_dependencies.in => [id] } } }
## methods ## ## methods ##
@ -114,16 +110,6 @@ module Locomotive
self.raw_template ||= ::I18n.t('attributes.defaults.pages.other.body') self.raw_template ||= ::I18n.t('attributes.defaults.pages.other.body')
end end
def build_fullpath
if self.index? || self.not_found?
self.fullpath = self.slug
else
slugs = self.ancestors_and_self.map(&:slug)
slugs.shift unless slugs.size == 1
self.fullpath = File.join slugs.compact
end
end
def record_current_locale def record_current_locale
self.locales ||= [] self.locales ||= []
self.locales << ::Mongoid::Fields::I18n.locale self.locales << ::Mongoid::Fields::I18n.locale

View File

@ -5,15 +5,15 @@ rescue LoadError
puts 'You must `gem install bundler` and `bundle install` to run rake tasks' puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
end end
Locomotive::Page.each do |page| # Locomotive::Page.each do |page|
page.editable_elements.each_with_index do |el, index| # page.editable_elements.each_with_index do |el, index|
next if el._type != 'Locomotive::EditableFile' || el.attributes['source'].is_a?(Hash) # next if el._type != 'Locomotive::EditableFile' || el.attributes['source'].is_a?(Hash)
#
value = el.attributes['source'] # value = el.attributes['source']
#
page.collection.update({ '_id' => page._id }, { '$set' => { "editable_elements.#{index}.source" => { 'en' => value } } }) # page.collection.update({ '_id' => page._id }, { '$set' => { "editable_elements.#{index}.source" => { 'en' => value } } })
end # end
end # end
# ================ GLOBAL VARIABLES ============== # ================ GLOBAL VARIABLES ==============

View File

@ -0,0 +1,135 @@
# coding: utf-8
require 'spec_helper'
describe Locomotive::Page do
before(:each) do
Locomotive::Site.any_instance.stubs(:create_default_pages!).returns(true)
Locomotive::Page.any_instance.stubs(:set_default_raw_template).returns(true)
end
describe 'wildcards' do
before(:each) do
@page = FactoryGirl.build(:page, :parent => FactoryGirl.build(:page), :title => 'Project template', :slug => 'permalink', :wildcard => true)
end
it 'has a fullpath with wildcards' do
@page.wildcard?.should be_true
end
it 'returns a nice output of the fullpath' do
@page.fullpath = 'archives/*/projects/*'
@page.wildcards = %w(month permalink)
@page.pretty_fullpath.should == 'archives/:month/projects/:permalink'
end
describe 'building the fullpath' do
it 'returns "index" for the root page' do
@page = FactoryGirl.build(:page)
@page.send(:build_fullpath)
@page.fullpath.should == 'index'
end
it 'returns "404" for the "page not found" page' do
@page = FactoryGirl.build(:page, :slug => '404')
@page.send(:build_fullpath)
@page.fullpath.should == '404'
end
it 'includes a single "*" if the page enables wildcards' do
@page.send(:build_fullpath)
@page.fullpath.should == '*'
end
it 'includes a single "*" if the page enables wildcards and if there are a lot of ancestors' do
@page.stubs(:ancestors_and_self).returns([FactoryGirl.build(:page), FactoryGirl.build(:page, :slug => 'archives'), FactoryGirl.build(:page, :slug => 'projects'), @page])
@page.send(:build_fullpath)
@page.fullpath.should == 'archives/projects/*'
end
it 'includes many "*" when there are ancestors enabling wildcards' do
@page.stubs(:ancestors_and_self).returns([FactoryGirl.build(:page),
FactoryGirl.build(:page, :slug => 'archives'),
FactoryGirl.build(:page, :slug => 'month', :wildcard => true),
FactoryGirl.build(:page, :slug => 'projects'), @page])
@page.send(:build_fullpath)
@page.fullpath.should == 'archives/*/projects/*'
end
end
describe 'adding wildcards' do
it 'fills the array of wildcards' do
@page.valid?
@page.wildcards.should == %w(permalink)
end
it 'fills the array of wildcards from ancestors' do
@page.parent.stubs(:has_wildcards?).returns(true)
@page.parent.wildcards = %w(category month)
@page.valid?
@page.wildcards.should == %w(category month permalink)
end
it 'contains a array of valid wildcards' do
@page.slug = 'another permalink'
@page.valid?
@page.wildcards.should == %w(another-permalink)
end
end
describe 'propagating changes' do
before(:each) do
@home_page = FactoryGirl.create(:page)
@archives_page = FactoryGirl.create(:page, :site => @home_page.site, :parent => @home_page, :slug => 'archives')
@month_page = FactoryGirl.create(:page, :site => @home_page.site, :parent => @archives_page, :slug => 'month')
@projects_page = FactoryGirl.create(:page, :site => @home_page.site, :parent => @month_page, :slug => 'projects')
@project_page = FactoryGirl.create(:page, :site => @home_page.site, :parent => @projects_page, :slug => 'project', :wildcard => true)
@posts_page = FactoryGirl.create(:page, :site => @home_page.site, :parent => @month_page, :slug => 'posts')
end
it 'keeps the wildcards as they were if we modify a slug of an ancestor' do
@archives_page.update_attributes :slug => 'my_archives'
@project_page.reload
@project_page.fullpath.should == 'my_archives/month/projects/*'
end
it 'turns a page into a wildcards one' do
Rails.logger.debug "=========== START ============"
@month_page.update_attributes :wildcard => true
Rails.logger.debug "=========== END ============"
@project_page.reload
@project_page.fullpath.should == 'archives/*/projects/*'
@posts_page.reload
@posts_page.fullpath.should == 'archives/*/posts'
end
it 'turns off the wildcard property of page' do
puts "==== 1 ==="
Rails.logger.debug "==== 1 ==="
puts "@month_page = #{@month_page.fullpath.inspect} / #{@month_page.wildcards.inspect}"
@month_page.update_attributes :wildcard => true
puts "==== 2 === "
Rails.logger.debug "==== 2 ==="
@month_page.update_attributes :wildcard => false
puts "---- DONE ----"
Rails.logger.debug "==== DONE ==="
@project_page.reload
@project_page.fullpath.should == 'archives/month/projects/*'
@project_page.wildcards.should == %w(project)
@posts_page.reload
@posts_page.fullpath.should == 'archives/month/posts'
@posts_page.wildcards.should == nil
end
end
end
end

View File

@ -223,108 +223,108 @@ describe Locomotive::Page do
end end
describe 'templatized extension' do # describe 'templatized extension' do
#
before(:each) do # before(:each) do
@page = FactoryGirl.build(:page, :parent => FactoryGirl.build(:page, :templatized => false), :templatized => true, :target_klass_name => 'Foo') # @page = FactoryGirl.build(:page, :parent => FactoryGirl.build(:page, :templatized => false), :templatized => true, :target_klass_name => 'Foo')
end # end
#
it 'is considered as a templatized page' do # it 'is considered as a templatized page' do
@page.templatized?.should be_true # @page.templatized?.should be_true
end # end
#
it 'fills in the slug field' do # it 'fills in the slug field' do
@page.valid? # @page.valid?
@page.slug.should == 'content_type_template' # @page.slug.should == 'content_type_template'
end # end
#
it 'returns the target klass' do # it 'returns the target klass' do
@page.target_klass.should == Foo # @page.target_klass.should == Foo
end # end
#
it 'has a name for the target entry' do # it 'has a name for the target entry' do
@page.target_entry_name.should == 'foo' # @page.target_entry_name.should == 'foo'
end # end
#
it 'uses the find_by_permalink method when fetching the entry' do # it 'uses the find_by_permalink method when fetching the entry' do
Foo.expects(:find_by_permalink) # Foo.expects(:find_by_permalink)
@page.fetch_target_entry('foo') # @page.fetch_target_entry('foo')
end # end
#
context '#descendants' do # context '#descendants' do
#
before(:each) do # before(:each) do
@home = FactoryGirl.create(:page) # @home = FactoryGirl.create(:page)
@page.attributes = { :parent_id => @home._id, :site => @home.site }; @page.save! # @page.attributes = { :parent_id => @home._id, :site => @home.site }; @page.save!
@sub_page = FactoryGirl.build(:page, :title => 'Subpage', :slug => 'foo', :parent => @page, :site => @home.site, :templatized => false) # @sub_page = FactoryGirl.build(:page, :title => 'Subpage', :slug => 'foo', :parent => @page, :site => @home.site, :templatized => false)
end # end
#
it 'inherits the templatized property from its parent' do # it 'inherits the templatized property from its parent' do
@sub_page.valid? # @sub_page.valid?
@sub_page.templatized?.should be_true # @sub_page.templatized?.should be_true
@sub_page.templatized_from_parent?.should be_true # @sub_page.templatized_from_parent?.should be_true
@sub_page.target_klass_name.should == 'Foo' # @sub_page.target_klass_name.should == 'Foo'
end # end
#
it 'gets templatized if its parent is' do # it 'gets templatized if its parent is' do
@page.attributes = { :templatized => false, :target_klass_name => nil }; @page.save! # @page.attributes = { :templatized => false, :target_klass_name => nil }; @page.save!
@sub_page.save.should be_true # @sub_page.save.should be_true
@sub_page.templatized?.should be_false # @sub_page.templatized?.should be_false
#
@page.attributes = { :templatized => true, :target_klass_name => 'Foo' }; @page.save! # @page.attributes = { :templatized => true, :target_klass_name => 'Foo' }; @page.save!
@sub_page.reload # @sub_page.reload
@sub_page.templatized?.should be_true # @sub_page.templatized?.should be_true
@sub_page.templatized_from_parent?.should be_true # @sub_page.templatized_from_parent?.should be_true
@sub_page.target_klass_name.should == 'Foo' # @sub_page.target_klass_name.should == 'Foo'
end # end
#
it 'is not templatized if its parent is no more a templatized page' do # it 'is not templatized if its parent is no more a templatized page' do
@sub_page.save.should be_true # @sub_page.save.should be_true
@page.templatized = false; @page.save! # @page.templatized = false; @page.save!
@sub_page.reload # @sub_page.reload
@sub_page.templatized.should be_false # @sub_page.templatized.should be_false
@sub_page.templatized_from_parent.should be_false # @sub_page.templatized_from_parent.should be_false
@sub_page.target_klass_name.should be_nil # @sub_page.target_klass_name.should be_nil
end # end
#
end # end
#
context 'using a content type' do # context 'using a content type' do
#
before(:each) do # before(:each) do
@site = FactoryGirl.build(:site) # @site = FactoryGirl.build(:site)
@content_type = FactoryGirl.build(:content_type, :slug => 'posts', :site => @site) # @content_type = FactoryGirl.build(:content_type, :slug => 'posts', :site => @site)
@page.site = @site # @page.site = @site
@page.target_klass_name = 'Locomotive::Entry42' # @page.target_klass_name = 'Locomotive::Entry42'
end # end
#
it 'has a name for the target entry' do # it 'has a name for the target entry' do
@site.stubs(:content_types).returns(mock(:find => @content_type)) # @site.stubs(:content_types).returns(mock(:find => @content_type))
@page.target_entry_name.should == 'post' # @page.target_entry_name.should == 'post'
end # end
#
context '#security' do # context '#security' do
#
before(:each) do # before(:each) do
Locomotive::ContentType.stubs(:find).returns(@content_type) # Locomotive::ContentType.stubs(:find).returns(@content_type)
end # end
#
it 'is valid if the content type belongs to the site' do # it 'is valid if the content type belongs to the site' do
@page.send(:ensure_target_klass_name_security) # @page.send(:ensure_target_klass_name_security)
@page.errors.should be_empty # @page.errors.should be_empty
end # end
#
it 'does not valid the page if the content type does not belong to the site' do # it 'does not valid the page if the content type does not belong to the site' do
@content_type.site = FactoryGirl.build(:site) # @content_type.site = FactoryGirl.build(:site)
@page.send(:ensure_target_klass_name_security) # @page.send(:ensure_target_klass_name_security)
@page.errors[:target_klass_name].should == ['presents a security problem'] # @page.errors[:target_klass_name].should == ['presents a security problem']
end # end
#
end # end
#
end # end
#
end # end
describe 'listed extension' do describe 'listed extension' do