fix the tests + finish the integration of Dragonfly + clean code

This commit is contained in:
did 2011-06-20 17:39:59 -07:00
parent 87e7ced3c1
commit f4d9acd282
20 changed files with 346 additions and 252 deletions

View File

@ -31,7 +31,7 @@ class Asset
end
def to_liquid
Locomotive::Liquid::Drops::Asset.new(self)
{ :url => self.source.url }.merge(self.attributes).stringify_keys
end
end

View File

@ -92,7 +92,7 @@ class ThemeAsset
end
def to_liquid
{ :url => self.source.url }.merge(self.attributes)
{ :url => self.source.url }.merge(self.attributes).stringify_keys
end
def self.all_grouped_by_folder(site, include_all = true)

View File

@ -4,18 +4,22 @@ module Locomotive
def self.resize_url(source, resize_string)
file = nil
if source.is_a?(String) # simple string
if source.is_a?(String) || source.is_a?(Hash) # simple string or theme asset
source = source['url'] if source.is_a?(Hash)
if source =~ /^http/
file = self.app.fetch_url(source)
else
file = self.app.fetch_file(File.join('public', source))
end
elsif source.respond_to?(:url) # carrierwave uploader
if source.file.respond_to?(:url)
file = self.app.fetch_url(source.url) # amazon s3, cloud files, ...etc
else
file = self.app.fetch_file(source.path)
end
else
Locomotive.logger.warning "Unable to resize on the fly: #{source.inspect}"
return

View File

@ -66,9 +66,7 @@ module Locomotive
end
def add_middlewares
Rails.application.configure do |config|
config.middleware.use '::Locomotive::Hosting::Bushido::Middleware'
end
Rails.application.config.middleware.use '::Locomotive::Hosting::Bushido::Middleware'
end
# manage domains

View File

@ -18,34 +18,30 @@ module Locomotive
end
def call(env)
if Locomotive.bushido?
status, headers, response = @app.call(env)
status, headers, response = @app.call(env)
content = ""
response.each { |part| content += part }
content = ""
response.each { |part| content += part }
# "claiming" bar + stats ?
content.gsub!(/<\/body>/i, <<-STR
<script type="text/javascript">
var _bushido_app = '#{@bushido_app_name}';
var _bushido_claimed = #{@bushido_claimed.to_s};
var _bushido_metrics_token = '#{@bushido_metrics_token}';
(function() {
var bushido = document.createElement('script'); bushido.type = 'text/javascript'; bushido.async = true;
bushido.src = '#{BUSHIDO_JS_URL}?#{::Bushido::VERSION.gsub('.', '')}';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(bushido, s);
})();
</script>
</body>
STR
)
# "claiming" bar + stats ?
content.gsub!(/<\/body>/i, <<-STR
<script type="text/javascript">
var _bushido_app = '#{@bushido_app_name}';
var _bushido_claimed = #{@bushido_claimed.to_s};
var _bushido_metrics_token = '#{@bushido_metrics_token}';
(function() {
var bushido = document.createElement('script'); bushido.type = 'text/javascript'; bushido.async = true;
bushido.src = '#{BUSHIDO_JS_URL}?#{::Bushido::VERSION.gsub('.', '')}';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(bushido, s);
})();
</script>
</body>
STR
)
headers['content-length'] = bytesize(content).to_s
headers['content-length'] = bytesize(content).to_s
[status, headers, [content]]
else
@app.call(env)
end
[status, headers, [content]]
end
end

View File

@ -42,8 +42,6 @@ module Locomotive
end
def add_other_assets
collection = AssetCollection.find_or_create_internal(site)
Dir[File.join(theme_path, 'public', 'samples', '*')].each do |asset_path|
next if File.directory?(asset_path)
@ -52,7 +50,7 @@ module Locomotive
name = File.basename(asset_path, File.extname(asset_path)).parameterize('_')
collection.assets.create! :name => name, :source => File.open(asset_path)
self.site.assets.create! :name => name, :source => File.open(asset_path)
end
end

