custom fields has its own repo + upgrade code for Mongoid beta 16 + clean code + fix rspec tests
This commit is contained in:
parent
53500bda9e
commit
e25ded881b
3
Gemfile
3
Gemfile
@ -6,7 +6,7 @@ gem 'rails', '3.0.0.rc'
|
||||
gem 'liquid', :git => 'git://github.com/locomotivecms/liquid.git', :ref => 'a41213c77cbc81dab87d'
|
||||
|
||||
gem 'bson_ext', '>= 1.0.1'
|
||||
gem 'mongoid', :git => 'git://github.com/durran/mongoid.git', :ref => 'e387a0d1dc74da057472'
|
||||
gem 'mongoid', '2.0.0.beta.16'
|
||||
gem 'mongoid_acts_as_tree', '0.1.5'
|
||||
gem 'mongo_session_store', '2.0.0.pre'
|
||||
gem 'warden'
|
||||
@ -22,6 +22,7 @@ gem 'heroku'
|
||||
gem 'httparty', '0.6.1'
|
||||
gem 'RedCloth'
|
||||
gem 'inherited_resources', '1.1.2'
|
||||
gem 'custom_fields', :git => 'git://github.com/locomotivecms/custom_fields.git'
|
||||
gem 'jeweler'
|
||||
|
||||
# Development environment
|
||||
|
29
Gemfile.lock
29
Gemfile.lock
@ -1,15 +1,3 @@
|
||||
GIT
|
||||
remote: git://github.com/durran/mongoid.git
|
||||
revision: e387a0d
|
||||
ref: e387a0d1dc74da057472
|
||||
specs:
|
||||
mongoid (2.0.0.beta.15)
|
||||
activemodel (= 3.0.0.rc)
|
||||
bson (= 1.0.4)
|
||||
mongo (= 1.0.6)
|
||||
tzinfo (= 0.3.22)
|
||||
will_paginate (~> 3.0.pre)
|
||||
|
||||
GIT
|
||||
remote: git://github.com/floehopper/mocha.git
|
||||
revision: d1715ff
|
||||
@ -17,6 +5,12 @@ GIT
|
||||
mocha (0.9.8.20090918115329)
|
||||
rake
|
||||
|
||||
GIT
|
||||
remote: git://github.com/locomotivecms/custom_fields.git
|
||||
revision: d393307
|
||||
specs:
|
||||
custom_fields (0.0.0.1)
|
||||
|
||||
GIT
|
||||
remote: git://github.com/locomotivecms/liquid.git
|
||||
revision: a41213c
|
||||
@ -152,10 +146,16 @@ GEM
|
||||
treetop (>= 1.4.5)
|
||||
mime-types (1.16)
|
||||
mimetype-fu (0.1.2)
|
||||
mongo (1.0.6)
|
||||
mongo (1.0.7)
|
||||
bson (>= 1.0.4)
|
||||
mongo_session_store (2.0.0.pre)
|
||||
actionpack (~> 3.0)
|
||||
mongoid (2.0.0.beta.16)
|
||||
activemodel (= 3.0.0.rc)
|
||||
bson (= 1.0.4)
|
||||
mongo (= 1.0.7)
|
||||
tzinfo (= 0.3.22)
|
||||
will_paginate (~> 3.0.pre)
|
||||
mongoid_acts_as_tree (0.1.5)
|
||||
bson (>= 0.20.1)
|
||||
mongoid (<= 2.0.0)
|
||||
@ -246,6 +246,7 @@ DEPENDENCIES
|
||||
cgi_multipart_eof_fix
|
||||
cucumber
|
||||
cucumber-rails
|
||||
custom_fields!
|
||||
database_cleaner
|
||||
devise!
|
||||
factory_girl_rails
|
||||
@ -262,7 +263,7 @@ DEPENDENCIES
|
||||
mimetype-fu
|
||||
mocha!
|
||||
mongo_session_store (= 2.0.0.pre)
|
||||
mongoid!
|
||||
mongoid (= 2.0.0.beta.16)
|
||||
mongoid_acts_as_tree (= 0.1.5)
|
||||
mongrel
|
||||
pickle!
|
||||
|
@ -1,13 +0,0 @@
|
||||
module Admin
|
||||
class LayoutsController < BaseController
|
||||
|
||||
sections 'settings'
|
||||
|
||||
respond_to :json, :only => :update
|
||||
|
||||
def index
|
||||
@layouts = current_site.layouts.order_by([[:name, :asc]])
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -1,15 +1,16 @@
|
||||
module Admin
|
||||
class PagePartsController < BaseController
|
||||
|
||||
layout nil
|
||||
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
parts = current_site.layouts.find(params[:layout_id]).parts
|
||||
|
||||
respond_with parts.collect(&:attributes)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
# @DEPRECATED
|
||||
# module Admin
|
||||
# class PagePartsController < BaseController
|
||||
#
|
||||
# layout nil
|
||||
#
|
||||
# respond_to :json
|
||||
#
|
||||
# def index
|
||||
# parts = current_site.layouts.find(params[:layout_id]).parts
|
||||
#
|
||||
# respond_with parts.collect(&:attributes)
|
||||
# end
|
||||
#
|
||||
# end
|
||||
# end
|
||||
|
@ -1,58 +1,59 @@
|
||||
module Models
|
||||
module Extensions
|
||||
module Page
|
||||
module Parts
|
||||
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
embeds_many :parts, :class_name => 'PagePart'
|
||||
|
||||
before_validation do |p|
|
||||
if p.parts.empty?
|
||||
p.parts << PagePart.build_body_part(p.respond_to?(:body) ? p.body : nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
|
||||
def parts_attributes=(attributes)
|
||||
self.update_parts(attributes.values.map { |attrs| PagePart.new(attrs) })
|
||||
end
|
||||
|
||||
def joined_parts
|
||||
self.parts.enabled.map(&:template).join('')
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def update_parts(parts)
|
||||
performed = []
|
||||
|
||||
# add / update
|
||||
parts.each do |part|
|
||||
if (existing = self.parts.detect { |p| p.id == part.id || p.slug == part.slug })
|
||||
existing.attributes = part.attributes.delete_if { |k, v| %w{_id slug}.include?(k) }
|
||||
else
|
||||
self.parts << (existing = part)
|
||||
end
|
||||
performed << existing unless existing.disabled?
|
||||
end
|
||||
|
||||
# disable missing parts
|
||||
(self.parts.map(&:slug) - performed.map(&:slug)).each do |slug|
|
||||
self.parts.detect { |p| p.slug == slug }.disabled = true
|
||||
end
|
||||
end
|
||||
|
||||
def update_parts!(new_parts)
|
||||
self.update_parts(new_parts)
|
||||
self.save
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
# @DEPRECATED
|
||||
# module Models
|
||||
# module Extensions
|
||||
# module Page
|
||||
# module Parts
|
||||
#
|
||||
# extend ActiveSupport::Concern
|
||||
#
|
||||
# included do
|
||||
# embeds_many :parts, :class_name => 'PagePart'
|
||||
#
|
||||
# before_validation do |p|
|
||||
# if p.parts.empty?
|
||||
# p.parts << PagePart.build_body_part(p.respond_to?(:body) ? p.body : nil)
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# module InstanceMethods
|
||||
#
|
||||
# def parts_attributes=(attributes)
|
||||
# self.update_parts(attributes.values.map { |attrs| PagePart.new(attrs) })
|
||||
# end
|
||||
#
|
||||
# def joined_parts
|
||||
# self.parts.enabled.map(&:template).join('')
|
||||
# end
|
||||
#
|
||||
# protected
|
||||
#
|
||||
# def update_parts(parts)
|
||||
# performed = []
|
||||
#
|
||||
# # add / update
|
||||
# parts.each do |part|
|
||||
# if (existing = self.parts.detect { |p| p.id == part.id || p.slug == part.slug })
|
||||
# existing.attributes = part.attributes.delete_if { |k, v| %w{_id slug}.include?(k) }
|
||||
# else
|
||||
# self.parts << (existing = part)
|
||||
# end
|
||||
# performed << existing unless existing.disabled?
|
||||
# end
|
||||
#
|
||||
# # disable missing parts
|
||||
# (self.parts.map(&:slug) - performed.map(&:slug)).each do |slug|
|
||||
# self.parts.detect { |p| p.slug == slug }.disabled = true
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# def update_parts!(new_parts)
|
||||
# self.update_parts(new_parts)
|
||||
# self.save
|
||||
# end
|
||||
#
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
|
@ -5,15 +5,6 @@ module Models
|
||||
|
||||
def render(context)
|
||||
self.template.render(context)
|
||||
|
||||
# FIXME : old code based on layout / parts
|
||||
# self.template.render(context)
|
||||
#
|
||||
# if self.layout
|
||||
# self.layout.template.render(context)
|
||||
# else
|
||||
# ::Liquid::Template.parse("{{ content_for_layout }}").render(context)
|
||||
# end
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -24,6 +24,7 @@ module Models
|
||||
|
||||
# Fixme (Didier L.): Instances methods are defined before the include itself
|
||||
alias :fix_position :hacked_fix_position
|
||||
alias :descendants :hacked_descendants
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
@ -42,6 +43,11 @@ module Models
|
||||
self.instance_variable_set :@_will_move, true
|
||||
end
|
||||
|
||||
def hacked_descendants
|
||||
return [] if new_record?
|
||||
self.class.all_in(path_field => [self._id]).order_by tree_order
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def change_parent
|
||||
|
@ -1,74 +0,0 @@
|
||||
# @deprecated
|
||||
class Layout < LiquidTemplate
|
||||
|
||||
# acts_as_tree
|
||||
|
||||
protected
|
||||
|
||||
# TODO: move that in the liquify_template module
|
||||
|
||||
def after_parse_template
|
||||
blocks = self.find_blocks(self.template.root)
|
||||
self.template.send(:instance_variable_set, :"@parent_blocks", blocks)
|
||||
end
|
||||
|
||||
def find_blocks(node, blocks = {})
|
||||
if node.respond_to?(:nodelist) && node.nodelist
|
||||
node.nodelist.inject(blocks) do |b, node|
|
||||
if node.is_a?(Locomotive::Liquid::Tags::Block)
|
||||
b[node.name] = node
|
||||
end
|
||||
self.find_blocks(node, b) # FIXME: find nested blocks too
|
||||
b
|
||||
end
|
||||
end
|
||||
blocks
|
||||
end
|
||||
|
||||
## associations ##
|
||||
|
||||
# references_many :pages
|
||||
# embeds_many :parts, :class_name => 'PagePart'
|
||||
|
||||
## callbacks ##
|
||||
# before_save :build_parts_from_value
|
||||
# after_save :update_parts_in_pages
|
||||
|
||||
## validations ##
|
||||
# validates_format_of :value, :with => Locomotive::Regexps::CONTENT_FOR_LAYOUT, :message => :missing_content_for_layout
|
||||
|
||||
## methods ##
|
||||
|
||||
# protected
|
||||
#
|
||||
# def build_parts_from_value
|
||||
# if self.value_changed? || self.new_record?
|
||||
# self.parts.each { |p| p.disabled = true }
|
||||
#
|
||||
# self.value.scan(Locomotive::Regexps::CONTENT_FOR).each do |attributes|
|
||||
# slug = attributes[0].strip.downcase
|
||||
# name = slug.humanize
|
||||
# name = I18n.t('attributes.defaults.page_parts.name') if slug == 'layout'
|
||||
#
|
||||
# if part = self.parts.detect { |p| p.slug == slug }
|
||||
# part.name = name if name.present?
|
||||
# part.disabled = false
|
||||
# else
|
||||
# self.parts.build :slug => slug, :name => name || slug
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# # body always first
|
||||
# body = self.parts.detect { |p| p.slug == 'layout' }
|
||||
# self.parts.delete(body)
|
||||
# self.parts.insert(0, body)
|
||||
#
|
||||
# @_update_pages = true if self.value_changed?
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# def update_parts_in_pages
|
||||
# self.pages.each { |p| p.send(:update_parts!, self.parts) } if @_update_pages
|
||||
# end
|
||||
|
||||
end
|
@ -22,7 +22,6 @@ class Page
|
||||
|
||||
## associations ##
|
||||
referenced_in :site
|
||||
# referenced_in :layout
|
||||
|
||||
## callbacks ##
|
||||
before_validation :normalize_slug
|
||||
|
@ -1,35 +1,36 @@
|
||||
class PagePart
|
||||
|
||||
include Mongoid::Document
|
||||
|
||||
## fields ##
|
||||
field :name
|
||||
field :slug
|
||||
field :value
|
||||
field :disabled, :type => Boolean, :default => false
|
||||
field :value
|
||||
|
||||
## associations ##
|
||||
embedded_in :page, :inverse_of => :parts
|
||||
|
||||
## validations ##
|
||||
validates_presence_of :name, :slug
|
||||
|
||||
## named scopes ##
|
||||
scope :enabled, where(:disabled => false)
|
||||
|
||||
## methods ##
|
||||
|
||||
def template
|
||||
"{% capture content_for_#{self.slug} %}#{self.value}{% endcapture %}"
|
||||
end
|
||||
|
||||
def self.build_body_part(body_content = nil)
|
||||
self.new({
|
||||
:name => I18n.t('attributes.defaults.page_parts.name'),
|
||||
:value => body_content || I18n.t('attributes.defaults.pages.other.body'),
|
||||
:slug => 'layout'
|
||||
})
|
||||
end
|
||||
|
||||
end
|
||||
# @DEPRECATED
|
||||
# class PagePart
|
||||
#
|
||||
# include Mongoid::Document
|
||||
#
|
||||
# ## fields ##
|
||||
# field :name
|
||||
# field :slug
|
||||
# field :value
|
||||
# field :disabled, :type => Boolean, :default => false
|
||||
# field :value
|
||||
#
|
||||
# ## associations ##
|
||||
# embedded_in :page, :inverse_of => :parts
|
||||
#
|
||||
# ## validations ##
|
||||
# validates_presence_of :name, :slug
|
||||
#
|
||||
# ## named scopes ##
|
||||
# scope :enabled, where(:disabled => false)
|
||||
#
|
||||
# ## methods ##
|
||||
#
|
||||
# def template
|
||||
# "{% capture content_for_#{self.slug} %}#{self.value}{% endcapture %}"
|
||||
# end
|
||||
#
|
||||
# def self.build_body_part(body_content = nil)
|
||||
# self.new({
|
||||
# :name => I18n.t('attributes.defaults.page_parts.name'),
|
||||
# :value => body_content || I18n.t('attributes.defaults.pages.other.body'),
|
||||
# :slug => 'layout'
|
||||
# })
|
||||
# end
|
||||
#
|
||||
# end
|
||||
|
@ -11,11 +11,10 @@ class Site
|
||||
|
||||
## associations ##
|
||||
references_many :pages
|
||||
references_many :layouts
|
||||
references_many :snippets
|
||||
references_many :theme_assets
|
||||
references_many :asset_collections
|
||||
references_many :content_types
|
||||
references_many :snippets, :dependent => :destroy
|
||||
references_many :theme_assets, :dependent => :destroy
|
||||
references_many :asset_collections, :dependent => :destroy
|
||||
references_many :content_types, :dependent => :destroy
|
||||
embeds_many :memberships
|
||||
|
||||
## validations ##
|
||||
@ -28,11 +27,13 @@ class Site
|
||||
## callbacks ##
|
||||
after_create :create_default_pages!
|
||||
before_save :add_subdomain_to_domains
|
||||
after_destroy :destroy_in_cascade!
|
||||
after_destroy :destroy_pages
|
||||
|
||||
## named scopes ##
|
||||
scope :match_domain, lambda { |domain| { :where => { :domains => domain } } }
|
||||
scope :match_domain_with_exclusion_of, lambda { |domain, site| { :where => { :domains => domain, :_id.ne => site.id } } }
|
||||
scope :match_domain, lambda { |domain| { :any_in => { :domains => [*domain] } } }
|
||||
scope :match_domain_with_exclusion_of, lambda { |domain, site|
|
||||
{ :any_in => { :domains => [*domain] }, :where => { :_id.ne => site.id } }
|
||||
}
|
||||
|
||||
## methods ##
|
||||
|
||||
@ -67,7 +68,7 @@ class Site
|
||||
return if self.domains.empty?
|
||||
|
||||
self.domains_without_subdomain.each do |domain|
|
||||
if not self.class.match_domain_with_exclusion_of(domain, self).empty?
|
||||
if self.class.match_domain_with_exclusion_of(domain, self).any?
|
||||
self.errors.add(:domains, :domain_taken, :value => domain)
|
||||
end
|
||||
|
||||
@ -88,10 +89,9 @@ class Site
|
||||
end
|
||||
end
|
||||
|
||||
def destroy_in_cascade!
|
||||
%w{pages layouts snippets theme_assets asset_collections content_types}.each do |association|
|
||||
self.send(association).destroy_all
|
||||
end
|
||||
def destroy_pages
|
||||
# pages is a tree so we just need to delete the root (as well as the page not found page)
|
||||
self.pages.index.first.try(:destroy) && self.pages.not_found.first.try(:destroy)
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -1,13 +0,0 @@
|
||||
- content_for :head do
|
||||
= javascript_include_tag 'admin/plugins/codemirror/codemirror', 'admin/layouts.js'
|
||||
= image_picker_include_tags
|
||||
|
||||
= f.inputs :name => :information do
|
||||
= f.input :name
|
||||
|
||||
= f.inputs :name => :code do
|
||||
= f.custom_input :value, :css => 'code full', :with_label => false do
|
||||
%code{ :class => 'html' }
|
||||
= f.text_area :value
|
||||
.more
|
||||
= link_to t('admin.image_picker.link'), admin_theme_assets_path, :id => 'image-picker-link'
|
@ -1,7 +0,0 @@
|
||||
%li
|
||||
%strong= link_to layout.name, edit_admin_layout_path(layout)
|
||||
.more
|
||||
%span!= t('.updated_at')
|
||||
= l layout.updated_at, :format => :short
|
||||
|
||||
= link_to image_tag('admin/list/icons/trash.png'), admin_layout_path(layout), :class => 'remove', :confirm => t('admin.messages.confirm'), :method => :delete
|
@ -1,15 +0,0 @@
|
||||
- title t('.title')
|
||||
|
||||
- content_for :submenu do
|
||||
= render 'admin/shared/menu/settings'
|
||||
|
||||
- content_for :buttons do
|
||||
= admin_button_tag :new, new_admin_layout_url, :class => 'new'
|
||||
|
||||
%p!= t('.help')
|
||||
|
||||
= semantic_form_for @layout, :url => admin_layout_url(@layout), :html => { :class => 'save-with-shortcut' } do |form|
|
||||
|
||||
= render 'form', :f => form
|
||||
|
||||
= render 'admin/shared/form_actions', :back_url => admin_layouts_url, :button_label => :update
|
@ -1,15 +0,0 @@
|
||||
- title t('.title')
|
||||
|
||||
- content_for :submenu do
|
||||
= render 'admin/shared/menu/settings'
|
||||
|
||||
- content_for :buttons do
|
||||
= admin_button_tag :new, new_admin_layout_url, :class => 'new'
|
||||
|
||||
%p!= t('.help')
|
||||
|
||||
- if @layouts.empty?
|
||||
%p.no-items!= t('.no_items', :url => new_admin_layout_url)
|
||||
- else
|
||||
%ul#layouts-list.list
|
||||
= render @layouts
|
@ -1,12 +0,0 @@
|
||||
- title t('.title')
|
||||
|
||||
- content_for :submenu do
|
||||
= render 'admin/shared/menu/settings'
|
||||
|
||||
%p!= t('.help')
|
||||
|
||||
= semantic_form_for @layout, :url => admin_layouts_url do |form|
|
||||
|
||||
= render 'form', :f => form
|
||||
|
||||
= render 'admin/shared/form_actions', :back_url => admin_layouts_url, :button_label => :create
|
@ -6,8 +6,6 @@
|
||||
|
||||
= f.input :title
|
||||
|
||||
/ = f.input :layout_id, :as => :select, :collection => current_site.layouts.all.to_a, :input_html => { :data_url => admin_layout_page_parts_url('_id_to_replace_') }
|
||||
|
||||
- if not @page.index? and not @page.not_found?
|
||||
= f.input :parent_id, :as => :select, :collection => parent_pages_options, :include_blank => false
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
%ul
|
||||
= admin_submenu_item 'site', edit_admin_current_site_url
|
||||
/ = admin_submenu_item 'layouts', admin_layouts_url
|
||||
= admin_submenu_item 'snippets', admin_snippets_url
|
||||
= admin_submenu_item 'theme_assets', admin_theme_assets_url
|
||||
= admin_submenu_item 'account', edit_admin_my_account_url
|
@ -20,7 +20,6 @@ en:
|
||||
assets: Assets
|
||||
settings: Settings
|
||||
pages: Pages
|
||||
layouts: Layouts
|
||||
snippets: Snippets
|
||||
account: My account
|
||||
site: Site
|
||||
@ -108,22 +107,6 @@ en:
|
||||
week: 1 week
|
||||
month: 1 month
|
||||
|
||||
layouts:
|
||||
index:
|
||||
title: Listing layouts
|
||||
help: "Layouts give the look of a page (1, 2 or many columns)."
|
||||
no_items: "There are no layouts for now. Just click <a href=\"%{url}\">here</a> to create the first one."
|
||||
new: new layout
|
||||
new:
|
||||
title: New layout
|
||||
help: "Fill in the form below to create your layout."
|
||||
edit:
|
||||
title: Editing layout
|
||||
help: "Fill in the form below to update your layout."
|
||||
new: new layout
|
||||
layout:
|
||||
updated_at: Updated at
|
||||
|
||||
snippets:
|
||||
index:
|
||||
title: Listing snippets
|
||||
@ -291,7 +274,7 @@ en:
|
||||
cache_strategy: "Cache the page for better performance. The 'Simple' choice is a good compromise."
|
||||
templatized: "Use the page as a template for a model you defined."
|
||||
snippet:
|
||||
slug: "You need to know it in order to insert the snippet inside a page or a layout"
|
||||
slug: "You need to know it in order to insert the snippet inside a page"
|
||||
site:
|
||||
meta_keywords: "Meta keywords used within the head tag of the page. They are separeted by an empty space. Required for SEO."
|
||||
meta_description: "Meta description used within the head tag of the page. Required for SEO."
|
||||
|
@ -30,7 +30,6 @@ fr:
|
||||
assets: Média
|
||||
settings: Paramètres
|
||||
pages: Pages
|
||||
layouts: Gabarits
|
||||
snippets: Snippets
|
||||
account: Mon compte
|
||||
site: Site
|
||||
@ -108,22 +107,6 @@ fr:
|
||||
week: 1 semaine
|
||||
month: 1 mois
|
||||
|
||||
layouts:
|
||||
index:
|
||||
title: Liste gabarits
|
||||
help: "Les gabarits permettent de définir le squelette d'une page (1, 2 ou plusieurs colonnes)."
|
||||
no_items: "Il n'existe pas de gabarit. Vous pouvez commencer par créer un <a href='%{url}'>ici</a>."
|
||||
new: nouveau gabarit
|
||||
new:
|
||||
title: Nouveau gabarit
|
||||
help: "Remplissez le formulaire ci-dessous pour créer votre gabarit."
|
||||
edit:
|
||||
title: Edition gabarit
|
||||
help: "Remplissez le formulaire ci-dessous pour mettre à jour votre gabarit."
|
||||
new: nouveau gabarit
|
||||
layout:
|
||||
updated_at: Mis à jour le
|
||||
|
||||
snippets:
|
||||
index:
|
||||
title: Liste des snippets
|
||||
@ -290,7 +273,7 @@ fr:
|
||||
cache_strategy: "Cache la page pour de meilleure performance. L'option 'Simple' est le meilleur compromis."
|
||||
templatized: "Utilise la page comme un template pour un modèle défini."
|
||||
snippet:
|
||||
slug: "Utilisé pour insérer le snippet dans une page ou un gabarit."
|
||||
slug: "Utilisé pour insérer le snippet dans une page."
|
||||
site:
|
||||
meta_keywords: "Mots-clés utilisés à l'intérieur de la balise HEAD. Ils sont séparés par un espace. Requis pour un meilleur référencement."
|
||||
meta_description: "Description utilisée à l'intérieur de la balise HEAD. Requis pour un meilleur référencement."
|
||||
|
@ -2,18 +2,17 @@ en:
|
||||
date:
|
||||
formats:
|
||||
default: "%m/%d/%Y"
|
||||
|
||||
|
||||
errors:
|
||||
messages:
|
||||
domain_taken: "%{value} is already taken"
|
||||
invalid_domain: "%{value} is invalid"
|
||||
missing_content_for_layout: "should contain 'content_for_layout' liquid tag"
|
||||
needs_admin_account: "One admin account is required at least"
|
||||
protected_page: "You can not remove index or 404 pages"
|
||||
extname_changed: "New file does not have the original extension"
|
||||
array_too_short: "is too small (minimum element number is %{count})"
|
||||
liquid_syntax_error: "Syntax error in page parts, please check the syntax"
|
||||
|
||||
|
||||
attributes:
|
||||
defaults:
|
||||
pages:
|
||||
@ -27,7 +26,7 @@ en:
|
||||
body: "Content goes here"
|
||||
page_parts:
|
||||
name: "Body"
|
||||
|
||||
|
||||
pagination:
|
||||
previous: "« Previous"
|
||||
next: "Next »"
|
||||
|
@ -28,7 +28,6 @@ fr:
|
||||
|
||||
domain_taken: "%{value} a été déjà pris"
|
||||
invalid_domain: "%{value} n'est pas valide"
|
||||
missing_content_for_layout: "doit contenir le tag liquid 'content_for_layout'"
|
||||
needs_admin_account: "Un minimum d'un scompte admin est requis"
|
||||
protected_page: "Vous ne pouvez pas supprimer les pages index et 404"
|
||||
extname_changed: "Nouveau fichier n'a pas l'extension original"
|
||||
@ -53,7 +52,6 @@ fr:
|
||||
attributes:
|
||||
page:
|
||||
title: Titre
|
||||
layout_id: Gabarit
|
||||
parent: Parent
|
||||
slug: Raccourci
|
||||
templatized: Templatisée
|
||||
@ -79,9 +77,6 @@ fr:
|
||||
language: Langue
|
||||
new_password: "Nouveau mot de passe"
|
||||
new_password_confirmation: "Confirmation nouveau mot de passe"
|
||||
layout:
|
||||
name: Nom
|
||||
body: Code
|
||||
snippet:
|
||||
body: Code
|
||||
slug: Raccourci
|
||||
|
@ -40,16 +40,6 @@ en:
|
||||
notice: "My site was successfully updated."
|
||||
alert: "My site was not updated."
|
||||
|
||||
layouts:
|
||||
create:
|
||||
notice: "Layout was successfully created."
|
||||
alert: "Layout was not created."
|
||||
update:
|
||||
notice: "Layout was successfully updated."
|
||||
alert: "Layout was not updated."
|
||||
destroy:
|
||||
notice: "Layout was successfully deleted."
|
||||
|
||||
snippets:
|
||||
create:
|
||||
notice: "Snippet was successfully created."
|
||||
|
@ -40,16 +40,6 @@ fr:
|
||||
notice: "Mon site a été mis à jour avec succès."
|
||||
alert: "Mon site n'a pas été mis à jour."
|
||||
|
||||
layouts:
|
||||
create:
|
||||
notice: "Le gabarit a été crée avec succès."
|
||||
alert: "Le gabarit n'a pas été crée."
|
||||
update:
|
||||
notice: "Le gabarit a été mis à jour avec succès."
|
||||
alert: "Le gabarit n'a pas été mis à jour."
|
||||
destroy:
|
||||
notice: "Le gabarit a été supprimé avec succès."
|
||||
|
||||
snippets:
|
||||
create:
|
||||
notice: "Le snippet a été crée avec succès."
|
||||
|
@ -17,9 +17,6 @@ Rails.application.routes.draw do
|
||||
get :get_path, :on => :collection
|
||||
end
|
||||
|
||||
resources :layouts do
|
||||
resources :page_parts, :only => :index
|
||||
end
|
||||
resources :snippets
|
||||
|
||||
resources :sites
|
||||
|
@ -18,7 +18,7 @@ Scenario: Creating a valid page
|
||||
And I fill in "Title" with "Test"
|
||||
And I fill in "Slug" with "test"
|
||||
And I select "Home page" from "Parent"
|
||||
And I fill in "Body" with "Lorem ipsum...."
|
||||
And I fill in "Layout Template" with "Lorem ipsum...."
|
||||
And I press "Create"
|
||||
Then I should see "Page was successfully created."
|
||||
And I should have "Lorem ipsum...." in the test page layout
|
||||
@ -27,7 +27,7 @@ Scenario: Updating a valid page
|
||||
When I go to pages
|
||||
And I follow "Home page"
|
||||
And I fill in "Title" with "Home page !"
|
||||
And I fill in "Body" with "My new content is here"
|
||||
And I fill in "Layout Template" with "My new content is here"
|
||||
And I press "Update"
|
||||
Then I should see "Page was successfully updated."
|
||||
And I should have "My new content is here" in the index page layout
|
||||
|
@ -27,13 +27,13 @@ end
|
||||
|
||||
### Common
|
||||
|
||||
def create_layout_samples
|
||||
Factory(:layout, :site => @site, :name => 'One column', :value => %{<html>
|
||||
<head>
|
||||
<title>My website</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="main">{{ content_for_layout }}</div>
|
||||
</body>
|
||||
</html>})
|
||||
end
|
||||
# def create_layout_samples
|
||||
# Factory(:layout, :site => @site, :name => 'One column', :value => %{<html>
|
||||
# <head>
|
||||
# <title>My website</title>
|
||||
# </head>
|
||||
# <body>
|
||||
# <div id="main">{{ content_for_layout }}</div>
|
||||
# </body>
|
||||
# </html>})
|
||||
# end
|
||||
|
@ -17,29 +17,24 @@ Given /^a page named "([^"]*)" with the template:$/ do |page_slug, template|
|
||||
@page = create_content_page(page_slug, '', template)
|
||||
end
|
||||
|
||||
# creates a layout
|
||||
Given /^a layout named "([^"]*)" with the source:$/ do |layout_name, layout_body|
|
||||
@layout = Factory(:layout, :name => layout_name, :value => layout_body, :site => @site)
|
||||
end
|
||||
|
||||
# creates a part within a page
|
||||
Given /^the page named "([^"]*)" has the part "([^"]*)" with the content:$/ do |page_slug, part_slug, part_contents|
|
||||
page = @site.pages.where(:slug => page_slug).first
|
||||
raise "Could not find page: #{page_slug}" unless page
|
||||
|
||||
# find or crate page part
|
||||
part = page.parts.where(:slug => part_slug).first
|
||||
unless part
|
||||
part = page.parts.build(:name => part_slug.titleize, :slug => part_slug)
|
||||
end
|
||||
|
||||
# set part value
|
||||
part.value = part_contents
|
||||
part.should be_valid
|
||||
|
||||
# save page with embedded part
|
||||
page.save
|
||||
end
|
||||
# # creates a part within a page
|
||||
# Given /^the page named "([^"]*)" has the part "([^"]*)" with the content:$/ do |page_slug, part_slug, part_contents|
|
||||
# page = @site.pages.where(:slug => page_slug).first
|
||||
# raise "Could not find page: #{page_slug}" unless page
|
||||
#
|
||||
# # find or crate page part
|
||||
# part = page.parts.where(:slug => part_slug).first
|
||||
# unless part
|
||||
# part = page.parts.build(:name => part_slug.titleize, :slug => part_slug)
|
||||
# end
|
||||
#
|
||||
# # set part value
|
||||
# part.value = part_contents
|
||||
# part.should be_valid
|
||||
#
|
||||
# # save page with embedded part
|
||||
# page.save
|
||||
# end
|
||||
|
||||
# try to render a page by slug
|
||||
When /^I view the rendered page at "([^"]*)"$/ do |path|
|
||||
|
@ -5,9 +5,5 @@ module Locomotive
|
||||
|
||||
DOMAIN = /^[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/ix
|
||||
|
||||
CONTENT_FOR = /\{\{\s*content_for_([a-zA-Z]{1}[a-zA-Z_0-9]*)(\s+.*)?\s*\}\}/
|
||||
|
||||
CONTENT_FOR_LAYOUT = /\{\{\s*content_for_layout\s*/
|
||||
|
||||
end
|
||||
end
|
||||
|
@ -1,7 +0,0 @@
|
||||
$(document).ready(function() {
|
||||
$('a#image-picker-link').imagepicker({
|
||||
insertFn: function(link) {
|
||||
return "{{ theme_images." + link.attr('data-slug') + " }}";
|
||||
}
|
||||
});
|
||||
});
|
@ -17,8 +17,9 @@ $(document).ready(function() {
|
||||
var newRow = lastRow.clone(true).removeClass('template').addClass('added').insertBefore(lastRow);
|
||||
|
||||
// should copy the value of the select box
|
||||
var input_name = $('input#current_site_subdomain').attr('name').split('[')[0];
|
||||
var input = newRow.find('input.label')
|
||||
.attr('name', 'site[domains][]');
|
||||
.attr('name', input_name + '[domains][]');
|
||||
if (lastRow.find('input.label').val() == '') input.val("undefined");
|
||||
|
||||
// then reset the form
|
||||
|
@ -67,41 +67,41 @@ Factory.define :liquid_template do |t|
|
||||
end
|
||||
|
||||
|
||||
## Layouts ##
|
||||
Factory.define :layout do |l|
|
||||
l.name '1 main column + sidebar'
|
||||
l.value %{<html>
|
||||
<head>
|
||||
<title>My website</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="sidebar">
|
||||
\{% block sidebar %\}
|
||||
DEFAULT SIDEBAR CONTENT
|
||||
\{% endblock %\}
|
||||
</div>
|
||||
<div id="main">
|
||||
\{% block main %\}
|
||||
DEFAULT MAIN CONTENT
|
||||
\{% endblock %\}
|
||||
</div>
|
||||
</body>
|
||||
</html>}
|
||||
l.site { Site.where(:subdomain => "acme").first || Factory(:site) }
|
||||
end
|
||||
|
||||
Factory.define :base_layout, :parent => :layout do |l|
|
||||
l.name '1 main column + sidebar'
|
||||
l.value %{<html>
|
||||
<head>
|
||||
<title>My website</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="sidebar">\{\{ content_for_left_sidebar \}\}</div>
|
||||
<div id="main">\{\{ content_for_layout | textile \}\}</div>
|
||||
</body>
|
||||
</html>}
|
||||
end
|
||||
# ## Layouts ##
|
||||
# Factory.define :layout do |l|
|
||||
# l.name '1 main column + sidebar'
|
||||
# l.value %{<html>
|
||||
# <head>
|
||||
# <title>My website</title>
|
||||
# </head>
|
||||
# <body>
|
||||
# <div id="sidebar">
|
||||
# \{% block sidebar %\}
|
||||
# DEFAULT SIDEBAR CONTENT
|
||||
# \{% endblock %\}
|
||||
# </div>
|
||||
# <div id="main">
|
||||
# \{% block main %\}
|
||||
# DEFAULT MAIN CONTENT
|
||||
# \{% endblock %\}
|
||||
# </div>
|
||||
# </body>
|
||||
# </html>}
|
||||
# l.site { Site.where(:subdomain => "acme").first || Factory(:site) }
|
||||
# end
|
||||
#
|
||||
# Factory.define :base_layout, :parent => :layout do |l|
|
||||
# l.name '1 main column + sidebar'
|
||||
# l.value %{<html>
|
||||
# <head>
|
||||
# <title>My website</title>
|
||||
# </head>
|
||||
# <body>
|
||||
# <div id="sidebar">\{\{ content_for_left_sidebar \}\}</div>
|
||||
# <div id="main">\{\{ content_for_layout | textile \}\}</div>
|
||||
# </body>
|
||||
# </html>}
|
||||
# end
|
||||
|
||||
|
||||
## Snippets ##
|
||||
|
@ -7,21 +7,21 @@ describe Locomotive::Liquid::Tags::Consume do
|
||||
it 'validates a basic syntax' do
|
||||
markup = 'blog from "http://blog.locomotiveapp.org"'
|
||||
lambda do
|
||||
Locomotive::Liquid::Tags::Consume.new('consume', markup, ["{% endconsume %}"])
|
||||
Locomotive::Liquid::Tags::Consume.new('consume', markup, ["{% endconsume %}"], {})
|
||||
end.should_not raise_error
|
||||
end
|
||||
|
||||
it 'validates more complex syntax with attributes' do
|
||||
markup = 'blog from "http://www.locomotiveapp.org" username: "john", password: "easyone"'
|
||||
lambda do
|
||||
Locomotive::Liquid::Tags::Consume.new('consume', markup, ["{% endconsume %}"])
|
||||
Locomotive::Liquid::Tags::Consume.new('consume', markup, ["{% endconsume %}"], {})
|
||||
end.should_not raise_error
|
||||
end
|
||||
|
||||
it 'raises an error if the syntax is incorrect' do
|
||||
markup = 'blog from http://www.locomotiveapp.org'
|
||||
lambda do
|
||||
Locomotive::Liquid::Tags::Consume.new('consume', markup, ["{% endconsume %}"])
|
||||
Locomotive::Liquid::Tags::Consume.new('consume', markup, ["{% endconsume %}"], {})
|
||||
end.should raise_error
|
||||
end
|
||||
|
||||
|
@ -5,14 +5,14 @@ describe Locomotive::Liquid::Tags::Paginate do
|
||||
it 'should have a valid syntax' do
|
||||
markup = "contents.projects by 5"
|
||||
lambda do
|
||||
Locomotive::Liquid::Tags::Paginate.new('paginate', markup, ["{% endpaginate %}"])
|
||||
Locomotive::Liquid::Tags::Paginate.new('paginate', markup, ["{% endpaginate %}"], {})
|
||||
end.should_not raise_error
|
||||
end
|
||||
|
||||
it 'should raise an error if the syntax is incorrect' do
|
||||
["contents.projects by a", "contents.projects", "contents.projects 5"].each do |markup|
|
||||
lambda do
|
||||
Locomotive::Liquid::Tags::Paginate.new('paginate', markup, ["{% endpaginate %}"])
|
||||
Locomotive::Liquid::Tags::Paginate.new('paginate', markup, ["{% endpaginate %}"], {})
|
||||
end.should raise_error
|
||||
end
|
||||
end
|
||||
|
@ -3,7 +3,7 @@ require 'spec_helper'
|
||||
describe Locomotive::Liquid::Tags::WithScope do
|
||||
|
||||
it 'should decode options (boolean, interger, ...)' do
|
||||
scope = Locomotive::Liquid::Tags::WithScope.new('with_scope', 'active:true price:42 title:\'foo\' hidden:false', ["{% endwith_scope %}"])
|
||||
scope = Locomotive::Liquid::Tags::WithScope.new('with_scope', 'active:true price:42 title:\'foo\' hidden:false', ["{% endwith_scope %}"], {})
|
||||
attributes = scope.send(:decode, scope.instance_variable_get(:@attributes))
|
||||
attributes['active'].should == true
|
||||
attributes['price'].should == 42
|
||||
|
@ -1,64 +0,0 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Layout do
|
||||
|
||||
it 'should have a valid factory' do
|
||||
Factory.build(:layout).should be_valid
|
||||
end
|
||||
|
||||
# ## validations ##
|
||||
#
|
||||
# it 'should validate presence of content_for_layout in value' do
|
||||
# layout = Factory.build(:layout, :value => 'without content_for_layout')
|
||||
# layout.should_not be_valid
|
||||
# layout.errors[:value].should == ["should contain 'content_for_layout' liquid tag"]
|
||||
# end
|
||||
#
|
||||
# context 'dealing with page parts' do
|
||||
#
|
||||
# before(:each) do
|
||||
# @layout = Factory.build(:layout)
|
||||
# end
|
||||
#
|
||||
# it 'should have 2 parts' do
|
||||
# @layout.send(:build_parts_from_value)
|
||||
# @layout.parts.size.should == 2
|
||||
#
|
||||
# @layout.parts.first.name.should == 'Body'
|
||||
# @layout.parts.first.slug.should == 'layout'
|
||||
#
|
||||
# @layout.parts.last.name.should == 'Left sidebar'
|
||||
# @layout.parts.last.slug.should == 'left_sidebar'
|
||||
# end
|
||||
#
|
||||
# it 'should not add parts to pages if layout does not change' do
|
||||
# @layout.stubs(:value_changed?).returns(false)
|
||||
# page = Factory.build(:page, :layout => @layout, :site => nil)
|
||||
# page.expects(:update_parts!).never
|
||||
# @layout.pages << page
|
||||
# @layout.save
|
||||
# end
|
||||
#
|
||||
# it 'should add parts to pages if layout changes' do
|
||||
# @layout.value = @layout.value + "..."
|
||||
# page = Factory.build(:page, :layout => @layout, :site => nil)
|
||||
# page.expects(:update_parts!)
|
||||
# @layout.pages << page
|
||||
# @layout.save
|
||||
# end
|
||||
#
|
||||
# end
|
||||
#
|
||||
# context 'parsing liquid template' do
|
||||
#
|
||||
# before(:each) do
|
||||
# @layout = Factory.build(:layout)
|
||||
# end
|
||||
#
|
||||
# it 'should not raise an error if template is empty' do
|
||||
# @layout.template.should be_nil
|
||||
# end
|
||||
#
|
||||
# end
|
||||
|
||||
end
|
@ -105,120 +105,6 @@ describe Page do
|
||||
|
||||
end
|
||||
|
||||
describe 'accepts_nested_attributes_for used for parts' do
|
||||
|
||||
before(:each) do
|
||||
@page = Factory.build(:page)
|
||||
@page.parts.build(:name => 'Main content', :slug => 'layout')
|
||||
@page.parts.build(:name => 'Left column', :slug => 'left_sidebar')
|
||||
@page.parts.build(:name => 'Right column', :slug => 'right_sidebar')
|
||||
end
|
||||
|
||||
it 'should add parts' do
|
||||
attributes = { '0' => { 'slug' => 'footer', 'name' => 'A custom footer', 'value' => 'End of page' } }
|
||||
@page.parts_attributes = attributes
|
||||
@page.parts.size.should == 4
|
||||
@page.parts.last.slug.should == 'footer'
|
||||
@page.parts.last.disabled.should == false
|
||||
end
|
||||
|
||||
it 'should update parts' do
|
||||
attributes = { '0' => { 'slug' => 'layout', 'name' => 'A new name', 'value' => 'Hello world' } }
|
||||
@page.parts_attributes = attributes
|
||||
@page.parts.size.should == 3
|
||||
@page.parts.first.slug.should == 'layout'
|
||||
@page.parts.first.name.should == 'A new name'
|
||||
@page.parts.first.value.should == 'Hello world'
|
||||
end
|
||||
|
||||
it 'should disable parts' do
|
||||
attributes = { '0' => { 'slug' => 'left_sidebar', 'disabled' => 'true' } }
|
||||
@page.parts_attributes = attributes
|
||||
@page.parts.size.should == 3
|
||||
@page.parts.first.disabled.should == true
|
||||
@page.parts[1].disabled.should == true
|
||||
@page.parts[2].disabled.should == true
|
||||
end
|
||||
|
||||
it 'should add/update/disable parts at the same time' do
|
||||
@page.parts.size.should == 3
|
||||
|
||||
attributes = {
|
||||
'0' => { 'slug' => 'layout', 'name' => 'Body', 'value' => 'Hello world' },
|
||||
'1' => { 'slug' => 'left_sidebar', 'disabled' => 'true' },
|
||||
'2' => { 'id' => @page.parts[2].id, 'value' => 'Content from right sidebar', 'disabled' => 'false' }
|
||||
}
|
||||
@page.parts_attributes = attributes
|
||||
@page.parts.size.should == 3
|
||||
|
||||
@page.parts[0].value.should == 'Hello world'
|
||||
@page.parts[1].disabled.should == true
|
||||
@page.parts[2].disabled.should == false
|
||||
end
|
||||
|
||||
it 'should update it with success (mongoid bug #71)' do
|
||||
@page.save
|
||||
@page = Page.first
|
||||
|
||||
@page.parts.size.should == 3
|
||||
@page.parts_attributes = { '0' => { 'slug' => 'header', 'name' => 'A custom header', 'value' => 'Head of page' } }
|
||||
@page.parts.size.should == 4
|
||||
|
||||
@page.save
|
||||
@page = Page.first
|
||||
|
||||
@page.parts.size.should == 4
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe 'dealing with page parts' do # DUPLICATED ?
|
||||
|
||||
before(:each) do
|
||||
@page = Factory.build(:page)
|
||||
@parts = [
|
||||
PagePart.new(:name => 'Main content', :slug => 'layout'),
|
||||
PagePart.new(:name => 'Left column', :slug => 'left_sidebar'),
|
||||
PagePart.new(:name => 'Right column', :slug => 'right_sidebar')
|
||||
]
|
||||
@page.send(:update_parts, @parts)
|
||||
end
|
||||
|
||||
it 'should add new parts from an array of parts' do
|
||||
@page.parts.size.should == 3
|
||||
@page.parts.shift.name.should == 'Main content'
|
||||
@page.parts.shift.name.should == 'Left column'
|
||||
@page.parts.shift.name.should == 'Right column'
|
||||
end
|
||||
|
||||
it 'should update parts' do
|
||||
@parts[1].name = 'Very left column'
|
||||
@page.send(:update_parts, @parts)
|
||||
@page.parts.size.should == 3
|
||||
@page.parts[1].name.should == 'Very left column'
|
||||
@page.parts[1].slug.should == 'left_sidebar'
|
||||
end
|
||||
|
||||
it 'should disable parts' do
|
||||
@parts = [@parts.shift, @parts.pop]
|
||||
@page.send(:update_parts, @parts)
|
||||
@page.parts.size.should == 3
|
||||
@page.parts[1].name.should == 'Left column'
|
||||
@page.parts[1].disabled.should be_true
|
||||
end
|
||||
|
||||
it 'should enable parts previously disabled' do
|
||||
parts_at_first = @parts.clone
|
||||
@parts = [@parts.shift, @parts.pop]
|
||||
@page.send(:update_parts, @parts)
|
||||
@page.send(:update_parts, parts_at_first)
|
||||
@page.parts.size.should == 3
|
||||
@page.parts[1].name.should == 'Left column'
|
||||
@page.parts[1].disabled.should be_true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe 'acts as tree' do
|
||||
|
||||
before(:each) do
|
||||
@ -295,71 +181,6 @@ describe Page do
|
||||
|
||||
end
|
||||
|
||||
context 'rendering' do
|
||||
|
||||
before(:each) do
|
||||
@page = Factory.build(:page, :site => nil)
|
||||
@page.parts.build :slug => 'layout', :value => 'Hello world !'
|
||||
@page.parts.build :slug => 'left_sidebar', :value => 'A sidebar...'
|
||||
@page.send(:store_template)
|
||||
@layout = Factory.build(:layout, :site => nil)
|
||||
@layout.send(:store_template)
|
||||
@context = Liquid::Context.new
|
||||
end
|
||||
|
||||
context 'without layout' do
|
||||
|
||||
it 'should render the body part' do
|
||||
@page.render(@context).should == 'Hello world !'
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context 'with layout' do
|
||||
|
||||
it 'should render both the body and sidebar parts' do
|
||||
@page.layout = @layout
|
||||
@page.render(@context).should == %{<html>
|
||||
<head>
|
||||
<title>My website</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="sidebar">A sidebar...</div>
|
||||
<div id="main"><p>Hello world !</p></div>
|
||||
</body>
|
||||
</html>}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
describe "creating a new page" do
|
||||
|
||||
context "with a body" do
|
||||
before do
|
||||
@site = Factory(:site, :subdomain => "somethingweird")
|
||||
@page = Page.create({
|
||||
:slug => "some_slug",
|
||||
:title => "Page Title",
|
||||
:body => "Page Body",
|
||||
:published => true,
|
||||
:site => @site
|
||||
})
|
||||
end
|
||||
|
||||
it "should be valid" do
|
||||
@page.should be_valid
|
||||
end
|
||||
|
||||
it "should render the passed in body attribute of the page" do
|
||||
@page.render(Liquid::Context.new).should == "Page Body"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe 'templatized extension' do
|
||||
|
||||
before(:each) do
|
||||
|
@ -9,87 +9,87 @@ describe Site do
|
||||
it 'should have a valid factory' do
|
||||
Factory.build(:site).should be_valid
|
||||
end
|
||||
|
||||
|
||||
## Validations ##
|
||||
|
||||
|
||||
it 'should validate presence of name' do
|
||||
site = Factory.build(:site, :name => nil)
|
||||
site.should_not be_valid
|
||||
site.errors[:name].should == ["can't be blank"]
|
||||
end
|
||||
|
||||
|
||||
it 'should validate presence of subdomain' do
|
||||
site = Factory.build(:site, :subdomain => nil)
|
||||
site.should_not be_valid
|
||||
site.errors[:subdomain].should == ["can't be blank"]
|
||||
end
|
||||
|
||||
|
||||
%w{test test42}.each do |subdomain|
|
||||
it "should accept subdomain like '#{subdomain}'" do
|
||||
Factory.build(:site, :subdomain => subdomain).should be_valid
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
['-', '_test', 'test_', 't est', '42', '42test', 'foo_bar'].each do |subdomain|
|
||||
it "should not accept subdomain like '#{subdomain}'" do
|
||||
(site = Factory.build(:site, :subdomain => subdomain)).should_not be_valid
|
||||
site.errors[:subdomain].should == ['is invalid']
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
it "should not use reserved keywords as subdomain" do
|
||||
%w{www admin email blog webmail mail support help site sites}.each do |subdomain|
|
||||
(site = Factory.build(:site, :subdomain => subdomain)).should_not be_valid
|
||||
site.errors[:subdomain].should == ['is reserved']
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
it 'should validate uniqueness of subdomain' do
|
||||
Factory(:site)
|
||||
(site = Factory.build(:site)).should_not be_valid
|
||||
site.errors[:subdomain].should == ["is already taken"]
|
||||
end
|
||||
|
||||
|
||||
it 'should validate uniqueness of domains' do
|
||||
Factory(:site, :domains => %w{www.acme.net www.acme.com})
|
||||
|
||||
|
||||
(site = Factory.build(:site, :domains => %w{www.acme.com})).should_not be_valid
|
||||
site.errors[:domains].should == ["www.acme.com is already taken"]
|
||||
|
||||
|
||||
(site = Factory.build(:site, :subdomain => 'foo', :domains => %w{acme.example.com})).should_not be_valid
|
||||
site.errors[:domains].should == ["acme.example.com is already taken"]
|
||||
end
|
||||
|
||||
|
||||
it 'should validate format of domains' do
|
||||
site = Factory.build(:site, :domains => ['barformat.superlongextension', '-foo.net'])
|
||||
site.should_not be_valid
|
||||
site.errors[:domains].should == ['barformat.superlongextension is invalid', '-foo.net is invalid']
|
||||
end
|
||||
|
||||
|
||||
## Named scopes ##
|
||||
|
||||
|
||||
it 'should retrieve sites by domain' do
|
||||
site_1 = Factory(:site, :domains => %w{www.acme.net})
|
||||
site_2 = Factory(:site, :subdomain => 'test', :domains => %w{www.example.com})
|
||||
|
||||
|
||||
sites = Site.match_domain('www.acme.net')
|
||||
sites.size.should == 1
|
||||
sites.first.should == site_1
|
||||
|
||||
|
||||
sites = Site.match_domain('www.example.com')
|
||||
sites.size.should == 1
|
||||
sites.first.should == site_2
|
||||
|
||||
|
||||
sites = Site.match_domain('test.example.com')
|
||||
sites.size.should == 1
|
||||
sites.first.should == site_2
|
||||
|
||||
|
||||
sites = Site.match_domain('www.unknown.com')
|
||||
sites.should be_empty
|
||||
end
|
||||
|
||||
|
||||
## Associations ##
|
||||
|
||||
|
||||
it 'should have many accounts' do
|
||||
site = Factory.build(:site)
|
||||
account_1, account_2 = Factory(:account), Factory(:account, :name => 'homer', :email => 'homer@simpson.net')
|
||||
@ -98,50 +98,41 @@ describe Site do
|
||||
site.memberships.size.should == 2
|
||||
site.accounts.should == [account_1, account_2]
|
||||
end
|
||||
|
||||
|
||||
## Methods ##
|
||||
|
||||
|
||||
it 'should return domains without subdomain' do
|
||||
site = Factory(:site, :domains => %w{www.acme.net www.acme.com})
|
||||
site.domains.should == %w{www.acme.net www.acme.com acme.example.com}
|
||||
site.domains_without_subdomain.should == %w{www.acme.net www.acme.com}
|
||||
end
|
||||
|
||||
|
||||
describe 'once created' do
|
||||
|
||||
|
||||
before(:each) do
|
||||
@site = Factory(:site)
|
||||
end
|
||||
|
||||
|
||||
it 'should create index and 404 pages' do
|
||||
@site.pages.size.should == 2
|
||||
@site.pages.first.slug.should == 'index'
|
||||
@site.pages.last.slug.should == '404'
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
describe 'delete in cascade' do
|
||||
|
||||
describe 'deleting in cascade' do
|
||||
|
||||
before(:each) do
|
||||
@site = Factory(:site)
|
||||
end
|
||||
|
||||
it 'should destroy pages' do
|
||||
@site.pages.expects(:destroy_all)
|
||||
@site.destroy
|
||||
|
||||
it 'should also destroy pages' do
|
||||
lambda {
|
||||
@site.destroy
|
||||
}.should change(Page, :count).by(-2)
|
||||
end
|
||||
|
||||
it 'should destroy layouts' do
|
||||
@site.layouts.expects(:destroy_all)
|
||||
@site.destroy
|
||||
end
|
||||
|
||||
it 'should destroy snippets' do
|
||||
@site.snippets.expects(:destroy_all)
|
||||
@site.destroy
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
3
vendor/plugins/custom_fields/.rspec
vendored
3
vendor/plugins/custom_fields/.rspec
vendored
@ -1,3 +0,0 @@
|
||||
--colour
|
||||
--format nested
|
||||
--backtrace
|
12
vendor/plugins/custom_fields/Gemfile
vendored
12
vendor/plugins/custom_fields/Gemfile
vendored
@ -1,12 +0,0 @@
|
||||
source 'http://gemcutter.org'
|
||||
|
||||
gem 'bson_ext', '>= 1.0.1'
|
||||
gem 'mongo_ext'
|
||||
gem 'mongoid', '2.0.0.beta.14'
|
||||
gem 'activesupport', '~>3.0.0.beta'
|
||||
gem 'carrierwave-rails3', :require => 'carrierwave'
|
||||
|
||||
group :test do
|
||||
gem 'rspec', '>= 2.0.0.beta.10'
|
||||
gem 'mocha', :git => 'git://github.com/floehopper/mocha.git'
|
||||
end
|
20
vendor/plugins/custom_fields/MIT-LICENSE
vendored
20
vendor/plugins/custom_fields/MIT-LICENSE
vendored
@ -1,20 +0,0 @@
|
||||
Copyright (c) 2010 [name of plugin creator]
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
13
vendor/plugins/custom_fields/README
vendored
13
vendor/plugins/custom_fields/README
vendored
@ -1,13 +0,0 @@
|
||||
CustomFields
|
||||
===========
|
||||
|
||||
Introduction goes here.
|
||||
|
||||
|
||||
Example
|
||||
=======
|
||||
|
||||
Example goes here.
|
||||
|
||||
|
||||
Copyright (c) 2010 [Didier Lafforgue], released under the MIT license
|
29
vendor/plugins/custom_fields/Rakefile
vendored
29
vendor/plugins/custom_fields/Rakefile
vendored
@ -1,29 +0,0 @@
|
||||
require "rubygems"
|
||||
require "rake"
|
||||
require "rake/rdoctask"
|
||||
require "rspec"
|
||||
require "rspec/core/rake_task"
|
||||
|
||||
desc 'Generate documentation for the custom_fields plugin.'
|
||||
Rake::RDocTask.new(:rdoc) do |rdoc|
|
||||
rdoc.rdoc_dir = 'rdoc'
|
||||
rdoc.title = 'CustomFields'
|
||||
rdoc.options << '--line-numbers' << '--inline-source'
|
||||
rdoc.rdoc_files.include('README')
|
||||
rdoc.rdoc_files.include('lib/**/*.rb')
|
||||
end
|
||||
|
||||
Rspec::Core::RakeTask.new('spec:unit') do |spec|
|
||||
spec.pattern = "spec/unit/**/*_spec.rb"
|
||||
# spec.pattern = "spec/unit/custom_fields_for_spec.rb"
|
||||
# spec.pattern = "spec/unit/types/category_spec.rb"
|
||||
end
|
||||
|
||||
Rspec::Core::RakeTask.new('spec:integration') do |spec|
|
||||
spec.pattern = "spec/integration/**/*_spec.rb"
|
||||
# spec.pattern = "spec/integration/types/category_spec.rb"
|
||||
end
|
||||
|
||||
task :spec => ['spec:unit', 'spec:integration']
|
||||
|
||||
task :default => :spec
|
2
vendor/plugins/custom_fields/init.rb
vendored
2
vendor/plugins/custom_fields/init.rb
vendored
@ -1,2 +0,0 @@
|
||||
# Include hook code here
|
||||
require File.dirname(__FILE__) + '/lib/custom_fields'
|
@ -1,28 +0,0 @@
|
||||
$:.unshift File.expand_path(File.dirname(__FILE__))
|
||||
|
||||
require 'active_support'
|
||||
require 'carrierwave/orm/mongoid'
|
||||
|
||||
require 'custom_fields/extensions/mongoid/hierarchy'
|
||||
require 'custom_fields/extensions/mongoid/associations/proxy'
|
||||
require 'custom_fields/extensions/mongoid/associations/references_many'
|
||||
require 'custom_fields/extensions/mongoid/associations/embeds_many'
|
||||
require 'custom_fields/types/default'
|
||||
require 'custom_fields/types/string'
|
||||
require 'custom_fields/types/text'
|
||||
require 'custom_fields/types/category'
|
||||
require 'custom_fields/types/boolean'
|
||||
require 'custom_fields/types/date'
|
||||
require 'custom_fields/types/file'
|
||||
require 'custom_fields/proxy_class_enabler'
|
||||
require 'custom_fields/field'
|
||||
require 'custom_fields/custom_fields_for'
|
||||
|
||||
module Mongoid
|
||||
module CustomFields
|
||||
extend ActiveSupport::Concern
|
||||
included do
|
||||
include ::CustomFields::CustomFieldsFor
|
||||
end
|
||||
end
|
||||
end
|
@ -1,50 +0,0 @@
|
||||
module CustomFields
|
||||
|
||||
module CustomFieldsFor
|
||||
|
||||
def self.included(base)
|
||||
base.extend(ClassMethods)
|
||||
end
|
||||
|
||||
# Enhance an embedded collection by providing methods to manage custom fields
|
||||
#
|
||||
# class Company
|
||||
# embeds_many :employees
|
||||
# custom_fields_for :employees
|
||||
# end
|
||||
#
|
||||
# class Employee
|
||||
# embedded_in :company, :inverse_of => :employees
|
||||
# field :name, String
|
||||
# end
|
||||
#
|
||||
# company.employee_custom_fields.build :label => 'His/her position', :_alias => 'position', :kind => 'String'
|
||||
#
|
||||
# company.employees.build :name => 'Michael Scott', :position => 'Regional manager'
|
||||
#
|
||||
module ClassMethods
|
||||
|
||||
def custom_fields_for(collection_name)
|
||||
singular_name = collection_name.to_s.singularize
|
||||
|
||||
class_eval <<-EOV
|
||||
field :#{singular_name}_custom_fields_counter, :type => Integer, :default => 0
|
||||
|
||||
embeds_many :#{singular_name}_custom_fields, :class_name => "::CustomFields::Field"
|
||||
|
||||
validates_associated :#{singular_name}_custom_fields
|
||||
|
||||
accepts_nested_attributes_for :#{singular_name}_custom_fields, :allow_destroy => true
|
||||
|
||||
def ordered_#{singular_name}_custom_fields
|
||||
self.#{singular_name}_custom_fields.sort { |a, b| (a.position || 0) <=> (b.position || 0) }
|
||||
end
|
||||
|
||||
EOV
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
@ -1,31 +0,0 @@
|
||||
# encoding: utf-8
|
||||
module Mongoid #:nodoc:
|
||||
module Associations #:nodoc:
|
||||
class EmbedsMany < Proxy
|
||||
|
||||
def initialize_with_custom_fields(parent, options, target_array = nil)
|
||||
if custom_fields?(parent, options.name)
|
||||
options = options.clone # 2 parent instances should not share the exact same option instance
|
||||
|
||||
custom_fields = parent.send(:"ordered_#{custom_fields_association_name(options.name)}")
|
||||
|
||||
klass = options.klass.to_klass_with_custom_fields(custom_fields)
|
||||
klass._parent = parent
|
||||
klass.association_name = options.name
|
||||
|
||||
options.instance_eval <<-EOF
|
||||
def klass=(klass); @klass = klass; end
|
||||
def klass; @klass || class_name.constantize; end
|
||||
EOF
|
||||
|
||||
options.klass = klass
|
||||
end
|
||||
|
||||
initialize_without_custom_fields(parent, options, target_array)
|
||||
end
|
||||
|
||||
alias_method_chain :initialize, :custom_fields
|
||||
|
||||
end
|
||||
end
|
||||
end
|
@ -1,20 +0,0 @@
|
||||
# encoding: utf-8
|
||||
module Mongoid #:nodoc
|
||||
module Associations #:nodoc
|
||||
class Proxy #:nodoc
|
||||
|
||||
def custom_fields_association_name(association_name)
|
||||
"#{association_name.to_s.singularize}_custom_fields".to_sym
|
||||
end
|
||||
|
||||
def custom_fields?(object, association_name)
|
||||
object.respond_to?(custom_fields_association_name(association_name))
|
||||
end
|
||||
|
||||
def klass
|
||||
@klass
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
@ -1,33 +0,0 @@
|
||||
# encoding: utf-8
|
||||
module Mongoid #:nodoc:
|
||||
module Associations #:nodoc:
|
||||
# Represents an relational one-to-many association with an object in a
|
||||
# separate collection or database.
|
||||
class ReferencesMany < Proxy
|
||||
|
||||
def initialize_with_custom_fields(parent, options, target_array = nil)
|
||||
if custom_fields?(parent, options.name)
|
||||
options = options.clone # 2 parent instances should not share the exact same option instance
|
||||
|
||||
custom_fields = parent.send(:"ordered_#{custom_fields_association_name(options.name)}")
|
||||
|
||||
klass = options.klass.to_klass_with_custom_fields(custom_fields)
|
||||
klass._parent = parent
|
||||
klass.association_name = options.name
|
||||
|
||||
options.instance_eval <<-EOF
|
||||
def klass=(klass); @klass = klass; end
|
||||
def klass; @klass || class_name.constantize; end
|
||||
EOF
|
||||
|
||||
options.klass = klass
|
||||
end
|
||||
|
||||
initialize_without_custom_fields(parent, options, target_array)
|
||||
end
|
||||
|
||||
alias_method_chain :initialize, :custom_fields
|
||||
|
||||
end
|
||||
end
|
||||
end
|
@ -1,28 +0,0 @@
|
||||
# encoding: utf-8
|
||||
module Mongoid #:nodoc
|
||||
module Hierarchy #:nodoc
|
||||
module InstanceMethods
|
||||
|
||||
def parentize_with_custom_fields(object, association_name)
|
||||
if association_name.to_s.ends_with?('_custom_fields')
|
||||
self.singleton_class.associations = {}
|
||||
self.singleton_class.embedded_in object.class.to_s.underscore.to_sym, :inverse_of => association_name
|
||||
end
|
||||
|
||||
parentize_without_custom_fields(object, association_name)
|
||||
|
||||
if self.embedded? && self.instance_variable_get(:"@association_name").nil?
|
||||
self.instance_variable_set(:"@association_name", association_name) # weird bug with proxy class
|
||||
end
|
||||
|
||||
if association_name.to_s.ends_with?('_custom_fields')
|
||||
self.send(:set_unique_name!)
|
||||
self.send(:set_alias)
|
||||
end
|
||||
end
|
||||
|
||||
alias_method_chain :parentize, :custom_fields
|
||||
|
||||
end
|
||||
end
|
||||
end
|
@ -1,82 +0,0 @@
|
||||
module CustomFields
|
||||
|
||||
class Field
|
||||
include ::Mongoid::Document
|
||||
include ::Mongoid::Timestamps
|
||||
|
||||
# types ##
|
||||
include Types::Default
|
||||
include Types::String
|
||||
include Types::Text
|
||||
include Types::Category
|
||||
include Types::Boolean
|
||||
include Types::Date
|
||||
include Types::File
|
||||
|
||||
## fields ##
|
||||
field :label
|
||||
field :_alias
|
||||
field :_name
|
||||
field :kind
|
||||
field :hint
|
||||
field :position, :type => Integer, :default => 0
|
||||
|
||||
## validations ##
|
||||
validates_presence_of :label, :kind
|
||||
validate :uniqueness_of_label
|
||||
|
||||
## methods ##
|
||||
|
||||
def field_type
|
||||
self.class.field_types[self.kind.downcase.to_sym]
|
||||
end
|
||||
|
||||
def apply(klass)
|
||||
return unless self.valid?
|
||||
|
||||
klass.field self._name, :type => self.field_type if self.field_type
|
||||
|
||||
apply_method_name = :"apply_#{self.kind.downcase}_type"
|
||||
|
||||
if self.respond_to?(apply_method_name)
|
||||
self.send(apply_method_name, klass)
|
||||
else
|
||||
apply_default_type(klass)
|
||||
end
|
||||
end
|
||||
|
||||
def safe_alias
|
||||
self.set_alias
|
||||
self._alias
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def uniqueness_of_label
|
||||
duplicate = self.siblings.detect { |f| f.label == self.label && f._id != self._id }
|
||||
if not duplicate.nil?
|
||||
self.errors.add(:label, :taken)
|
||||
end
|
||||
end
|
||||
|
||||
def set_unique_name!
|
||||
self._name ||= "custom_field_#{self.increment_counter!}"
|
||||
end
|
||||
|
||||
def set_alias
|
||||
return if self.label.blank? && self._alias.blank?
|
||||
self._alias = (self._alias.blank? ? self.label : self._alias).parameterize('_').downcase
|
||||
end
|
||||
|
||||
def increment_counter!
|
||||
next_value = (self._parent.send(:"#{self.association_name}_counter") || 0) + 1
|
||||
self._parent.send(:"#{self.association_name}_counter=", next_value)
|
||||
next_value
|
||||
end
|
||||
|
||||
def siblings
|
||||
self._parent.send(self.association_name)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
@ -1,37 +0,0 @@
|
||||
module CustomFields
|
||||
module ProxyClassEnabler
|
||||
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
|
||||
cattr_accessor :klass_with_custom_fields
|
||||
|
||||
def self.to_klass_with_custom_fields(fields)
|
||||
return klass_with_custom_fields unless klass_with_custom_fields.nil?
|
||||
|
||||
klass = Class.new(self)
|
||||
klass.class_eval <<-EOF
|
||||
cattr_accessor :custom_fields, :_parent, :association_name
|
||||
|
||||
def self.model_name
|
||||
@_model_name ||= ActiveModel::Name.new(self.superclass)
|
||||
end
|
||||
|
||||
def custom_fields
|
||||
self.class.custom_fields
|
||||
end
|
||||
EOF
|
||||
|
||||
klass.hereditary = false
|
||||
klass.custom_fields = fields
|
||||
|
||||
[*fields].each { |field| field.apply(klass) }
|
||||
|
||||
klass_with_custom_fields = klass
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -1,29 +0,0 @@
|
||||
module CustomFields
|
||||
module Types
|
||||
module Boolean
|
||||
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
register_type :boolean
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
|
||||
def apply_boolean_type(klass)
|
||||
|
||||
klass.class_eval <<-EOF
|
||||
alias :#{self.safe_alias}= :#{self._name}=
|
||||
|
||||
def #{self.safe_alias}
|
||||
::Boolean.set(read_attribute(:#{self._name}))
|
||||
end
|
||||
EOF
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
@ -1,85 +0,0 @@
|
||||
module CustomFields
|
||||
module Types
|
||||
module Category
|
||||
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
embeds_many :category_items, :class_name => 'CustomFields::Types::Category::Item'
|
||||
|
||||
validates_associated :category_items
|
||||
|
||||
accepts_nested_attributes_for :category_items, :allow_destroy => true
|
||||
|
||||
register_type :category, ::String
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
|
||||
def ordered_category_items
|
||||
self.category_items.sort { |a, b| (a.position || 0) <=> (b.position || 0) }
|
||||
end
|
||||
|
||||
def category_names
|
||||
self.category_items.collect(&:name)
|
||||
end
|
||||
|
||||
def category_ids
|
||||
self.category_items.collect(&:_id)
|
||||
end
|
||||
|
||||
def apply_category_type(klass)
|
||||
klass.cattr_accessor :"#{self.safe_alias}_items"
|
||||
|
||||
klass.send("#{self.safe_alias}_items=", self.ordered_category_items)
|
||||
|
||||
klass.class_eval <<-EOF
|
||||
def self.#{self.safe_alias}_names
|
||||
self.#{self.safe_alias}_items.collect(&:name)
|
||||
end
|
||||
|
||||
def self.group_by_#{self.safe_alias}(list_method = nil)
|
||||
groups = (if self.embedded?
|
||||
list_method ||= self.association_name
|
||||
self._parent.send(list_method)
|
||||
else
|
||||
list_method ||= :all
|
||||
self.send(list_method)
|
||||
end).to_a.group_by(&:#{self._name})
|
||||
|
||||
self.#{self.safe_alias}_items.collect do |category|
|
||||
{
|
||||
:name => category.name,
|
||||
:items => groups[category._id] || []
|
||||
}.with_indifferent_access
|
||||
end
|
||||
end
|
||||
|
||||
def #{self.safe_alias}=(name)
|
||||
category_id = self.class.#{self.safe_alias}_items.find { |item| item.name == name }._id rescue name
|
||||
write_attribute(:#{self._name}, category_id)
|
||||
end
|
||||
|
||||
def #{self.safe_alias}
|
||||
category_id = read_attribute(:#{self._name})
|
||||
self.class.#{self.safe_alias}_items.find { |item| item._id == category_id }.name rescue category_id
|
||||
end
|
||||
EOF
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Item
|
||||
|
||||
include Mongoid::Document
|
||||
|
||||
field :name
|
||||
field :position, :type => Integer, :default => 0
|
||||
|
||||
embedded_in :custom_field, :inverse_of => :category_items
|
||||
|
||||
validates_presence_of :name
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,35 +0,0 @@
|
||||
module CustomFields
|
||||
module Types
|
||||
module Date
|
||||
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
register_type :date, ::Date
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
|
||||
def apply_date_type(klass)
|
||||
|
||||
klass.class_eval <<-EOF
|
||||
def #{self.safe_alias}
|
||||
self.#{self._name}.strftime(I18n.t('date.formats.default')) rescue nil
|
||||
end
|
||||
|
||||
def #{self.safe_alias}=(value)
|
||||
if value.is_a?(String)
|
||||
date = ::Date._strptime(value, I18n.t('date.formats.default'))
|
||||
value = Date.new(date[:year], date[:mon], date[:mday])
|
||||
end
|
||||
self.#{self._name} = value
|
||||
end
|
||||
EOF
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
@ -1,37 +0,0 @@
|
||||
module CustomFields
|
||||
module Types
|
||||
module Default
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
cattr_accessor :field_types
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
|
||||
def apply_default_type(klass)
|
||||
klass.class_eval <<-EOF
|
||||
alias :#{self.safe_alias} :#{self._name}
|
||||
alias :#{self.safe_alias}= :#{self._name}=
|
||||
EOF
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
|
||||
def register_type(kind, klass = ::String)
|
||||
self.field_types ||= {}
|
||||
self.field_types[kind.to_sym] = klass unless klass.nil?
|
||||
|
||||
self.class_eval <<-EOF
|
||||
def #{kind.to_s}?
|
||||
self.kind.downcase == '#{kind}' rescue false
|
||||
end
|
||||
EOF
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,27 +0,0 @@
|
||||
module CustomFields
|
||||
module Types
|
||||
module File
|
||||
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
register_type :file, nil # do not create the default field
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
|
||||
def apply_file_type(klass)
|
||||
|
||||
klass.mount_uploader self._name, FileUploader
|
||||
|
||||
self.apply_default_type(klass)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class FileUploader < ::CarrierWave::Uploader::Base
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
@ -1,13 +0,0 @@
|
||||
module CustomFields
|
||||
module Types
|
||||
module String
|
||||
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
register_type :string
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
@ -1,15 +0,0 @@
|
||||
module CustomFields
|
||||
module Types
|
||||
module Text
|
||||
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
field :text_formatting, :default => 'html'
|
||||
|
||||
register_type :text
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
@ -1 +0,0 @@
|
||||
Hello world !
|
@ -1,28 +0,0 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe CustomFields::CustomFieldsFor do
|
||||
|
||||
describe 'Saving' do
|
||||
|
||||
before(:each) do
|
||||
@project = Project.new(:name => 'Locomotive')
|
||||
@project.person_custom_fields.build(:label => 'E-mail', :_alias => 'email', :kind => 'String')
|
||||
@project.person_custom_fields.build(:label => 'Age', :_alias => 'age', :kind => 'String')
|
||||
end
|
||||
|
||||
context '@create' do
|
||||
|
||||
it 'persists parent object' do
|
||||
lambda { @project.save }.should change(Project, :count).by(1)
|
||||
end
|
||||
|
||||
it 'persists custom fields' do
|
||||
@project.save && @project.reload
|
||||
@project.person_custom_fields.count.should == 2
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
@ -1,26 +0,0 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe CustomFields::Types::Category do
|
||||
|
||||
before(:each) do
|
||||
@project = Project.new(:name => 'Locomotive')
|
||||
@field = @project.task_custom_fields.build(:label => 'Main category', :_alias => 'main_category', :kind => 'Category')
|
||||
end
|
||||
|
||||
context 'saving category items' do
|
||||
|
||||
before(:each) do
|
||||
@field.category_items.build :name => 'Development'
|
||||
@field.category_items.build :name => 'Design'
|
||||
@field.updated_at = Time.now
|
||||
end
|
||||
|
||||
it 'persists items' do
|
||||
@field.save.should be_true
|
||||
@project.reload
|
||||
@project.task_custom_fields.first.category_items.size.should == 2
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
@ -1,18 +0,0 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe CustomFields::Types::File do
|
||||
|
||||
before(:each) do
|
||||
@project = Project.new(:name => 'Locomotive')
|
||||
@project.task_custom_fields.build(:label => 'Screenshot', :_alias => 'screenshot', :kind => 'File')
|
||||
@project.save
|
||||
@task = @project.tasks.build
|
||||
end
|
||||
|
||||
it 'attaches file' do
|
||||
@task.screenshot = FixturedFile.open('doc.txt')
|
||||
@task.save
|
||||
@task.screenshot.url.should == '/uploads/doc.txt'
|
||||
end
|
||||
|
||||
end
|
@ -1,10 +0,0 @@
|
||||
class Person
|
||||
|
||||
include Mongoid::Document
|
||||
include CustomFields::ProxyClassEnabler
|
||||
|
||||
field :full_name
|
||||
|
||||
embedded_in :project, :inverse_of => :people
|
||||
|
||||
end
|
@ -1,18 +0,0 @@
|
||||
class Project
|
||||
|
||||
include Mongoid::Document
|
||||
include CustomFields::ProxyClassEnabler
|
||||
include CustomFields::CustomFieldsFor
|
||||
|
||||
field :name
|
||||
field :description
|
||||
|
||||
references_many :people
|
||||
embeds_many :tasks
|
||||
|
||||
custom_fields_for :people
|
||||
custom_fields_for :tasks
|
||||
|
||||
scope :ordered, :order_by => [[:name, :asc]]
|
||||
|
||||
end
|
10
vendor/plugins/custom_fields/spec/models/task.rb
vendored
10
vendor/plugins/custom_fields/spec/models/task.rb
vendored
@ -1,10 +0,0 @@
|
||||
class Task
|
||||
|
||||
include Mongoid::Document
|
||||
include CustomFields::ProxyClassEnabler
|
||||
|
||||
field :title
|
||||
|
||||
embedded_in :project, :inverse_of => :tasks
|
||||
|
||||
end
|
27
vendor/plugins/custom_fields/spec/spec_helper.rb
vendored
27
vendor/plugins/custom_fields/spec/spec_helper.rb
vendored
@ -1,27 +0,0 @@
|
||||
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
||||
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
||||
|
||||
MODELS = File.join(File.dirname(__FILE__), 'models')
|
||||
$LOAD_PATH.unshift(MODELS)
|
||||
|
||||
require 'rubygems'
|
||||
require 'bundler'
|
||||
Bundler.setup
|
||||
Bundler.require
|
||||
|
||||
require 'mongoid'
|
||||
require 'mocha'
|
||||
require 'rspec'
|
||||
require 'custom_fields'
|
||||
|
||||
Dir[ File.join(MODELS, "*.rb") ].sort.each { |file| require File.basename(file) }
|
||||
|
||||
require 'support/mongoid'
|
||||
require 'support/carrierwave'
|
||||
|
||||
Rspec.configure do |config|
|
||||
config.mock_with :mocha
|
||||
config.after :suite do
|
||||
Mongoid.master.collections.select { |c| c.name != 'system.indexes' }.each(&:drop)
|
||||
end
|
||||
end
|
@ -1,31 +0,0 @@
|
||||
require 'carrierwave/test/matchers'
|
||||
|
||||
CarrierWave.configure do |config|
|
||||
config.storage = :file
|
||||
config.store_dir = "uploads"
|
||||
config.cache_dir = "cache"
|
||||
config.root = File.join(File.dirname(__FILE__), '..', 'tmp')
|
||||
end
|
||||
|
||||
module FixturedFile
|
||||
def self.open(filename)
|
||||
File.new(self.path(filename))
|
||||
end
|
||||
|
||||
def self.path(filename)
|
||||
File.join(File.dirname(__FILE__), '..', 'fixtures', filename)
|
||||
end
|
||||
|
||||
def self.duplicate(filename)
|
||||
dst = File.join(File.dirname(__FILE__), '..', 'tmp', filename)
|
||||
FileUtils.cp self.path(filename), dst
|
||||
dst
|
||||
end
|
||||
|
||||
def self.reset!
|
||||
FileUtils.rm_rf(File.join(File.dirname(__FILE__), '..', 'tmp'))
|
||||
FileUtils.mkdir(File.join(File.dirname(__FILE__), '..', 'tmp'))
|
||||
end
|
||||
end
|
||||
|
||||
FixturedFile.reset!
|
@ -1,6 +0,0 @@
|
||||
Mongoid.configure do |config|
|
||||
name = "custom_fields_test"
|
||||
host = "localhost"
|
||||
config.master = Mongo::Connection.new.db(name)
|
||||
# config.master = Mongo::Connection.new('localhost', '27017', :logger => Logger.new($stdout)).db(name)
|
||||
end
|
@ -1,42 +0,0 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe CustomFields::Field do
|
||||
|
||||
it 'is initialized' do
|
||||
lambda { CustomFields::Field.new }.should_not raise_error
|
||||
end
|
||||
|
||||
context '#mongoid' do
|
||||
|
||||
before(:each) do
|
||||
@field = CustomFields::Field.new(:label => 'manager', :_name => 'field_1', :kind => 'String', :_alias => 'manager')
|
||||
@field.stubs(:valid?).returns(true)
|
||||
@project = Project.to_klass_with_custom_fields(@field).new
|
||||
end
|
||||
|
||||
it 'is added to the list of mongoid fields' do
|
||||
@project.fields['field_1'].should_not be_nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context 'on target class' do
|
||||
|
||||
before(:each) do
|
||||
@field = CustomFields::Field.new(:label => 'manager', :_name => 'field_1', :kind => 'String', :_alias => 'manager')
|
||||
@field.stubs(:valid?).returns(true)
|
||||
@project = Project.to_klass_with_custom_fields(@field).new
|
||||
end
|
||||
|
||||
it 'has a new field' do
|
||||
@project.respond_to?(:manager).should be_true
|
||||
end
|
||||
|
||||
it 'sets / retrieves a value' do
|
||||
@project.manager = 'Mickael Scott'
|
||||
@project.manager.should == 'Mickael Scott'
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
@ -1,106 +0,0 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe CustomFields::CustomFieldsFor do
|
||||
|
||||
context '#proxy class' do
|
||||
|
||||
before(:each) do
|
||||
@project = Project.new
|
||||
@klass = @project.tasks.klass
|
||||
end
|
||||
|
||||
it 'returns the proxy class in the association' do
|
||||
@klass.should == @project.tasks.build.class
|
||||
end
|
||||
|
||||
it 'has a link to the parent' do
|
||||
@klass._parent.should == @project
|
||||
end
|
||||
|
||||
it 'has the association name which references to' do
|
||||
@klass.association_name.should == 'tasks'
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context 'with embedded collection' do
|
||||
|
||||
context '#association' do
|
||||
|
||||
before(:each) do
|
||||
@project = Project.new
|
||||
end
|
||||
|
||||
it 'has custom fields for embedded collection' do
|
||||
@project.respond_to?(:task_custom_fields).should be_true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context '#building' do
|
||||
|
||||
before(:each) do
|
||||
@project = Project.new
|
||||
@project.task_custom_fields.build :label => 'Short summary', :_alias => 'summary', :kind => 'String'
|
||||
@task = @project.tasks.build
|
||||
end
|
||||
|
||||
it 'returns a new document whose Class is different from the original one' do
|
||||
@task.class.should_not == Task
|
||||
end
|
||||
|
||||
it 'returns a new document with custom field' do
|
||||
@project.tasks.build
|
||||
@project.tasks.build
|
||||
@task.respond_to?(:summary).should be_true
|
||||
end
|
||||
|
||||
it 'sets/gets custom attributes' do
|
||||
@task.summary = 'Lorem ipsum...'
|
||||
@task.summary.should == 'Lorem ipsum...'
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context 'with related collection' do
|
||||
|
||||
context '#association' do
|
||||
|
||||
before(:each) do
|
||||
@project = Project.new
|
||||
end
|
||||
|
||||
it 'has custom fields for related collections' do
|
||||
@project.respond_to?(:person_custom_fields).should be_true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context '#building' do
|
||||
|
||||
before(:each) do
|
||||
@project = Project.new
|
||||
@project.person_custom_fields.build :label => 'Position in the project', :_alias => 'position', :kind => 'String'
|
||||
@person = @project.people.build
|
||||
end
|
||||
|
||||
it 'returns a new document whose Class is different from the original one' do
|
||||
@person.class.should_not == Person
|
||||
end
|
||||
|
||||
it 'returns a new document with custom field' do
|
||||
@person.respond_to?(:position).should be_true
|
||||
end
|
||||
|
||||
it 'sets/gets custom attributes' do
|
||||
@person.position = 'Designer'
|
||||
@person.position.should == 'Designer'
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
@ -1,25 +0,0 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe CustomFields::ProxyClassEnabler do
|
||||
|
||||
context '#proxy klass' do
|
||||
|
||||
before(:each) do
|
||||
@klass = Task.to_klass_with_custom_fields([])
|
||||
end
|
||||
|
||||
it 'does not be flagged as a inherited document' do
|
||||
@klass.new.hereditary?.should be_false
|
||||
end
|
||||
|
||||
it 'has a list of custom fields' do
|
||||
@klass.custom_fields.should == []
|
||||
end
|
||||
|
||||
it 'has the exact same model name than its parent' do
|
||||
@klass.model_name.should == 'Task'
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
@ -1,81 +0,0 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe CustomFields::Types::Boolean do
|
||||
|
||||
context 'on field class' do
|
||||
|
||||
before(:each) do
|
||||
@field = CustomFields::Field.new
|
||||
end
|
||||
|
||||
it 'returns true if it is a Boolean' do
|
||||
@field.kind = 'boolean'
|
||||
@field.boolean?.should be_true
|
||||
end
|
||||
|
||||
it 'returns false if it is not a Boolean' do
|
||||
@field.kind = 'string'
|
||||
@field.boolean?.should be_false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context 'on target class' do
|
||||
|
||||
before(:each) do
|
||||
@project = build_project_with_boolean
|
||||
end
|
||||
|
||||
context '#setting' do
|
||||
|
||||
context '#true' do
|
||||
|
||||
it 'sets value from an integer' do
|
||||
@project.active = 1
|
||||
@project.active.should == true
|
||||
@project.field_1.should == '1'
|
||||
end
|
||||
|
||||
it 'sets value from a string' do
|
||||
@project.active = '1'
|
||||
@project.active.should == true
|
||||
@project.field_1.should == '1'
|
||||
|
||||
@project.active = 'true'
|
||||
@project.active.should == true
|
||||
@project.field_1.should == 'true'
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context '#false' do
|
||||
|
||||
it 'sets value from an integer' do
|
||||
@project.active = 0
|
||||
@project.active.should == false
|
||||
@project.field_1.should == '0'
|
||||
end
|
||||
|
||||
it 'sets value from a string' do
|
||||
@project.active = '0'
|
||||
@project.active.should == false
|
||||
@project.field_1.should == '0'
|
||||
|
||||
@project.active = 'false'
|
||||
@project.active.should == false
|
||||
@project.field_1.should == 'false'
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def build_project_with_boolean
|
||||
field = CustomFields::Field.new(:label => 'Active', :_name => 'field_1', :kind => 'Boolean')
|
||||
field.stubs(:valid?).returns(true)
|
||||
Project.to_klass_with_custom_fields(field).new
|
||||
end
|
||||
|
||||
end
|
@ -1,112 +0,0 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe CustomFields::Types::Category do
|
||||
|
||||
context 'on field class' do
|
||||
|
||||
before(:each) do
|
||||
@field = CustomFields::Field.new
|
||||
end
|
||||
|
||||
it 'has the category items field' do
|
||||
@field.respond_to?(:category_items).should be_true
|
||||
end
|
||||
|
||||
it 'has the apply method used for the target object' do
|
||||
@field.respond_to?(:apply_category_type).should be_true
|
||||
end
|
||||
|
||||
it 'returns true if it is a Category' do
|
||||
@field.kind = 'category'
|
||||
@field.category?.should be_true
|
||||
end
|
||||
|
||||
it 'returns false if it is not a Category' do
|
||||
@field.kind = 'string'
|
||||
@field.category?.should be_false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context 'on target class' do
|
||||
|
||||
before(:each) do
|
||||
@project = build_project_with_category
|
||||
end
|
||||
|
||||
it 'has getter/setter' do
|
||||
@project.respond_to?(:global_category).should be_true
|
||||
@project.respond_to?(:global_category=).should be_true
|
||||
end
|
||||
|
||||
it 'has the values of this category' do
|
||||
@project.class.global_category_names.should == %w{Maintenance Design Development}
|
||||
end
|
||||
|
||||
it 'sets the category from a name' do
|
||||
@project.global_category = 'Design'
|
||||
@project.global_category.should == 'Design'
|
||||
@project.field_1.should == '42'
|
||||
end
|
||||
|
||||
it 'sets the category even it does not exit' do
|
||||
@project.global_category = 'Accounting'
|
||||
@project.global_category.should == 'Accounting'
|
||||
@project.field_1.should == 'Accounting'
|
||||
end
|
||||
|
||||
context 'group by category' do
|
||||
|
||||
before(:each) do
|
||||
seed_projects
|
||||
@groups = @project.class.group_by_global_category
|
||||
end
|
||||
|
||||
it 'is an non empty array' do
|
||||
@groups.class.should == Array
|
||||
@groups.size.should == 3
|
||||
end
|
||||
|
||||
it 'is an array of hash composed of a name' do
|
||||
@groups.collect { |g| g[:name] }.should == %w{Maintenance Design Development}
|
||||
end
|
||||
|
||||
it 'is an array of hash composed of a list of objects' do
|
||||
@groups[0][:items].size.should == 0
|
||||
@groups[1][:items].size.should == 1
|
||||
@groups[2][:items].size.should == 2
|
||||
end
|
||||
|
||||
it 'passes method to retrieve items' do
|
||||
@project.class.expects(:ordered)
|
||||
@project.class.group_by_global_category(:ordered)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def build_project_with_category
|
||||
field = build_category
|
||||
Project.to_klass_with_custom_fields(field).new
|
||||
end
|
||||
|
||||
def build_category
|
||||
field = CustomFields::Field.new(:label => 'global_category', :_name => 'field_1', :kind => 'Category')
|
||||
field.stubs(:valid?).returns(true)
|
||||
field.category_items.build :name => 'Development', :_id => '41', :position => 2
|
||||
field.category_items.build :name => 'Design', :_id => '42', :position => 1
|
||||
field.category_items.build :name => 'Maintenance', :_id => '43', :position => 0
|
||||
field
|
||||
end
|
||||
|
||||
def seed_projects
|
||||
list = [
|
||||
@project.class.new(:name => 'Locomotive CMS', :global_category => '41'),
|
||||
@project.class.new(:name => 'Ruby on Rails', :global_category => '41'),
|
||||
@project.class.new(:name => 'Dribble', :global_category => '42')
|
||||
]
|
||||
@project.class.stubs(:all).returns(list)
|
||||
end
|
||||
|
||||
end
|
@ -1,59 +0,0 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe CustomFields::Types::Date do
|
||||
|
||||
context 'on field class' do
|
||||
|
||||
before(:each) do
|
||||
@field = CustomFields::Field.new
|
||||
end
|
||||
|
||||
it 'returns true if it is a Date' do
|
||||
@field.kind = 'Date'
|
||||
@field.date?.should be_true
|
||||
end
|
||||
|
||||
it 'returns false if it is not a Date' do
|
||||
@field.kind = 'string'
|
||||
@field.date?.should be_false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context 'on target class' do
|
||||
|
||||
before(:each) do
|
||||
@project = build_project_with_date
|
||||
@date = Date.parse('2010-06-29')
|
||||
end
|
||||
|
||||
it 'sets value from a date' do
|
||||
@project.started_at = @date
|
||||
@project.started_at.should == '2010-06-29'
|
||||
@project.field_1.class.should == Date
|
||||
@project.field_1.should == @date
|
||||
end
|
||||
|
||||
it 'sets value from a string' do
|
||||
@project.started_at = '2010-06-29'
|
||||
@project.started_at.class.should == String
|
||||
@project.started_at.should == '2010-06-29'
|
||||
@project.field_1.class.should == Date
|
||||
@project.field_1.should == @date
|
||||
end
|
||||
|
||||
it 'sets nil value' do
|
||||
@project.started_at = nil
|
||||
@project.started_at.should be_nil
|
||||
@project.field_1.should be_nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def build_project_with_date
|
||||
field = CustomFields::Field.new(:label => 'Started at', :_name => 'field_1', :kind => 'Date')
|
||||
field.stubs(:valid?).returns(true)
|
||||
Project.to_klass_with_custom_fields(field).new
|
||||
end
|
||||
|
||||
end
|
@ -1,23 +0,0 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe CustomFields::Types::Date do
|
||||
|
||||
context 'on field class' do
|
||||
|
||||
before(:each) do
|
||||
@field = CustomFields::Field.new
|
||||
end
|
||||
|
||||
it 'returns true if it is a Date' do
|
||||
@field.kind = 'File'
|
||||
@field.file?.should be_true
|
||||
end
|
||||
|
||||
it 'returns false if it is not a Date' do
|
||||
@field.kind = 'string'
|
||||
@field.file?.should be_false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
1
vendor/plugins/custom_fields/uninstall.rb
vendored
1
vendor/plugins/custom_fields/uninstall.rb
vendored
@ -1 +0,0 @@
|
||||
# Uninstall hook code here
|
Loading…
Reference in New Issue
Block a user