View File

@ -43,7 +43,6 @@ module Locomotive
# invalidate the cache of the dynamic classes (custom fields)
site.content_types.all.collect { |c| c.invalidate_content_klass; c.fetch_content_klass }
site.asset_collections.all.collect { |c| c.invalidate_content_klass; c.fetch_content_klass }
end
protected

View File

@ -162,9 +162,9 @@ module Locomotive
def reset!
@site.pages.destroy_all
@site.assets.destroy_all
@site.theme_assets.destroy_all
@site.content_types.destroy_all
@site.asset_collections.destroy_all
end
def get_uploader(site)

View File

@ -8,18 +8,18 @@ module Locomotive
class_inheritable_reader :liquid_attributes
write_inheritable_attribute :liquid_attributes, []
attr_reader :source
delegate :hash, :to => :source
attr_reader :_source
delegate :hash, :to => :_source
def initialize(source)
unless source.nil?
@source = source
@liquid = liquid_attributes.flatten.inject({}) { |h, k| h.update k.to_s => @source.send(k) }
@_source = source
@liquid = liquid_attributes.flatten.inject({}) { |h, k| h.update k.to_s => @_source.send(k) }
end
end
def id
(@source.respond_to?(:id) ? @source.id : nil) || 'new'
(@_source.respond_to?(:id) ? @_source.id : nil) || 'new'
end
def before_method(method)

View File

@ -2,22 +2,22 @@ module Locomotive
module Liquid
module Drops
class Content < Base
delegate :meta_keywords, :meta_description, :to => '@source'
delegate :meta_keywords, :meta_description, :to => '_source'
def _id
@source._id.to_s
self._source._id.to_s
end
def before_method(meth)
return '' if @source.nil?
return '' if self._source.nil?
if not @@forbidden_attributes.include?(meth.to_s)
value = @source.send(meth)
value = self._source.send(meth)
end
end
def highlighted_field_value
@source.highlighted_field_value
self._source.highlighted_field_value
end
end

View File

@ -2,26 +2,26 @@ module Locomotive
module Liquid
module Drops
class Page < Base
delegate :meta_keywords, :meta_description, :to => "@source"
delegate :meta_keywords, :meta_description, :to => "_source"
def title
@source.templatized? ? @context['content_instance'].highlighted_field_value : @source.title
self._source.templatized? ? @context['content_instance'].highlighted_field_value : self._source.title
end
def slug
@source.templatized? ? @source.content_type.slug.singularize : @source.slug
self._source.templatized? ? self._source.content_type.slug.singularize : self._source.slug
end
def children
@children ||= liquify(*@source.children)
@children ||= liquify(*self._source.children)
end
def fullpath
@fullpath ||= @source.fullpath
@fullpath ||= self._source.fullpath
end
def depth
@source.depth
self._source.depth
end
end

View File

@ -6,11 +6,11 @@ module Locomotive
liquid_attributes << :name << :meta_keywords << :meta_description
def index
@index ||= @source.pages.root.first
@index ||= self._source.pages.root.first
end
def pages
@pages ||= @source.pages.to_a.collect(&:to_liquid)
@pages ||= self._source.pages.to_a.collect(&:to_liquid)
end
end

View File

@ -77,16 +77,15 @@ Factory.define :snippet do |s|
end
## Theme assets ##
Factory.define :theme_asset do |a|
## Assets ##
Factory.define :asset do |a|
a.site { Site.where(:subdomain => "acme").first || Factory(:site) }
end
## Asset collections ##
Factory.define :asset_collection do |s|
s.name 'Trip to Chicago'
s.site { Site.where(:subdomain => "acme").first || Factory(:site) }
## Theme assets ##
Factory.define :theme_asset do |a|
a.site { Site.where(:subdomain => "acme").first || Factory(:site) }
end

View File

@ -35,7 +35,7 @@ describe 'Heroku support' do
end
it 'has a nil connection' do
Locomotive.heroku_connection.should be_nil
Locomotive.respond_to?(:heroku_connection).should be_false
end
it 'tells heroku is disabled' do

View File

@ -0,0 +1,64 @@
require 'spec_helper'
describe Locomotive::Liquid::Filters::Resize do
before :each do
@site = Factory.create(:site)
@theme_asset = Factory.create(:theme_asset, :source => FixturedAsset.open('5k.png'), :site => @site)
@theme_asset_path = "/sites/#{@theme_asset.site_id}/theme/images/5k.png"
@asset = Factory.create(:asset, :source => FixturedAsset.open('5k.png'), :site => @site)
@asset_url = @asset.source.url
@asset_path = "/sites/#{@asset.site_id}/assets/#{@asset.id}/5k.png"
@context = Liquid::Context.new( { }, { 'asset_url' => @asset_url, 'theme_asset' => @theme_asset.to_liquid }, { :site => @site })
@app = Locomotive::Dragonfly.app
end
describe '#resize' do
context 'when an asset url string is given' do
before :each do
@template = Liquid::Template.parse('{{ asset_url | resize: "40x30" }}')
end
it 'should return the location of the resized image' do
@template.render(@context).should =~ /media\/.*\/5k.png/
end
it 'should use the path in the public folder to generate a location' do
@template.render(@context).should == @app.fetch_file("public#{@asset_path}").thumb('40x30').url
end
end
context 'when a theme asset is given' do
before :each do
@template = Liquid::Template.parse("{{ theme_asset | resize: '300x400' }}")
end
it 'should return the location of the resized image' do
@template.render(@context).should =~ /media\/.*\/5k.png/
end
it 'should use the path of the theme asset to generate a location' do
@template.render(@context).should == @app.fetch_file("public#{@theme_asset_path}").thumb('300x400').url
end
end
context 'when no resize string is given' do
before :each do
@template = Liquid::Template.parse('{{ asset | resize: }}')
end
it 'should return a liquid error' do
@template.render(@context).should include 'Liquid error: wrong number of arguments'
end
end
end
end

View File

@ -51,7 +51,8 @@ describe 'Locomotive rendering system' do
end
it 'sets the status to 404 not found when no page is found' do
@controller.expects(:not_found_page).returns(@page)
# @controller.expects(:not_found_page).returns(@page)
@page.stubs(:not_found?).returns(true)
@controller.send(:prepare_and_set_response, 'Hello world !')
@controller.status.should == :not_found
end

View File

@ -1,186 +0,0 @@
require 'spec_helper'
describe AssetCollection do
it 'should have a valid factory' do
Factory.build(:asset_collection).should be_valid
end
describe 'custom fields (beta)' do
before(:each) do
Site.any_instance.stubs(:create_default_pages!).returns(true)
site = Factory.build(:site)
Site.stubs(:find).returns(site)
@collection = Factory.build(:asset_collection, :site => site)
@collection.asset_custom_fields.build :label => 'My Description', :_alias => 'description', :kind => 'Text'
@collection.asset_custom_fields.build :label => 'Active', :kind => 'Boolean'
# AssetCollection.logger = Logger.new($stdout)
# AssetCollection.db.connection.instance_variable_set(:@logger, Logger.new($stdout))
end
context 'unit' do
before(:each) do
@field = CustomFields::Field.new(:kind => 'String')
end
it 'should tell if it is a String' do
@field.string?.should be_true
end
it 'should tell if it is a Text' do
@field.kind = 'Text'
@field.text?.should be_true
end
end
context 'validation' do
%w{label kind}.each do |key|
it "should validate presence of #{key}" do
field = @collection.asset_custom_fields.build({ :label => 'Shortcut', :kind => 'String' }.merge(key.to_sym => nil))
field.should_not be_valid
field.errors[key.to_sym].should == ["can't be blank"]
end
end
it 'should not have unique label' do
field = @collection.asset_custom_fields.build :label => 'Active', :kind => 'Boolean'
field.should_not be_valid
field.errors[:label].should == ["is already taken"]
end
it 'should invalidate parent if custom field is not valid' do
field = @collection.asset_custom_fields.build
@collection.should_not be_valid
@collection.asset_custom_fields.last.errors[:label].should == ["can't be blank"]
end
end
context 'define core attributes' do
it 'should have an unique name' do
@collection.asset_custom_fields.first._name.should == "custom_field_1"
@collection.asset_custom_fields.last._name.should == "custom_field_2"
end
it 'should have an unique alias' do
@collection.asset_custom_fields.first.safe_alias.should == "description"
@collection.asset_custom_fields.last.safe_alias.should == "active"
end
end
context 'build and save' do
it 'should build asset' do
asset = @collection.assets.build
lambda {
asset.description
asset.active
asset.custom_fields.size.should == 2
}.should_not raise_error
end
it 'should assign values to newly built asset' do
asset = build_asset(@collection)
asset.description.should == 'Lorem ipsum'
asset.active.should == true
end
it 'should save asset' do
asset = build_asset(@collection)
asset.save and @collection.reload
asset = @collection.assets.first
asset.description.should == 'Lorem ipsum'
asset.active.should == true
end
it 'should not modify assets from another collection' do
asset = build_asset(@collection)
asset.save and @collection.reload
new_collection = AssetCollection.new
lambda { new_collection.assets.build.description }.should raise_error
end
end
context 'modifying fields' do
before(:each) do
@asset = build_asset(@collection).save
end
it 'should add new field' do
@collection.asset_custom_fields.build :label => 'Active at', :name => 'active_at', :kind => 'Date'
@collection.upsert(:validate => false)
@collection.invalidate_asset_klass
@collection.reload
asset = @collection.assets.first
lambda { asset.active_at }.should_not raise_error
end
it 'should remove field' do
@collection.asset_custom_fields.clear
@collection.upsert(:validate => false)
@collection.invalidate_asset_klass
@collection.reload
asset = @collection.assets.first
lambda { asset.active_at }.should raise_error
end
it 'should rename field label' do
@collection.asset_custom_fields.first.label = 'Simple description'
@collection.asset_custom_fields.first._alias = nil
@collection.upsert(:validate => false)
@collection.invalidate_asset_klass
@collection.reload
asset = @collection.assets.first
asset.simple_description.should == 'Lorem ipsum'
end
end
context 'managing from hash' do
it 'adds new field' do
@collection.asset_custom_fields.clear
field = @collection.asset_custom_fields.build :label => 'Title'
@collection.asset_custom_fields_attributes = { 0 => { :id => field.id.to_s, 'label' => 'A title', 'kind' => 'String' }, 1 => { 'label' => 'Tagline', 'kind' => 'String' } }
@collection.asset_custom_fields.size.should == 2
@collection.asset_custom_fields.first.label.should == 'A title'
@collection.asset_custom_fields.last.label.should == 'Tagline'
end
it 'updates/removes fields' do
field = @collection.asset_custom_fields.build :label => 'Title', :kind => 'String'
@collection.save; @collection = AssetCollection.find(@collection.id)
@collection.update_attributes(:asset_custom_fields_attributes => {
'0' => { 'id' => lookup_field_id(0), 'label' => 'My Description', 'kind' => 'Text', '_destroy' => '1' },
'1' => { 'id' => lookup_field_id(1), 'label' => 'Active', 'kind' => 'Boolean', '_destroy' => '1' },
'2' => { 'id' => lookup_field_id(2), 'label' => 'My Title !', 'kind' => 'String' },
'new_record' => { 'label' => 'Published at', 'kind' => 'String' }
})
@collection = AssetCollection.find(@collection.id)
@collection.asset_custom_fields.size.should == 2
@collection.asset_custom_fields.first.label.should == 'My Title !'
end
end
end
def build_asset(collection)
collection.assets.build(:name => 'Asset on steroids', :description => 'Lorem ipsum', :active => true)
end
def lookup_field_id(index)
@collection.asset_custom_fields.all[index].id.to_s
end
end

46
spec/models/asset_spec.rb Normal file
View File

@ -0,0 +1,46 @@
# coding: utf-8
require 'spec_helper'
describe Asset do
describe 'attaching a file' do
before(:each) do
Asset.any_instance.stubs(:site_id).returns('test')
@asset = Factory.build(:asset)
end
it 'should process picture' do
@asset.source = FixturedAsset.open('5k.png')
@asset.source.file.content_type.should_not be_nil
@asset.image?.should be_true
end
it 'should get width and height from the image' do
@asset.source = FixturedAsset.open('5k.png')
@asset.width.should == 32
@asset.height.should == 32
end
end
describe 'vignette' do
before(:each) do
@asset = Factory.build(:asset, :source => FixturedAsset.open('5k.png'))
end
it 'does not resize image smaller than 50x50' do
@asset.vignette_url.should =~ /^\/spec\/.*\/5k.png/
end
it 'has any possible resized versions' do
@asset.stubs(:with).returns(81)
@asset.stubs(:height).returns(81)
@asset.vignette_url.should =~ /^\/media\/.*\/5k.png/
end
end
end

View File

@ -43,16 +43,16 @@ describe ContentType do
content_type.should_not be_valid
content_type.errors[:content_custom_fields].should == ["is too small (minimum element number is 1)"]
end
%w(created_at updated_at).each do |_alias|
it "does not allow #{_alias} as alias" do
it "does not allow #{_alias} as alias" do
content_type = Factory.build(:content_type)
field = content_type.content_custom_fields.build :label => 'anything', :kind => 'String', :_alias => _alias
field.valid?.should be_false
field.errors[:_alias].should == ['is reserved']
field.errors[:_alias].should == ['is reserved']
end
end
end
context '#ordered_contents' do
@ -92,4 +92,180 @@ describe ContentType do
end
describe 'custom fields' do
before(:each) do
site = Factory.build(:site)
Site.stubs(:find).returns(site)
@content_type = Factory.build(:content_type, :site => site, :highlighted_field_name => 'custom_field_1')
@content_type.content_custom_fields.build :label => 'My Description', :_alias => 'description', :kind => 'text'
@content_type.content_custom_fields.build :label => 'Active', :kind => 'boolean'
# ContentType.logger = Logger.new($stdout)
# ContentType.db.connection.instance_variable_set(:@logger, Logger.new($stdout))
end
context 'unit' do
before(:each) do
@field = CustomFields::Field.new(:kind => 'String')
end
it 'should tell if it is a String' do
@field.string?.should be_true
end
it 'should tell if it is a Text' do
@field.kind = 'Text'
@field.text?.should be_true
end
end
context 'validation' do
%w{label kind}.each do |key|
it "should validate presence of #{key}" do
field = @content_type.content_custom_fields.build({ :label => 'Shortcut', :kind => 'String' }.merge(key.to_sym => nil))
field.should_not be_valid
field.errors[key.to_sym].should == ["can't be blank"]
end
end
it 'should not have unique label' do
field = @content_type.content_custom_fields.build :label => 'Active', :kind => 'Boolean'
field.should_not be_valid
field.errors[:label].should == ["is already taken"]
end
it 'should invalidate parent if custom field is not valid' do
field = @content_type.content_custom_fields.build
@content_type.should_not be_valid
@content_type.content_custom_fields.last.errors[:label].should == ["can't be blank"]
end
end
context 'define core attributes' do
it 'should have an unique name' do
@content_type.content_custom_fields.first._name.should == "custom_field_1"
@content_type.content_custom_fields.last._name.should == "custom_field_2"
end
it 'should have an unique alias' do
@content_type.content_custom_fields.first.safe_alias.should == "description"
@content_type.content_custom_fields.last.safe_alias.should == "active"
end
end
context 'build and save' do
it 'should build asset' do
asset = @content_type.contents.build
lambda {
asset.description
asset.active
asset.custom_fields.size.should == 2
}.should_not raise_error
end
it 'should assign values to newly built asset' do
asset = build_content(@content_type)
asset.description.should == 'Lorem ipsum'
asset.active.should == true
end
it 'should save asset' do
asset = build_content(@content_type)
asset.save and @content_type.reload
asset = @content_type.contents.first
asset.description.should == 'Lorem ipsum'
asset.active.should == true
end
it 'should not modify contents from another collection' do
asset = build_content(@content_type)
asset.save and @content_type.reload
new_collection = ContentType.new
lambda { new_collection.contents.build.description }.should raise_error
end
end
context 'modifying fields' do
before(:each) do
@asset = build_content(@content_type).save
end
it 'should add new field' do
@content_type.content_custom_fields.build :label => 'Active at', :name => 'active_at', :kind => 'Date'
@content_type.upsert(:validate => false)
@content_type.invalidate_content_klass
@content_type.reload
asset = @content_type.contents.first
lambda { asset.active_at }.should_not raise_error
end
it 'should remove field' do
@content_type.content_custom_fields.clear
@content_type.upsert(:validate => false)
@content_type.invalidate_content_klass
@content_type.reload
asset = @content_type.contents.first
lambda { asset.active_at }.should raise_error
end
it 'should rename field label' do
@content_type.content_custom_fields.first.label = 'Simple description'
@content_type.content_custom_fields.first._alias = nil
@content_type.upsert(:validate => false)
@content_type.invalidate_content_klass
@content_type.reload
asset = @content_type.contents.first
asset.simple_description.should == 'Lorem ipsum'
end
end
context 'managing from hash' do
it 'adds new field' do
@content_type.content_custom_fields.clear
field = @content_type.content_custom_fields.build :label => 'Title'
@content_type.content_custom_fields_attributes = { 0 => { :id => field.id.to_s, 'label' => 'A title', 'kind' => 'String' }, 1 => { 'label' => 'Tagline', 'kind' => 'String' } }
@content_type.content_custom_fields.size.should == 2
@content_type.content_custom_fields.first.label.should == 'A title'
@content_type.content_custom_fields.last.label.should == 'Tagline'
end
it 'updates/removes fields' do
field = @content_type.content_custom_fields.build :label => 'Title', :kind => 'String'
@content_type.save; @content_type = ContentType.find(@content_type.id)
@content_type.update_attributes(:content_custom_fields_attributes => {
'0' => { 'id' => lookup_field_id(0), 'label' => 'My Description', 'kind' => 'Text', '_destroy' => '1' },
'1' => { 'id' => lookup_field_id(1), 'label' => 'Active', 'kind' => 'Boolean', '_destroy' => '1' },
'2' => { 'id' => lookup_field_id(2), 'label' => 'My Title !', 'kind' => 'String' },
'new_record' => { 'label' => 'Published at', 'kind' => 'String' }
})
@content_type = ContentType.find(@content_type.id)
@content_type.content_custom_fields.size.should == 2
@content_type.content_custom_fields.first.label.should == 'My Title !'
end
end
end
def build_content(content_type)
content_type.contents.build(:name => 'Asset on steroids', :description => 'Lorem ipsum', :active => true)
end
def lookup_field_id(index)
@content_type.content_custom_fields.all[index].id.to_s
end
end

View File

@ -2,7 +2,6 @@ require 'carrierwave/test/matchers'
CarrierWave.configure do |config|
config.storage = :file
# config.store_dir = "spec/tmp/uploads"
config.cache_dir = "spec/tmp/cache"
config.root = File.join(Rails.root, 'spec', 'tmp')
end