diff options
| author | erdgeist <erdgeist@erdgeist.org> | 2026-06-27 22:52:50 +0200 |
|---|---|---|
| committer | erdgeist <erdgeist@erdgeist.org> | 2026-06-27 22:52:50 +0200 |
| commit | 9a19a0494ef51cdac9a78e24d517ca48ba44c453 (patch) | |
| tree | 8eaae12d8047a40e29d3ea7ff3116b5c869e04bd /vendor | |
| parent | 85a01e35274b8d4d4165a7b26bd7986e211246bb (diff) | |
| parent | 1853082fcd8c067390c246f9daa01a9b47387497 (diff) | |
Migration from Rails 2.3.5 to Rails 8.1 successful.
Merging dev branch.
Diffstat (limited to 'vendor')
196 files changed, 0 insertions, 15074 deletions
diff --git a/vendor/plugins/acts_as_list/README b/vendor/plugins/acts_as_list/README deleted file mode 100644 index 36ae318..0000000 --- a/vendor/plugins/acts_as_list/README +++ /dev/null | |||
| @@ -1,23 +0,0 @@ | |||
| 1 | ActsAsList | ||
| 2 | ========== | ||
| 3 | |||
| 4 | This acts_as extension provides the capabilities for sorting and reordering a number of objects in a list. The class that has this specified needs to have a +position+ column defined as an integer on the mapped database table. | ||
| 5 | |||
| 6 | |||
| 7 | Example | ||
| 8 | ======= | ||
| 9 | |||
| 10 | class TodoList < ActiveRecord::Base | ||
| 11 | has_many :todo_items, :order => "position" | ||
| 12 | end | ||
| 13 | |||
| 14 | class TodoItem < ActiveRecord::Base | ||
| 15 | belongs_to :todo_list | ||
| 16 | acts_as_list :scope => :todo_list | ||
| 17 | end | ||
| 18 | |||
| 19 | todo_list.first.move_to_bottom | ||
| 20 | todo_list.last.move_higher | ||
| 21 | |||
| 22 | |||
| 23 | Copyright (c) 2007 David Heinemeier Hansson, released under the MIT license \ No newline at end of file | ||
diff --git a/vendor/plugins/acts_as_list/init.rb b/vendor/plugins/acts_as_list/init.rb deleted file mode 100644 index eb87e87..0000000 --- a/vendor/plugins/acts_as_list/init.rb +++ /dev/null | |||
| @@ -1,3 +0,0 @@ | |||
| 1 | $:.unshift "#{File.dirname(__FILE__)}/lib" | ||
| 2 | require 'active_record/acts/list' | ||
| 3 | ActiveRecord::Base.class_eval { include ActiveRecord::Acts::List } | ||
diff --git a/vendor/plugins/acts_as_list/lib/active_record/acts/list.rb b/vendor/plugins/acts_as_list/lib/active_record/acts/list.rb deleted file mode 100644 index 00d8692..0000000 --- a/vendor/plugins/acts_as_list/lib/active_record/acts/list.rb +++ /dev/null | |||
| @@ -1,256 +0,0 @@ | |||
| 1 | module ActiveRecord | ||
| 2 | module Acts #:nodoc: | ||
| 3 | module List #:nodoc: | ||
| 4 | def self.included(base) | ||
| 5 | base.extend(ClassMethods) | ||
| 6 | end | ||
| 7 | |||
| 8 | # This +acts_as+ extension provides the capabilities for sorting and reordering a number of objects in a list. | ||
| 9 | # The class that has this specified needs to have a +position+ column defined as an integer on | ||
| 10 | # the mapped database table. | ||
| 11 | # | ||
| 12 | # Todo list example: | ||
| 13 | # | ||
| 14 | # class TodoList < ActiveRecord::Base | ||
| 15 | # has_many :todo_items, :order => "position" | ||
| 16 | # end | ||
| 17 | # | ||
| 18 | # class TodoItem < ActiveRecord::Base | ||
| 19 | # belongs_to :todo_list | ||
| 20 | # acts_as_list :scope => :todo_list | ||
| 21 | # end | ||
| 22 | # | ||
| 23 | # todo_list.first.move_to_bottom | ||
| 24 | # todo_list.last.move_higher | ||
| 25 | module ClassMethods | ||
| 26 | # Configuration options are: | ||
| 27 | # | ||
| 28 | # * +column+ - specifies the column name to use for keeping the position integer (default: +position+) | ||
| 29 | # * +scope+ - restricts what is to be considered a list. Given a symbol, it'll attach <tt>_id</tt> | ||
| 30 | # (if it hasn't already been added) and use that as the foreign key restriction. It's also possible | ||
| 31 | # to give it an entire string that is interpolated if you need a tighter scope than just a foreign key. | ||
| 32 | # Example: <tt>acts_as_list :scope => 'todo_list_id = #{todo_list_id} AND completed = 0'</tt> | ||
| 33 | def acts_as_list(options = {}) | ||
| 34 | configuration = { :column => "position", :scope => "1 = 1" } | ||
| 35 | configuration.update(options) if options.is_a?(Hash) | ||
| 36 | |||
| 37 | configuration[:scope] = "#{configuration[:scope]}_id".intern if configuration[:scope].is_a?(Symbol) && configuration[:scope].to_s !~ /_id$/ | ||
| 38 | |||
| 39 | if configuration[:scope].is_a?(Symbol) | ||
| 40 | scope_condition_method = %( | ||
| 41 | def scope_condition | ||
| 42 | if #{configuration[:scope].to_s}.nil? | ||
| 43 | "#{configuration[:scope].to_s} IS NULL" | ||
| 44 | else | ||
| 45 | "#{configuration[:scope].to_s} = \#{#{configuration[:scope].to_s}}" | ||
| 46 | end | ||
| 47 | end | ||
| 48 | ) | ||
| 49 | else | ||
| 50 | scope_condition_method = "def scope_condition() \"#{configuration[:scope]}\" end" | ||
| 51 | end | ||
| 52 | |||
| 53 | class_eval <<-EOV | ||
| 54 | include ActiveRecord::Acts::List::InstanceMethods | ||
| 55 | |||
| 56 | def acts_as_list_class | ||
| 57 | ::#{self.name} | ||
| 58 | end | ||
| 59 | |||
| 60 | def position_column | ||
| 61 | '#{configuration[:column]}' | ||
| 62 | end | ||
| 63 | |||
| 64 | #{scope_condition_method} | ||
| 65 | |||
| 66 | before_destroy :remove_from_list | ||
| 67 | before_create :add_to_list_bottom | ||
| 68 | EOV | ||
| 69 | end | ||
| 70 | end | ||
| 71 | |||
| 72 | # All the methods available to a record that has had <tt>acts_as_list</tt> specified. Each method works | ||
| 73 | # by assuming the object to be the item in the list, so <tt>chapter.move_lower</tt> would move that chapter | ||
| 74 | # lower in the list of all chapters. Likewise, <tt>chapter.first?</tt> would return +true+ if that chapter is | ||
| 75 | # the first in the list of all chapters. | ||
| 76 | module InstanceMethods | ||
| 77 | # Insert the item at the given position (defaults to the top position of 1). | ||
| 78 | def insert_at(position = 1) | ||
| 79 | insert_at_position(position) | ||
| 80 | end | ||
| 81 | |||
| 82 | # Swap positions with the next lower item, if one exists. | ||
| 83 | def move_lower | ||
| 84 | return unless lower_item | ||
| 85 | |||
| 86 | acts_as_list_class.transaction do | ||
| 87 | lower_item.decrement_position | ||
| 88 | increment_position | ||
| 89 | end | ||
| 90 | end | ||
| 91 | |||
| 92 | # Swap positions with the next higher item, if one exists. | ||
| 93 | def move_higher | ||
| 94 | return unless higher_item | ||
| 95 | |||
| 96 | acts_as_list_class.transaction do | ||
| 97 | higher_item.increment_position | ||
| 98 | decrement_position | ||
| 99 | end | ||
| 100 | end | ||
| 101 | |||
| 102 | # Move to the bottom of the list. If the item is already in the list, the items below it have their | ||
| 103 | # position adjusted accordingly. | ||
| 104 | def move_to_bottom | ||
| 105 | return unless in_list? | ||
| 106 | acts_as_list_class.transaction do | ||
| 107 | decrement_positions_on_lower_items | ||
| 108 | assume_bottom_position | ||
| 109 | end | ||
| 110 | end | ||
| 111 | |||
| 112 | # Move to the top of the list. If the item is already in the list, the items above it have their | ||
| 113 | # position adjusted accordingly. | ||
| 114 | def move_to_top | ||
| 115 | return unless in_list? | ||
| 116 | acts_as_list_class.transaction do | ||
| 117 | increment_positions_on_higher_items | ||
| 118 | assume_top_position | ||
| 119 | end | ||
| 120 | end | ||
| 121 | |||
| 122 | # Removes the item from the list. | ||
| 123 | def remove_from_list | ||
| 124 | if in_list? | ||
| 125 | decrement_positions_on_lower_items | ||
| 126 | update_attribute position_column, nil | ||
| 127 | end | ||
| 128 | end | ||
| 129 | |||
| 130 | # Increase the position of this item without adjusting the rest of the list. | ||
| 131 | def increment_position | ||
| 132 | return unless in_list? | ||
| 133 | update_attribute position_column, self.send(position_column).to_i + 1 | ||
| 134 | end | ||
| 135 | |||
| 136 | # Decrease the position of this item without adjusting the rest of the list. | ||
| 137 | def decrement_position | ||
| 138 | return unless in_list? | ||
| 139 | update_attribute position_column, self.send(position_column).to_i - 1 | ||
| 140 | end | ||
| 141 | |||
| 142 | # Return +true+ if this object is the first in the list. | ||
| 143 | def first? | ||
| 144 | return false unless in_list? | ||
| 145 | self.send(position_column) == 1 | ||
| 146 | end | ||
| 147 | |||
| 148 | # Return +true+ if this object is the last in the list. | ||
| 149 | def last? | ||
| 150 | return false unless in_list? | ||
| 151 | self.send(position_column) == bottom_position_in_list | ||
| 152 | end | ||
| 153 | |||
| 154 | # Return the next higher item in the list. | ||
| 155 | def higher_item | ||
| 156 | return nil unless in_list? | ||
| 157 | acts_as_list_class.find(:first, :conditions => | ||
| 158 | "#{scope_condition} AND #{position_column} = #{(send(position_column).to_i - 1).to_s}" | ||
| 159 | ) | ||
| 160 | end | ||
| 161 | |||
| 162 | # Return the next lower item in the list. | ||
| 163 | def lower_item | ||
| 164 | return nil unless in_list? | ||
| 165 | acts_as_list_class.find(:first, :conditions => | ||
| 166 | "#{scope_condition} AND #{position_column} = #{(send(position_column).to_i + 1).to_s}" | ||
| 167 | ) | ||
| 168 | end | ||
| 169 | |||
| 170 | # Test if this record is in a list | ||
| 171 | def in_list? | ||
| 172 | !send(position_column).nil? | ||
| 173 | end | ||
| 174 | |||
| 175 | private | ||
| 176 | def add_to_list_top | ||
| 177 | increment_positions_on_all_items | ||
| 178 | end | ||
| 179 | |||
| 180 | def add_to_list_bottom | ||
| 181 | self[position_column] = bottom_position_in_list.to_i + 1 | ||
| 182 | end | ||
| 183 | |||
| 184 | # Overwrite this method to define the scope of the list changes | ||
| 185 | def scope_condition() "1" end | ||
| 186 | |||
| 187 | # Returns the bottom position number in the list. | ||
| 188 | # bottom_position_in_list # => 2 | ||
| 189 | def bottom_position_in_list(except = nil) | ||
| 190 | item = bottom_item(except) | ||
| 191 | item ? item.send(position_column) : 0 | ||
| 192 | end | ||
| 193 | |||
| 194 | # Returns the bottom item | ||
| 195 | def bottom_item(except = nil) | ||
| 196 | conditions = scope_condition | ||
| 197 | conditions = "#{conditions} AND #{self.class.primary_key} != #{except.id}" if except | ||
| 198 | acts_as_list_class.find(:first, :conditions => conditions, :order => "#{position_column} DESC") | ||
| 199 | end | ||
| 200 | |||
| 201 | # Forces item to assume the bottom position in the list. | ||
| 202 | def assume_bottom_position | ||
| 203 | update_attribute(position_column, bottom_position_in_list(self).to_i + 1) | ||
| 204 | end | ||
| 205 | |||
| 206 | # Forces item to assume the top position in the list. | ||
| 207 | def assume_top_position | ||
| 208 | update_attribute(position_column, 1) | ||
| 209 | end | ||
| 210 | |||
| 211 | # This has the effect of moving all the higher items up one. | ||
| 212 | def decrement_positions_on_higher_items(position) | ||
| 213 | acts_as_list_class.update_all( | ||
| 214 | "#{position_column} = (#{position_column} - 1)", "#{scope_condition} AND #{position_column} <= #{position}" | ||
| 215 | ) | ||
| 216 | end | ||
| 217 | |||
| 218 | # This has the effect of moving all the lower items up one. | ||
| 219 | def decrement_positions_on_lower_items | ||
| 220 | return unless in_list? | ||
| 221 | acts_as_list_class.update_all( | ||
| 222 | "#{position_column} = (#{position_column} - 1)", "#{scope_condition} AND #{position_column} > #{send(position_column).to_i}" | ||
| 223 | ) | ||
| 224 | end | ||
| 225 | |||
| 226 | # This has the effect of moving all the higher items down one. | ||
| 227 | def increment_positions_on_higher_items | ||
| 228 | return unless in_list? | ||
| 229 | acts_as_list_class.update_all( | ||
| 230 | "#{position_column} = (#{position_column} + 1)", "#{scope_condition} AND #{position_column} < #{send(position_column).to_i}" | ||
| 231 | ) | ||
| 232 | end | ||
| 233 | |||
| 234 | # This has the effect of moving all the lower items down one. | ||
| 235 | def increment_positions_on_lower_items(position) | ||
| 236 | acts_as_list_class.update_all( | ||
| 237 | "#{position_column} = (#{position_column} + 1)", "#{scope_condition} AND #{position_column} >= #{position}" | ||
| 238 | ) | ||
| 239 | end | ||
| 240 | |||
| 241 | # Increments position (<tt>position_column</tt>) of all items in the list. | ||
| 242 | def increment_positions_on_all_items | ||
| 243 | acts_as_list_class.update_all( | ||
| 244 | "#{position_column} = (#{position_column} + 1)", "#{scope_condition}" | ||
| 245 | ) | ||
| 246 | end | ||
| 247 | |||
| 248 | def insert_at_position(position) | ||
| 249 | remove_from_list | ||
| 250 | increment_positions_on_lower_items(position) | ||
| 251 | self.update_attribute(position_column, position) | ||
| 252 | end | ||
| 253 | end | ||
| 254 | end | ||
| 255 | end | ||
| 256 | end | ||
diff --git a/vendor/plugins/acts_as_list/test/list_test.rb b/vendor/plugins/acts_as_list/test/list_test.rb deleted file mode 100644 index e89cb8e..0000000 --- a/vendor/plugins/acts_as_list/test/list_test.rb +++ /dev/null | |||
| @@ -1,332 +0,0 @@ | |||
| 1 | require 'test/unit' | ||
| 2 | |||
| 3 | require 'rubygems' | ||
| 4 | gem 'activerecord', '>= 1.15.4.7794' | ||
| 5 | require 'active_record' | ||
| 6 | |||
| 7 | require "#{File.dirname(__FILE__)}/../init" | ||
| 8 | |||
| 9 | ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:") | ||
| 10 | |||
| 11 | def setup_db | ||
| 12 | ActiveRecord::Schema.define(:version => 1) do | ||
| 13 | create_table :mixins do |t| | ||
| 14 | t.column :pos, :integer | ||
| 15 | t.column :parent_id, :integer | ||
| 16 | t.column :created_at, :datetime | ||
| 17 | t.column :updated_at, :datetime | ||
| 18 | end | ||
| 19 | end | ||
| 20 | end | ||
| 21 | |||
| 22 | def teardown_db | ||
| 23 | ActiveRecord::Base.connection.tables.each do |table| | ||
| 24 | ActiveRecord::Base.connection.drop_table(table) | ||
| 25 | end | ||
| 26 | end | ||
| 27 | |||
| 28 | class Mixin < ActiveRecord::Base | ||
| 29 | end | ||
| 30 | |||
| 31 | class ListMixin < Mixin | ||
| 32 | acts_as_list :column => "pos", :scope => :parent | ||
| 33 | |||
| 34 | def self.table_name() "mixins" end | ||
| 35 | end | ||
| 36 | |||
| 37 | class ListMixinSub1 < ListMixin | ||
| 38 | end | ||
| 39 | |||
| 40 | class ListMixinSub2 < ListMixin | ||
| 41 | end | ||
| 42 | |||
| 43 | class ListWithStringScopeMixin < ActiveRecord::Base | ||
| 44 | acts_as_list :column => "pos", :scope => 'parent_id = #{parent_id}' | ||
| 45 | |||
| 46 | def self.table_name() "mixins" end | ||
| 47 | end | ||
| 48 | |||
| 49 | |||
| 50 | class ListTest < Test::Unit::TestCase | ||
| 51 | |||
| 52 | def setup | ||
| 53 | setup_db | ||
| 54 | (1..4).each { |counter| ListMixin.create! :pos => counter, :parent_id => 5 } | ||
| 55 | end | ||
| 56 | |||
| 57 | def teardown | ||
| 58 | teardown_db | ||
| 59 | end | ||
| 60 | |||
| 61 | def test_reordering | ||
| 62 | assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) | ||
| 63 | |||
| 64 | ListMixin.find(2).move_lower | ||
| 65 | assert_equal [1, 3, 2, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) | ||
| 66 | |||
| 67 | ListMixin.find(2).move_higher | ||
| 68 | assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) | ||
| 69 | |||
| 70 | ListMixin.find(1).move_to_bottom | ||
| 71 | assert_equal [2, 3, 4, 1], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) | ||
| 72 | |||
| 73 | ListMixin.find(1).move_to_top | ||
| 74 | assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) | ||
| 75 | |||
| 76 | ListMixin.find(2).move_to_bottom | ||
| 77 | assert_equal [1, 3, 4, 2], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) | ||
| 78 | |||
| 79 | ListMixin.find(4).move_to_top | ||
| 80 | assert_equal [4, 1, 3, 2], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) | ||
| 81 | end | ||
| 82 | |||
| 83 | def test_move_to_bottom_with_next_to_last_item | ||
| 84 | assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) | ||
| 85 | ListMixin.find(3).move_to_bottom | ||
| 86 | assert_equal [1, 2, 4, 3], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) | ||
| 87 | end | ||
| 88 | |||
| 89 | def test_next_prev | ||
| 90 | assert_equal ListMixin.find(2), ListMixin.find(1).lower_item | ||
| 91 | assert_nil ListMixin.find(1).higher_item | ||
| 92 | assert_equal ListMixin.find(3), ListMixin.find(4).higher_item | ||
| 93 | assert_nil ListMixin.find(4).lower_item | ||
| 94 | end | ||
| 95 | |||
| 96 | def test_injection | ||
| 97 | item = ListMixin.new(:parent_id => 1) | ||
| 98 | assert_equal "parent_id = 1", item.scope_condition | ||
| 99 | assert_equal "pos", item.position_column | ||
| 100 | end | ||
| 101 | |||
| 102 | def test_insert | ||
| 103 | new = ListMixin.create(:parent_id => 20) | ||
| 104 | assert_equal 1, new.pos | ||
| 105 | assert new.first? | ||
| 106 | assert new.last? | ||
| 107 | |||
| 108 | new = ListMixin.create(:parent_id => 20) | ||
| 109 | assert_equal 2, new.pos | ||
| 110 | assert !new.first? | ||
| 111 | assert new.last? | ||
| 112 | |||
| 113 | new = ListMixin.create(:parent_id => 20) | ||
| 114 | assert_equal 3, new.pos | ||
| 115 | assert !new.first? | ||
| 116 | assert new.last? | ||
| 117 | |||
| 118 | new = ListMixin.create(:parent_id => 0) | ||
| 119 | assert_equal 1, new.pos | ||
| 120 | assert new.first? | ||
| 121 | assert new.last? | ||
| 122 | end | ||
| 123 | |||
| 124 | def test_insert_at | ||
| 125 | new = ListMixin.create(:parent_id => 20) | ||
| 126 | assert_equal 1, new.pos | ||
| 127 | |||
| 128 | new = ListMixin.create(:parent_id => 20) | ||
| 129 | assert_equal 2, new.pos | ||
| 130 | |||
| 131 | new = ListMixin.create(:parent_id => 20) | ||
| 132 | assert_equal 3, new.pos | ||
| 133 | |||
| 134 | new4 = ListMixin.create(:parent_id => 20) | ||
| 135 | assert_equal 4, new4.pos | ||
| 136 | |||
| 137 | new4.insert_at(3) | ||
| 138 | assert_equal 3, new4.pos | ||
| 139 | |||
| 140 | new.reload | ||
| 141 | assert_equal 4, new.pos | ||
| 142 | |||
| 143 | new.insert_at(2) | ||
| 144 | assert_equal 2, new.pos | ||
| 145 | |||
| 146 | new4.reload | ||
| 147 | assert_equal 4, new4.pos | ||
| 148 | |||
| 149 | new5 = ListMixin.create(:parent_id => 20) | ||
| 150 | assert_equal 5, new5.pos | ||
| 151 | |||
| 152 | new5.insert_at(1) | ||
| 153 | assert_equal 1, new5.pos | ||
| 154 | |||
| 155 | new4.reload | ||
| 156 | assert_equal 5, new4.pos | ||
| 157 | end | ||
| 158 | |||
| 159 | def test_delete_middle | ||
| 160 | assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) | ||
| 161 | |||
| 162 | ListMixin.find(2).destroy | ||
| 163 | |||
| 164 | assert_equal [1, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) | ||
| 165 | |||
| 166 | assert_equal 1, ListMixin.find(1).pos | ||
| 167 | assert_equal 2, ListMixin.find(3).pos | ||
| 168 | assert_equal 3, ListMixin.find(4).pos | ||
| 169 | |||
| 170 | ListMixin.find(1).destroy | ||
| 171 | |||
| 172 | assert_equal [3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) | ||
| 173 | |||
| 174 | assert_equal 1, ListMixin.find(3).pos | ||
| 175 | assert_equal 2, ListMixin.find(4).pos | ||
| 176 | end | ||
| 177 | |||
| 178 | def test_with_string_based_scope | ||
| 179 | new = ListWithStringScopeMixin.create(:parent_id => 500) | ||
| 180 | assert_equal 1, new.pos | ||
| 181 | assert new.first? | ||
| 182 | assert new.last? | ||
| 183 | end | ||
| 184 | |||
| 185 | def test_nil_scope | ||
| 186 | new1, new2, new3 = ListMixin.create, ListMixin.create, ListMixin.create | ||
| 187 | new2.move_higher | ||
| 188 | assert_equal [new2, new1, new3], ListMixin.find(:all, :conditions => 'parent_id IS NULL', :order => 'pos') | ||
| 189 | end | ||
| 190 | |||
| 191 | |||
| 192 | def test_remove_from_list_should_then_fail_in_list? | ||
| 193 | assert_equal true, ListMixin.find(1).in_list? | ||
| 194 | ListMixin.find(1).remove_from_list | ||
| 195 | assert_equal false, ListMixin.find(1).in_list? | ||
| 196 | end | ||
| 197 | |||
| 198 | def test_remove_from_list_should_set_position_to_nil | ||
| 199 | assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) | ||
| 200 | |||
| 201 | ListMixin.find(2).remove_from_list | ||
| 202 | |||
| 203 | assert_equal [2, 1, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) | ||
| 204 | |||
| 205 | assert_equal 1, ListMixin.find(1).pos | ||
| 206 | assert_equal nil, ListMixin.find(2).pos | ||
| 207 | assert_equal 2, ListMixin.find(3).pos | ||
| 208 | assert_equal 3, ListMixin.find(4).pos | ||
| 209 | end | ||
| 210 | |||
| 211 | def test_remove_before_destroy_does_not_shift_lower_items_twice | ||
| 212 | assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) | ||
| 213 | |||
| 214 | ListMixin.find(2).remove_from_list | ||
| 215 | ListMixin.find(2).destroy | ||
| 216 | |||
| 217 | assert_equal [1, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) | ||
| 218 | |||
| 219 | assert_equal 1, ListMixin.find(1).pos | ||
| 220 | assert_equal 2, ListMixin.find(3).pos | ||
| 221 | assert_equal 3, ListMixin.find(4).pos | ||
| 222 | end | ||
| 223 | |||
| 224 | end | ||
| 225 | |||
| 226 | class ListSubTest < Test::Unit::TestCase | ||
| 227 | |||
| 228 | def setup | ||
| 229 | setup_db | ||
| 230 | (1..4).each { |i| ((i % 2 == 1) ? ListMixinSub1 : ListMixinSub2).create! :pos => i, :parent_id => 5000 } | ||
| 231 | end | ||
| 232 | |||
| 233 | def teardown | ||
| 234 | teardown_db | ||
| 235 | end | ||
| 236 | |||
| 237 | def test_reordering | ||
| 238 | assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id) | ||
| 239 | |||
| 240 | ListMixin.find(2).move_lower | ||
| 241 | assert_equal [1, 3, 2, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id) | ||
| 242 | |||
| 243 | ListMixin.find(2).move_higher | ||
| 244 | assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id) | ||
| 245 | |||
| 246 | ListMixin.find(1).move_to_bottom | ||
| 247 | assert_equal [2, 3, 4, 1], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id) | ||
| 248 | |||
| 249 | ListMixin.find(1).move_to_top | ||
| 250 | assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id) | ||
| 251 | |||
| 252 | ListMixin.find(2).move_to_bottom | ||
| 253 | assert_equal [1, 3, 4, 2], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id) | ||
| 254 | |||
| 255 | ListMixin.find(4).move_to_top | ||
| 256 | assert_equal [4, 1, 3, 2], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id) | ||
| 257 | end | ||
| 258 | |||
| 259 | def test_move_to_bottom_with_next_to_last_item | ||
| 260 | assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id) | ||
| 261 | ListMixin.find(3).move_to_bottom | ||
| 262 | assert_equal [1, 2, 4, 3], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id) | ||
| 263 | end | ||
| 264 | |||
| 265 | def test_next_prev | ||
| 266 | assert_equal ListMixin.find(2), ListMixin.find(1).lower_item | ||
| 267 | assert_nil ListMixin.find(1).higher_item | ||
| 268 | assert_equal ListMixin.find(3), ListMixin.find(4).higher_item | ||
| 269 | assert_nil ListMixin.find(4).lower_item | ||
| 270 | end | ||
| 271 | |||
| 272 | def test_injection | ||
| 273 | item = ListMixin.new("parent_id"=>1) | ||
| 274 | assert_equal "parent_id = 1", item.scope_condition | ||
| 275 | assert_equal "pos", item.position_column | ||
| 276 | end | ||
| 277 | |||
| 278 | def test_insert_at | ||
| 279 | new = ListMixin.create("parent_id" => 20) | ||
| 280 | assert_equal 1, new.pos | ||
| 281 | |||
| 282 | new = ListMixinSub1.create("parent_id" => 20) | ||
| 283 | assert_equal 2, new.pos | ||
| 284 | |||
| 285 | new = ListMixinSub2.create("parent_id" => 20) | ||
| 286 | assert_equal 3, new.pos | ||
| 287 | |||
| 288 | new4 = ListMixin.create("parent_id" => 20) | ||
| 289 | assert_equal 4, new4.pos | ||
| 290 | |||
| 291 | new4.insert_at(3) | ||
| 292 | assert_equal 3, new4.pos | ||
| 293 | |||
| 294 | new.reload | ||
| 295 | assert_equal 4, new.pos | ||
| 296 | |||
| 297 | new.insert_at(2) | ||
| 298 | assert_equal 2, new.pos | ||
| 299 | |||
| 300 | new4.reload | ||
| 301 | assert_equal 4, new4.pos | ||
| 302 | |||
| 303 | new5 = ListMixinSub1.create("parent_id" => 20) | ||
| 304 | assert_equal 5, new5.pos | ||
| 305 | |||
| 306 | new5.insert_at(1) | ||
| 307 | assert_equal 1, new5.pos | ||
| 308 | |||
| 309 | new4.reload | ||
| 310 | assert_equal 5, new4.pos | ||
| 311 | end | ||
| 312 | |||
| 313 | def test_delete_middle | ||
| 314 | assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id) | ||
| 315 | |||
| 316 | ListMixin.find(2).destroy | ||
| 317 | |||
| 318 | assert_equal [1, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id) | ||
| 319 | |||
| 320 | assert_equal 1, ListMixin.find(1).pos | ||
| 321 | assert_equal 2, ListMixin.find(3).pos | ||
| 322 | assert_equal 3, ListMixin.find(4).pos | ||
| 323 | |||
| 324 | ListMixin.find(1).destroy | ||
| 325 | |||
| 326 | assert_equal [3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id) | ||
| 327 | |||
| 328 | assert_equal 1, ListMixin.find(3).pos | ||
| 329 | assert_equal 2, ListMixin.find(4).pos | ||
| 330 | end | ||
| 331 | |||
| 332 | end | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/CHANGELOG b/vendor/plugins/acts_as_taggable_on_steroids/CHANGELOG deleted file mode 100644 index 5391c15..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/CHANGELOG +++ /dev/null | |||
| @@ -1,212 +0,0 @@ | |||
| 1 | [11 Jun 09] | ||
| 2 | |||
| 3 | * Remove deprecated TagCountsExtension. | ||
| 4 | |||
| 5 | * Update tests to use foxy fixtures [Jonas Wagner] | ||
| 6 | |||
| 7 | * Allow hash conditions to be passed to Tag.counts [Jonas Wagner] | ||
| 8 | |||
| 9 | [3 Jun 09] | ||
| 10 | |||
| 11 | * Upgrade tests for Rails 2.3 | ||
| 12 | |||
| 13 | [18 Mar 09] | ||
| 14 | |||
| 15 | * Change callbacks used to save tags. | ||
| 16 | |||
| 17 | [18 Feb 09] | ||
| 18 | |||
| 19 | * Greatly improve speed when using find_tagged_with and :match_all [notonthehighstreet.com]. | ||
| 20 | |||
| 21 | [17 Sep 08] | ||
| 22 | |||
| 23 | * Sanitize scope conditions in find_options_for_tag_counts [Rémy-Christophe Schermesser] | ||
| 24 | |||
| 25 | [23 Aug 08] | ||
| 26 | |||
| 27 | * Fix tag_counts instance method when no tags are present. | ||
| 28 | |||
| 29 | * Make tag_counts instance_method merge any :conditions passed to it. | ||
| 30 | |||
| 31 | [30 Mar 08] | ||
| 32 | |||
| 33 | * Make TagList.from accept array arguments. | ||
| 34 | |||
| 35 | [29 Mar 08] | ||
| 36 | |||
| 37 | * Improve parsing of quotes inside tags [Arturas Slajus]. | ||
| 38 | |||
| 39 | * Add Tag.counts method. | ||
| 40 | |||
| 41 | [28 Mar 08] | ||
| 42 | |||
| 43 | * Make Tag#taggings :dependent => :destroy. | ||
| 44 | |||
| 45 | [27 Mar 08] | ||
| 46 | |||
| 47 | * Fix documentation for tag_counts. | ||
| 48 | |||
| 49 | [18 Mar 08] | ||
| 50 | |||
| 51 | * Add TagList#toggle [Pete Yandell]. | ||
| 52 | |||
| 53 | # Add find_related_tags method [Austin Foncaier]. | ||
| 54 | |||
| 55 | [30 Jan 08] | ||
| 56 | |||
| 57 | * Fix Tag.destroy_unused on Rails 2.0. | ||
| 58 | |||
| 59 | [23 October 2007] | ||
| 60 | |||
| 61 | * Make find_options_for_tag_counts and find_options_for_tagged_with dup their options. | ||
| 62 | |||
| 63 | * Apply conditions properly in find_options_for_tag_counts. | ||
| 64 | |||
| 65 | * Fix tag_cloud when no tags are present. | ||
| 66 | |||
| 67 | [22 October 2007] | ||
| 68 | |||
| 69 | * Fix find_tagged_with using :match_all and :include. | ||
| 70 | |||
| 71 | * Use inner joins instead of left outer joins. | ||
| 72 | |||
| 73 | [15 October 2007] | ||
| 74 | |||
| 75 | * Make find_tagged_with correctly apply :conditions | ||
| 76 | |||
| 77 | * Add Tag.destroy_unused option. | ||
| 78 | |||
| 79 | [11 October 2007] | ||
| 80 | |||
| 81 | * Make tag_counts work correctly with STI. | ||
| 82 | |||
| 83 | [3 October 2007] | ||
| 84 | |||
| 85 | * Improve documentation. | ||
| 86 | |||
| 87 | * Fix TagsHelper and test. | ||
| 88 | |||
| 89 | [2 October 2007] | ||
| 90 | |||
| 91 | * Remove TagList.parse, use TagList.from instead. | ||
| 92 | |||
| 93 | * Add :parse option to TagList#new, TagList#add, and TagList#remove. | ||
| 94 | |||
| 95 | tag_list = TagList.new("One, Two", :parse => true) # ["One", "Two"] | ||
| 96 | |||
| 97 | tag_list # ["One", "Two"] | ||
| 98 | tag_list.add("Three, Four", :parse => true) # ["One", "Two", "Three", "Four"] | ||
| 99 | |||
| 100 | * Remove TagList#names. | ||
| 101 | |||
| 102 | [29 September 2007] | ||
| 103 | |||
| 104 | * Add TagsHelper to assist with generating tag clouds and provide a simple example. | ||
| 105 | |||
| 106 | [27 September 2007] | ||
| 107 | |||
| 108 | * Add #tag_counts method to get tag counts for a specific object's tags. | ||
| 109 | |||
| 110 | * BACKWARDS INCOMPATIBILITY: Rename #find_options_for_tagged_with to #find_options_for_find_tagged_with | ||
| 111 | |||
| 112 | [17 September 2007] | ||
| 113 | |||
| 114 | * Fix clearing of cached tag list when all tags removed. | ||
| 115 | |||
| 116 | [12 September 2007] | ||
| 117 | |||
| 118 | * Make the TagList class inherit from Array. | ||
| 119 | |||
| 120 | * Deprecate obsolete TagList#names. | ||
| 121 | |||
| 122 | [6 September 2007] | ||
| 123 | |||
| 124 | * Add TagList#include? and TagList#empty? | ||
| 125 | |||
| 126 | [26 August 2007] | ||
| 127 | |||
| 128 | * Remove deprecated Tag.delimiter. Use TagList.delimiter instead. | ||
| 129 | |||
| 130 | [25 August 2007] | ||
| 131 | |||
| 132 | * Make tag_counts work with has_many :through | ||
| 133 | |||
| 134 | [23 August 2007] | ||
| 135 | |||
| 136 | * Make search comparisons case-insensitive across different databases. [Moisés Machado] | ||
| 137 | |||
| 138 | * Improve compatiblity with STI. [Moisés Machado] | ||
| 139 | |||
| 140 | [25 July 2007] | ||
| 141 | |||
| 142 | * Respect custom table names for the Tag and Tagging classes. | ||
| 143 | |||
| 144 | * Fix the :exclude option for find_tagged_with | ||
| 145 | |||
| 146 | [17 July 2007] | ||
| 147 | |||
| 148 | * Make the migration work on edge rails | ||
| 149 | |||
| 150 | [8 July 2007] | ||
| 151 | |||
| 152 | * find_options_for_tagged_with should not alter its arguments | ||
| 153 | |||
| 154 | [1 July 2007] | ||
| 155 | |||
| 156 | * Fix incorrect tagging when the case of the tag list is changed. | ||
| 157 | |||
| 158 | * Fix deprecated Tag.delimiter accessor. | ||
| 159 | |||
| 160 | [23 June 2007] | ||
| 161 | |||
| 162 | * Add validation to Tag model. | ||
| 163 | |||
| 164 | * find_options_for_tagged_with should always return a hash. | ||
| 165 | |||
| 166 | * find_tagged_with passing in no tags should return an empty array. | ||
| 167 | |||
| 168 | * Improve compatibility with PostgreSQL. | ||
| 169 | |||
| 170 | [21 June 2007] | ||
| 171 | |||
| 172 | * Remove extra .rb from generated migration file name. | ||
| 173 | |||
| 174 | [15 June 2007] | ||
| 175 | |||
| 176 | * Introduce TagList class. | ||
| 177 | |||
| 178 | * Various cleanups and improvements. | ||
| 179 | |||
| 180 | * Use TagList.delimiter now, not Tag.delimiter. Tag.delimiter will be removed at some stage. | ||
| 181 | |||
| 182 | [11 June 2007] | ||
| 183 | |||
| 184 | * Restructure the creation of the options for find_tagged_with [Thijs Cadier] | ||
| 185 | |||
| 186 | * Add an example migration with a generator. | ||
| 187 | |||
| 188 | * Add caching. | ||
| 189 | |||
| 190 | * Fix compatibility with Ruby < 1.8.6 | ||
| 191 | |||
| 192 | [23 April 2007] | ||
| 193 | |||
| 194 | * Make tag_list to respect Tag.delimiter | ||
| 195 | |||
| 196 | [31 March 2007] | ||
| 197 | |||
| 198 | * Add Tag.delimiter accessor to change how tags are parsed. | ||
| 199 | |||
| 200 | * Fix :include => :tags when used with find_tagged_with | ||
| 201 | |||
| 202 | [7 March 2007] | ||
| 203 | |||
| 204 | * Fix tag_counts for SQLServer [Brad Young] | ||
| 205 | |||
| 206 | [21 Feb 2007] | ||
| 207 | |||
| 208 | * Use scoping instead of TagCountsExtension [Michael Schuerig] | ||
| 209 | |||
| 210 | [7 Jan 2007] | ||
| 211 | |||
| 212 | * Add :match_all to find_tagged_with [Michael Sheakoski] | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/MIT-LICENSE b/vendor/plugins/acts_as_taggable_on_steroids/MIT-LICENSE deleted file mode 100644 index 602bda2..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/MIT-LICENSE +++ /dev/null | |||
| @@ -1,20 +0,0 @@ | |||
| 1 | Copyright (c) 2006 Jonathan Viney | ||
| 2 | |||
| 3 | Permission is hereby granted, free of charge, to any person obtaining | ||
| 4 | a copy of this software and associated documentation files (the | ||
| 5 | "Software"), to deal in the Software without restriction, including | ||
| 6 | without limitation the rights to use, copy, modify, merge, publish, | ||
| 7 | distribute, sublicense, and/or sell copies of the Software, and to | ||
| 8 | permit persons to whom the Software is furnished to do so, subject to | ||
| 9 | the following conditions: | ||
| 10 | |||
| 11 | The above copyright notice and this permission notice shall be | ||
| 12 | included in all copies or substantial portions of the Software. | ||
| 13 | |||
| 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
| 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
| 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
| 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
| 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
| 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
| 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/README b/vendor/plugins/acts_as_taggable_on_steroids/README deleted file mode 100644 index b794030..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/README +++ /dev/null | |||
| @@ -1,151 +0,0 @@ | |||
| 1 | = acts_as_taggable_on_steroids | ||
| 2 | |||
| 3 | If you find this plugin useful, please consider a donation to show your support! | ||
| 4 | |||
| 5 | http://www.paypal.com/cgi-bin/webscr?cmd=_send-money | ||
| 6 | |||
| 7 | Email address: jonathan.viney@gmail.com | ||
| 8 | |||
| 9 | == Instructions | ||
| 10 | |||
| 11 | This plugin is based on acts_as_taggable by DHH but includes extras | ||
| 12 | such as tests, smarter tag assignment, and tag cloud calculations. | ||
| 13 | |||
| 14 | == Installation | ||
| 15 | |||
| 16 | ruby script/plugin install git://github.com/jviney/acts_as_taggable_on_steroids.git | ||
| 17 | |||
| 18 | == Usage | ||
| 19 | |||
| 20 | === Prepare database | ||
| 21 | |||
| 22 | Generate and apply the migration: | ||
| 23 | |||
| 24 | ruby script/generate acts_as_taggable_migration | ||
| 25 | rake db:migrate | ||
| 26 | |||
| 27 | === Basic tagging | ||
| 28 | |||
| 29 | Let's suppose users have many posts and we want those posts to have tags. | ||
| 30 | The first step is to add +acts_as_taggable+ to the Post class: | ||
| 31 | |||
| 32 | class Post < ActiveRecord::Base | ||
| 33 | acts_as_taggable | ||
| 34 | |||
| 35 | belongs_to :user | ||
| 36 | end | ||
| 37 | |||
| 38 | We can now use the tagging methods provided by acts_as_taggable, <tt>#tag_list</tt> and <tt>#tag_list=</tt>. Both these | ||
| 39 | methods work like regular attribute accessors. | ||
| 40 | |||
| 41 | p = Post.find(:first) | ||
| 42 | p.tag_list # [] | ||
| 43 | p.tag_list = "Funny, Silly" | ||
| 44 | p.save | ||
| 45 | p.tag_list # ["Funny", "Silly"] | ||
| 46 | |||
| 47 | You can also add or remove arrays of tags. | ||
| 48 | |||
| 49 | p.tag_list.add("Great", "Awful") | ||
| 50 | p.tag_list.remove("Funny") | ||
| 51 | |||
| 52 | In your views you should use something like the following: | ||
| 53 | |||
| 54 | <%= f.label :tag_list %> | ||
| 55 | <%= f.text_field :tag_list, :size => 80 %> | ||
| 56 | |||
| 57 | === Finding tagged objects | ||
| 58 | |||
| 59 | To retrieve objects tagged with a certain tag, use find_tagged_with. | ||
| 60 | |||
| 61 | Post.find_tagged_with('Funny, Silly') | ||
| 62 | |||
| 63 | By default, find_tagged_with will find objects that have any of the given tags. To | ||
| 64 | find only objects that are tagged with all the given tags, use match_all. | ||
| 65 | |||
| 66 | Post.find_tagged_with('Funny, Silly', :match_all => true) | ||
| 67 | |||
| 68 | See <tt>ActiveRecord::Acts::Taggable::InstanceMethods</tt> for more methods and options. | ||
| 69 | |||
| 70 | === Tag cloud calculations | ||
| 71 | |||
| 72 | To construct tag clouds, the frequency of each tag needs to be calculated. | ||
| 73 | Because we specified +acts_as_taggable+ on the <tt>Post</tt> class, we can | ||
| 74 | get a calculation of all the tag counts by using <tt>Post.tag_counts</tt>. But what if we wanted a tag count for | ||
| 75 | an single user's posts? To achieve this we call tag_counts on the association: | ||
| 76 | |||
| 77 | User.find(:first).posts.tag_counts | ||
| 78 | |||
| 79 | A helper is included to assist with generating tag clouds. Include it in your helper file: | ||
| 80 | |||
| 81 | module ApplicationHelper | ||
| 82 | include TagsHelper | ||
| 83 | end | ||
| 84 | |||
| 85 | You can also use the <tt>counts</tt> method on <tt>Tag</tt> to get the counts for all tags in the database. | ||
| 86 | |||
| 87 | Tag.counts | ||
| 88 | |||
| 89 | Here is an example that generates a tag cloud. | ||
| 90 | |||
| 91 | Controller: | ||
| 92 | |||
| 93 | class PostController < ApplicationController | ||
| 94 | def tag_cloud | ||
| 95 | @tags = Post.tag_counts | ||
| 96 | end | ||
| 97 | end | ||
| 98 | |||
| 99 | View: | ||
| 100 | <% tag_cloud @tags, %w(css1 css2 css3 css4) do |tag, css_class| %> | ||
| 101 | <%= link_to tag.name, { :action => :tag, :id => tag.name }, :class => css_class %> | ||
| 102 | <% end %> | ||
| 103 | |||
| 104 | CSS: | ||
| 105 | |||
| 106 | .css1 { font-size: 1.0em; } | ||
| 107 | .css2 { font-size: 1.2em; } | ||
| 108 | .css3 { font-size: 1.4em; } | ||
| 109 | .css4 { font-size: 1.6em; } | ||
| 110 | |||
| 111 | === Caching | ||
| 112 | |||
| 113 | It is useful to cache the list of tags to reduce the number of queries executed. To do this, | ||
| 114 | add a column named <tt>cached_tag_list</tt> to the model which is being tagged. The column should be long enough to hold | ||
| 115 | the full tag list and must have a default value of null, not an empty string. | ||
| 116 | |||
| 117 | class CachePostTagList < ActiveRecord::Migration | ||
| 118 | def self.up | ||
| 119 | add_column :posts, :cached_tag_list, :string | ||
| 120 | end | ||
| 121 | end | ||
| 122 | |||
| 123 | class Post < ActiveRecord::Base | ||
| 124 | acts_as_taggable | ||
| 125 | |||
| 126 | # The caching column defaults to cached_tag_list, but can be changed: | ||
| 127 | # | ||
| 128 | # set_cached_tag_list_column_name "my_caching_column_name" | ||
| 129 | end | ||
| 130 | |||
| 131 | The details of the caching are handled for you. Just continue to use the tag_list accessor as you normally would. | ||
| 132 | Note that the cached tag list will not be updated if you directly create Tagging objects or manually append to the | ||
| 133 | <tt>tags</tt> or <tt>taggings</tt> associations. To update the cached tag list you should call <tt>save_cached_tag_list</tt> manually. | ||
| 134 | |||
| 135 | === Delimiter | ||
| 136 | |||
| 137 | If you want to change the delimiter used to parse and present tags, set TagList.delimiter. | ||
| 138 | For example, to use spaces instead of commas, add the following to config/environment.rb: | ||
| 139 | |||
| 140 | TagList.delimiter = " " | ||
| 141 | |||
| 142 | === Unused tags | ||
| 143 | |||
| 144 | Set Tag.destroy_unused to remove tags when they are no longer being | ||
| 145 | used to tag any objects. Defaults to false. | ||
| 146 | |||
| 147 | Tag.destroy_unused = true | ||
| 148 | |||
| 149 | === Other | ||
| 150 | |||
| 151 | Problems, comments, and suggestions all welcome. jonathan.viney@gmail.com | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/Rakefile b/vendor/plugins/acts_as_taggable_on_steroids/Rakefile deleted file mode 100644 index 93c2706..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/Rakefile +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | require 'rake' | ||
| 2 | require 'rake/testtask' | ||
| 3 | require 'rake/rdoctask' | ||
| 4 | |||
| 5 | desc 'Default: run unit tests.' | ||
| 6 | task :default => :test | ||
| 7 | |||
| 8 | desc 'Test the acts_as_taggable_on_steroids plugin.' | ||
| 9 | Rake::TestTask.new(:test) do |t| | ||
| 10 | t.libs << 'test' | ||
| 11 | t.pattern = 'test/**/*_test.rb' | ||
| 12 | t.verbose = true | ||
| 13 | end | ||
| 14 | |||
| 15 | desc 'Generate documentation for the acts_as_taggable_on_steroids plugin.' | ||
| 16 | Rake::RDocTask.new(:rdoc) do |rdoc| | ||
| 17 | rdoc.rdoc_dir = 'rdoc' | ||
| 18 | rdoc.title = 'Acts As Taggable On Steroids' | ||
| 19 | rdoc.options << '--line-numbers' << '--inline-source' | ||
| 20 | rdoc.rdoc_files.include('README') | ||
| 21 | rdoc.rdoc_files.include('lib/**/*.rb') | ||
| 22 | end | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/acts_as_taggable_on_steroids.gemspec b/vendor/plugins/acts_as_taggable_on_steroids/acts_as_taggable_on_steroids.gemspec deleted file mode 100644 index f91ad4d..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/acts_as_taggable_on_steroids.gemspec +++ /dev/null | |||
| @@ -1,54 +0,0 @@ | |||
| 1 | Gem::Specification.new do |s| | ||
| 2 | s.name = "acts_as_taggable_on_steroids" | ||
| 3 | s.version = "1.1" | ||
| 4 | s.date = "2009-06-11" | ||
| 5 | s.summary = "Rails plugin that is based on acts_as_taggable by DHH but includes extras such as tests, smarter tag assignment, and tag cloud calculations." | ||
| 6 | s.email = "jonathan.viney@gmail.com" | ||
| 7 | s.homepage = "http://github.com/jviney/acts_as_taggable_on_steroids" | ||
| 8 | s.description = "Rails plugin that is based on acts_as_taggable by DHH but includes extras such as tests, smarter tag assignment, and tag cloud calculations." | ||
| 9 | s.has_rdoc = true | ||
| 10 | s.rdoc_options = ["--inline-source", "--charset=UTF-8"] | ||
| 11 | s.rubyforge_project = "acts_as_taggable_on_steroids" | ||
| 12 | s.authors = "Jonathan Viney" | ||
| 13 | s.files = [ | ||
| 14 | "acts_as_taggable_on_steroids.gemspec", | ||
| 15 | "CHANGELOG", | ||
| 16 | "generators/acts_as_taggable_migration", | ||
| 17 | "generators/acts_as_taggable_migration/acts_as_taggable_migration_generator.rb", | ||
| 18 | "generators/acts_as_taggable_migration/templates", | ||
| 19 | "generators/acts_as_taggable_migration/templates/migration.rb", | ||
| 20 | "init.rb", | ||
| 21 | "lib/acts_as_taggable.rb", | ||
| 22 | "lib/tag.rb", | ||
| 23 | "lib/tag_list.rb", | ||
| 24 | "lib/tagging.rb", | ||
| 25 | "lib/tags_helper.rb", | ||
| 26 | "MIT-LICENSE", | ||
| 27 | "Rakefile", | ||
| 28 | "README", | ||
| 29 | ] | ||
| 30 | s.test_files = [ | ||
| 31 | "test/abstract_unit.rb", | ||
| 32 | "test/acts_as_taggable_test.rb", | ||
| 33 | "test/database.yml", | ||
| 34 | "test/fixtures", | ||
| 35 | "test/fixtures/magazine.rb", | ||
| 36 | "test/fixtures/magazines.yml", | ||
| 37 | "test/fixtures/photo.rb", | ||
| 38 | "test/fixtures/photos.yml", | ||
| 39 | "test/fixtures/post.rb", | ||
| 40 | "test/fixtures/posts.yml", | ||
| 41 | "test/fixtures/special_post.rb", | ||
| 42 | "test/fixtures/subscription.rb", | ||
| 43 | "test/fixtures/subscriptions.yml", | ||
| 44 | "test/fixtures/taggings.yml", | ||
| 45 | "test/fixtures/tags.yml", | ||
| 46 | "test/fixtures/user.rb", | ||
| 47 | "test/fixtures/users.yml", | ||
| 48 | "test/schema.rb", | ||
| 49 | "test/tag_list_test.rb", | ||
| 50 | "test/tag_test.rb", | ||
| 51 | "test/tagging_test.rb", | ||
| 52 | "test/tags_helper_test.rb" | ||
| 53 | ] | ||
| 54 | end | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/generators/acts_as_taggable_migration/acts_as_taggable_migration_generator.rb b/vendor/plugins/acts_as_taggable_on_steroids/generators/acts_as_taggable_migration/acts_as_taggable_migration_generator.rb deleted file mode 100644 index be9b39c..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/generators/acts_as_taggable_migration/acts_as_taggable_migration_generator.rb +++ /dev/null | |||
| @@ -1,11 +0,0 @@ | |||
| 1 | class ActsAsTaggableMigrationGenerator < Rails::Generator::Base | ||
| 2 | def manifest | ||
| 3 | record do |m| | ||
| 4 | m.migration_template 'migration.rb', 'db/migrate' | ||
| 5 | end | ||
| 6 | end | ||
| 7 | |||
| 8 | def file_name | ||
| 9 | "acts_as_taggable_migration" | ||
| 10 | end | ||
| 11 | end | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/generators/acts_as_taggable_migration/templates/migration.rb b/vendor/plugins/acts_as_taggable_on_steroids/generators/acts_as_taggable_migration/templates/migration.rb deleted file mode 100644 index ea0c2cc..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/generators/acts_as_taggable_migration/templates/migration.rb +++ /dev/null | |||
| @@ -1,26 +0,0 @@ | |||
| 1 | class ActsAsTaggableMigration < ActiveRecord::Migration | ||
| 2 | def self.up | ||
| 3 | create_table :tags do |t| | ||
| 4 | t.column :name, :string | ||
| 5 | end | ||
| 6 | |||
| 7 | create_table :taggings do |t| | ||
| 8 | t.column :tag_id, :integer | ||
| 9 | t.column :taggable_id, :integer | ||
| 10 | |||
| 11 | # You should make sure that the column created is | ||
| 12 | # long enough to store the required class names. | ||
| 13 | t.column :taggable_type, :string | ||
| 14 | |||
| 15 | t.column :created_at, :datetime | ||
| 16 | end | ||
| 17 | |||
| 18 | add_index :taggings, :tag_id | ||
| 19 | add_index :taggings, [:taggable_id, :taggable_type] | ||
| 20 | end | ||
| 21 | |||
| 22 | def self.down | ||
| 23 | drop_table :taggings | ||
| 24 | drop_table :tags | ||
| 25 | end | ||
| 26 | end | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/init.rb b/vendor/plugins/acts_as_taggable_on_steroids/init.rb deleted file mode 100644 index 64505b9..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/init.rb +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | require File.dirname(__FILE__) + '/lib/acts_as_taggable' | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/lib/acts_as_taggable.rb b/vendor/plugins/acts_as_taggable_on_steroids/lib/acts_as_taggable.rb deleted file mode 100644 index 7a96ef0..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/lib/acts_as_taggable.rb +++ /dev/null | |||
| @@ -1,230 +0,0 @@ | |||
| 1 | module ActiveRecord #:nodoc: | ||
| 2 | module Acts #:nodoc: | ||
| 3 | module Taggable #:nodoc: | ||
| 4 | def self.included(base) | ||
| 5 | base.extend(ClassMethods) | ||
| 6 | end | ||
| 7 | |||
| 8 | module ClassMethods | ||
| 9 | def acts_as_taggable | ||
| 10 | has_many :taggings, :as => :taggable, :dependent => :destroy, :include => :tag | ||
| 11 | has_many :tags, :through => :taggings | ||
| 12 | |||
| 13 | before_save :save_cached_tag_list | ||
| 14 | |||
| 15 | after_create :save_tags | ||
| 16 | after_update :save_tags | ||
| 17 | |||
| 18 | include ActiveRecord::Acts::Taggable::InstanceMethods | ||
| 19 | extend ActiveRecord::Acts::Taggable::SingletonMethods | ||
| 20 | |||
| 21 | alias_method_chain :reload, :tag_list | ||
| 22 | end | ||
| 23 | |||
| 24 | def cached_tag_list_column_name | ||
| 25 | "cached_tag_list" | ||
| 26 | end | ||
| 27 | |||
| 28 | def set_cached_tag_list_column_name(value = nil, &block) | ||
| 29 | define_attr_method :cached_tag_list_column_name, value, &block | ||
| 30 | end | ||
| 31 | end | ||
| 32 | |||
| 33 | module SingletonMethods | ||
| 34 | # Returns an array of related tags. | ||
| 35 | # Related tags are all the other tags that are found on the models tagged with the provided tags. | ||
| 36 | # | ||
| 37 | # Pass either a tag, string, or an array of strings or tags. | ||
| 38 | # | ||
| 39 | # Options: | ||
| 40 | # :order - SQL Order how to order the tags. Defaults to "count DESC, tags.name". | ||
| 41 | def find_related_tags(tags, options = {}) | ||
| 42 | tags = tags.is_a?(Array) ? TagList.new(tags.map(&:to_s)) : TagList.from(tags) | ||
| 43 | |||
| 44 | related_models = find_tagged_with(tags) | ||
| 45 | |||
| 46 | return [] if related_models.blank? | ||
| 47 | |||
| 48 | related_ids = related_models.to_s(:db) | ||
| 49 | |||
| 50 | Tag.find(:all, options.merge({ | ||
| 51 | :select => "#{Tag.table_name}.*, COUNT(#{Tag.table_name}.id) AS count", | ||
| 52 | :joins => "JOIN #{Tagging.table_name} ON #{Tagging.table_name}.taggable_type = '#{base_class.name}' | ||
| 53 | AND #{Tagging.table_name}.taggable_id IN (#{related_ids}) | ||
| 54 | AND #{Tagging.table_name}.tag_id = #{Tag.table_name}.id", | ||
| 55 | :order => options[:order] || "count DESC, #{Tag.table_name}.name", | ||
| 56 | :group => "#{Tag.table_name}.id, #{Tag.table_name}.name HAVING #{Tag.table_name}.name NOT IN (#{tags.map { |n| quote_value(n) }.join(",")})" | ||
| 57 | })) | ||
| 58 | end | ||
| 59 | |||
| 60 | # Pass either a tag, string, or an array of strings or tags. | ||
| 61 | # | ||
| 62 | # Options: | ||
| 63 | # :exclude - Find models that are not tagged with the given tags | ||
| 64 | # :match_all - Find models that match all of the given tags, not just one | ||
| 65 | # :conditions - A piece of SQL conditions to add to the query | ||
| 66 | def find_tagged_with(*args) | ||
| 67 | options = find_options_for_find_tagged_with(*args) | ||
| 68 | options.blank? ? [] : find(:all, options) | ||
| 69 | end | ||
| 70 | |||
| 71 | def find_options_for_find_tagged_with(tags, options = {}) | ||
| 72 | tags = tags.is_a?(Array) ? TagList.new(tags.map(&:to_s)) : TagList.from(tags) | ||
| 73 | options = options.dup | ||
| 74 | |||
| 75 | return {} if tags.empty? | ||
| 76 | |||
| 77 | conditions = [] | ||
| 78 | conditions << sanitize_sql(options.delete(:conditions)) if options[:conditions] | ||
| 79 | |||
| 80 | taggings_alias, tags_alias = "#{table_name}_taggings", "#{table_name}_tags" | ||
| 81 | |||
| 82 | joins = [ | ||
| 83 | "INNER JOIN #{Tagging.table_name} #{taggings_alias} ON #{taggings_alias}.taggable_id = #{table_name}.#{primary_key} AND #{taggings_alias}.taggable_type = #{quote_value(base_class.name)}", | ||
| 84 | "INNER JOIN #{Tag.table_name} #{tags_alias} ON #{tags_alias}.id = #{taggings_alias}.tag_id" | ||
| 85 | ] | ||
| 86 | |||
| 87 | if options.delete(:exclude) | ||
| 88 | conditions << <<-END | ||
| 89 | #{table_name}.id NOT IN | ||
| 90 | (SELECT #{Tagging.table_name}.taggable_id FROM #{Tagging.table_name} | ||
| 91 | INNER JOIN #{Tag.table_name} ON #{Tagging.table_name}.tag_id = #{Tag.table_name}.id | ||
| 92 | WHERE #{tags_condition(tags)} AND #{Tagging.table_name}.taggable_type = #{quote_value(base_class.name)}) | ||
| 93 | END | ||
| 94 | else | ||
| 95 | if options.delete(:match_all) | ||
| 96 | joins << joins_for_match_all_tags(tags) | ||
| 97 | else | ||
| 98 | conditions << tags_condition(tags, tags_alias) | ||
| 99 | end | ||
| 100 | end | ||
| 101 | |||
| 102 | { :select => "DISTINCT #{table_name}.*", | ||
| 103 | :joins => joins.join(" "), | ||
| 104 | :conditions => conditions.join(" AND ") | ||
| 105 | }.reverse_merge!(options) | ||
| 106 | end | ||
| 107 | |||
| 108 | def joins_for_match_all_tags(tags) | ||
| 109 | joins = [] | ||
| 110 | |||
| 111 | tags.each_with_index do |tag, index| | ||
| 112 | taggings_alias, tags_alias = "taggings_#{index}", "tags_#{index}" | ||
| 113 | |||
| 114 | join = <<-END | ||
| 115 | INNER JOIN #{Tagging.table_name} #{taggings_alias} ON | ||
| 116 | #{taggings_alias}.taggable_id = #{table_name}.#{primary_key} AND | ||
| 117 | #{taggings_alias}.taggable_type = #{quote_value(base_class.name)} | ||
| 118 | |||
| 119 | INNER JOIN #{Tag.table_name} #{tags_alias} ON | ||
| 120 | #{taggings_alias}.tag_id = #{tags_alias}.id AND | ||
| 121 | #{tags_alias}.name = ? | ||
| 122 | END | ||
| 123 | |||
| 124 | joins << sanitize_sql([join, tag]) | ||
| 125 | end | ||
| 126 | |||
| 127 | joins.join(" ") | ||
| 128 | end | ||
| 129 | |||
| 130 | # Calculate the tag counts for all tags. | ||
| 131 | # | ||
| 132 | # See Tag.counts for available options. | ||
| 133 | def tag_counts(options = {}) | ||
| 134 | Tag.find(:all, find_options_for_tag_counts(options)) | ||
| 135 | end | ||
| 136 | |||
| 137 | def find_options_for_tag_counts(options = {}) | ||
| 138 | options = options.dup | ||
| 139 | scope = scope(:find) | ||
| 140 | |||
| 141 | conditions = [] | ||
| 142 | conditions << send(:sanitize_conditions, options.delete(:conditions)) if options[:conditions] | ||
| 143 | conditions << send(:sanitize_conditions, scope[:conditions]) if scope && scope[:conditions] | ||
| 144 | conditions << "#{Tagging.table_name}.taggable_type = #{quote_value(base_class.name)}" | ||
| 145 | conditions << type_condition unless descends_from_active_record? | ||
| 146 | conditions.compact! | ||
| 147 | conditions = conditions.join(" AND ") | ||
| 148 | |||
| 149 | joins = ["INNER JOIN #{table_name} ON #{table_name}.#{primary_key} = #{Tagging.table_name}.taggable_id"] | ||
| 150 | joins << options.delete(:joins) if options[:joins] | ||
| 151 | joins << scope[:joins] if scope && scope[:joins] | ||
| 152 | joins = joins.join(" ") | ||
| 153 | |||
| 154 | options = { :conditions => conditions, :joins => joins }.update(options) | ||
| 155 | |||
| 156 | Tag.options_for_counts(options) | ||
| 157 | end | ||
| 158 | |||
| 159 | def caching_tag_list? | ||
| 160 | column_names.include?(cached_tag_list_column_name) | ||
| 161 | end | ||
| 162 | |||
| 163 | private | ||
| 164 | def tags_condition(tags, table_name = Tag.table_name) | ||
| 165 | condition = tags.map { |t| sanitize_sql(["#{table_name}.name LIKE ?", t]) }.join(" OR ") | ||
| 166 | "(" + condition + ")" unless condition.blank? | ||
| 167 | end | ||
| 168 | end | ||
| 169 | |||
| 170 | module InstanceMethods | ||
| 171 | def tag_list | ||
| 172 | return @tag_list if @tag_list | ||
| 173 | |||
| 174 | if self.class.caching_tag_list? and !(cached_value = send(self.class.cached_tag_list_column_name)).nil? | ||
| 175 | @tag_list = TagList.from(cached_value) | ||
| 176 | else | ||
| 177 | @tag_list = TagList.new(*tags.map(&:name)) | ||
| 178 | end | ||
| 179 | end | ||
| 180 | |||
| 181 | def tag_list=(value) | ||
| 182 | @tag_list = TagList.from(value) | ||
| 183 | end | ||
| 184 | |||
| 185 | def save_cached_tag_list | ||
| 186 | if self.class.caching_tag_list? | ||
| 187 | self[self.class.cached_tag_list_column_name] = tag_list.to_s | ||
| 188 | end | ||
| 189 | end | ||
| 190 | |||
| 191 | def save_tags | ||
| 192 | return unless @tag_list | ||
| 193 | |||
| 194 | new_tag_names = @tag_list - tags.map(&:name) | ||
| 195 | old_tags = tags.reject { |tag| @tag_list.include?(tag.name) } | ||
| 196 | |||
| 197 | self.class.transaction do | ||
| 198 | if old_tags.any? | ||
| 199 | taggings.find(:all, :conditions => ["tag_id IN (?)", old_tags.map(&:id)]).each(&:destroy) | ||
| 200 | taggings.reset | ||
| 201 | end | ||
| 202 | |||
| 203 | new_tag_names.each do |new_tag_name| | ||
| 204 | tags << Tag.find_or_create_with_like_by_name(new_tag_name) | ||
| 205 | end | ||
| 206 | end | ||
| 207 | |||
| 208 | true | ||
| 209 | end | ||
| 210 | |||
| 211 | # Calculate the tag counts for the tags used by this model. | ||
| 212 | # | ||
| 213 | # The possible options are the same as the tag_counts class method. | ||
| 214 | def tag_counts(options = {}) | ||
| 215 | return [] if tag_list.blank? | ||
| 216 | |||
| 217 | options[:conditions] = self.class.send(:merge_conditions, options[:conditions], self.class.send(:tags_condition, tag_list)) | ||
| 218 | self.class.tag_counts(options) | ||
| 219 | end | ||
| 220 | |||
| 221 | def reload_with_tag_list(*args) #:nodoc: | ||
| 222 | @tag_list = nil | ||
| 223 | reload_without_tag_list(*args) | ||
| 224 | end | ||
| 225 | end | ||
| 226 | end | ||
| 227 | end | ||
| 228 | end | ||
| 229 | |||
| 230 | ActiveRecord::Base.send(:include, ActiveRecord::Acts::Taggable) | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/lib/tag.rb b/vendor/plugins/acts_as_taggable_on_steroids/lib/tag.rb deleted file mode 100644 index 44f0991..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/lib/tag.rb +++ /dev/null | |||
| @@ -1,71 +0,0 @@ | |||
| 1 | class Tag < ActiveRecord::Base | ||
| 2 | has_many :taggings, :dependent => :destroy | ||
| 3 | |||
| 4 | validates_presence_of :name | ||
| 5 | validates_uniqueness_of :name | ||
| 6 | |||
| 7 | cattr_accessor :destroy_unused | ||
| 8 | self.destroy_unused = false | ||
| 9 | |||
| 10 | # LIKE is used for cross-database case-insensitivity | ||
| 11 | def self.find_or_create_with_like_by_name(name) | ||
| 12 | find(:first, :conditions => ["name LIKE ?", name]) || create(:name => name) | ||
| 13 | end | ||
| 14 | |||
| 15 | def ==(object) | ||
| 16 | super || (object.is_a?(Tag) && name == object.name) | ||
| 17 | end | ||
| 18 | |||
| 19 | def to_s | ||
| 20 | name | ||
| 21 | end | ||
| 22 | |||
| 23 | def count | ||
| 24 | read_attribute(:count).to_i | ||
| 25 | end | ||
| 26 | |||
| 27 | class << self | ||
| 28 | # Calculate the tag counts for all tags. | ||
| 29 | # :start_at - Restrict the tags to those created after a certain time | ||
| 30 | # :end_at - Restrict the tags to those created before a certain time | ||
| 31 | # :conditions - A piece of SQL conditions to add to the query | ||
| 32 | # :limit - The maximum number of tags to return | ||
| 33 | # :order - A piece of SQL to order by. Eg 'count desc' or 'taggings.created_at desc' | ||
| 34 | # :at_least - Exclude tags with a frequency less than the given value | ||
| 35 | # :at_most - Exclude tags with a frequency greater than the given value | ||
| 36 | def counts(options = {}) | ||
| 37 | find(:all, options_for_counts(options)) | ||
| 38 | end | ||
| 39 | |||
| 40 | def options_for_counts(options = {}) | ||
| 41 | options.assert_valid_keys :start_at, :end_at, :conditions, :at_least, :at_most, :order, :limit, :joins | ||
| 42 | options = options.dup | ||
| 43 | |||
| 44 | start_at = sanitize_sql(["#{Tagging.table_name}.created_at >= ?", options.delete(:start_at)]) if options[:start_at] | ||
| 45 | end_at = sanitize_sql(["#{Tagging.table_name}.created_at <= ?", options.delete(:end_at)]) if options[:end_at] | ||
| 46 | |||
| 47 | conditions = [ | ||
| 48 | (sanitize_sql(options.delete(:conditions)) if options[:conditions]), | ||
| 49 | start_at, | ||
| 50 | end_at | ||
| 51 | ].compact | ||
| 52 | |||
| 53 | conditions = conditions.join(' AND ') if conditions.any? | ||
| 54 | |||
| 55 | joins = ["INNER JOIN #{Tagging.table_name} ON #{Tag.table_name}.id = #{Tagging.table_name}.tag_id"] | ||
| 56 | joins << options.delete(:joins) if options[:joins] | ||
| 57 | |||
| 58 | at_least = sanitize_sql(['COUNT(*) >= ?', options.delete(:at_least)]) if options[:at_least] | ||
| 59 | at_most = sanitize_sql(['COUNT(*) <= ?', options.delete(:at_most)]) if options[:at_most] | ||
| 60 | having = [at_least, at_most].compact.join(' AND ') | ||
| 61 | group_by = "#{Tag.table_name}.id, #{Tag.table_name}.name HAVING COUNT(*) > 0" | ||
| 62 | group_by << " AND #{having}" unless having.blank? | ||
| 63 | |||
| 64 | { :select => "#{Tag.table_name}.id, #{Tag.table_name}.name, COUNT(*) AS count", | ||
| 65 | :joins => joins.join(" "), | ||
| 66 | :conditions => conditions, | ||
| 67 | :group => group_by | ||
| 68 | }.update(options) | ||
| 69 | end | ||
| 70 | end | ||
| 71 | end | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/lib/tag_list.rb b/vendor/plugins/acts_as_taggable_on_steroids/lib/tag_list.rb deleted file mode 100644 index 700399b..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/lib/tag_list.rb +++ /dev/null | |||
| @@ -1,108 +0,0 @@ | |||
| 1 | class TagList < Array | ||
| 2 | cattr_accessor :delimiter | ||
| 3 | self.delimiter = ',' | ||
| 4 | |||
| 5 | def initialize(*args) | ||
| 6 | add(*args) | ||
| 7 | end | ||
| 8 | |||
| 9 | # Add tags to the tag_list. Duplicate or blank tags will be ignored. | ||
| 10 | # | ||
| 11 | # tag_list.add("Fun", "Happy") | ||
| 12 | # | ||
| 13 | # Use the <tt>:parse</tt> option to add an unparsed tag string. | ||
| 14 | # | ||
| 15 | # tag_list.add("Fun, Happy", :parse => true) | ||
| 16 | def add(*names) | ||
| 17 | extract_and_apply_options!(names) | ||
| 18 | concat(names) | ||
| 19 | clean! | ||
| 20 | self | ||
| 21 | end | ||
| 22 | |||
| 23 | # Remove specific tags from the tag_list. | ||
| 24 | # | ||
| 25 | # tag_list.remove("Sad", "Lonely") | ||
| 26 | # | ||
| 27 | # Like #add, the <tt>:parse</tt> option can be used to remove multiple tags in a string. | ||
| 28 | # | ||
| 29 | # tag_list.remove("Sad, Lonely", :parse => true) | ||
| 30 | def remove(*names) | ||
| 31 | extract_and_apply_options!(names) | ||
| 32 | delete_if { |name| names.include?(name) } | ||
| 33 | self | ||
| 34 | end | ||
| 35 | |||
| 36 | # Toggle the presence of the given tags. | ||
| 37 | # If a tag is already in the list it is removed, otherwise it is added. | ||
| 38 | def toggle(*names) | ||
| 39 | extract_and_apply_options!(names) | ||
| 40 | |||
| 41 | names.each do |name| | ||
| 42 | include?(name) ? delete(name) : push(name) | ||
| 43 | end | ||
| 44 | |||
| 45 | clean! | ||
| 46 | self | ||
| 47 | end | ||
| 48 | |||
| 49 | # Transform the tag_list into a tag string suitable for edting in a form. | ||
| 50 | # The tags are joined with <tt>TagList.delimiter</tt> and quoted if necessary. | ||
| 51 | # | ||
| 52 | # tag_list = TagList.new("Round", "Square,Cube") | ||
| 53 | # tag_list.to_s # 'Round, "Square,Cube"' | ||
| 54 | def to_s | ||
| 55 | clean! | ||
| 56 | |||
| 57 | map do |name| | ||
| 58 | name.include?(delimiter) ? "\"#{name}\"" : name | ||
| 59 | end.join(delimiter.ends_with?(" ") ? delimiter : "#{delimiter} ") | ||
| 60 | end | ||
| 61 | |||
| 62 | private | ||
| 63 | # Remove whitespace, duplicates, and blanks. | ||
| 64 | def clean! | ||
| 65 | reject!(&:blank?) | ||
| 66 | map!(&:strip) | ||
| 67 | uniq! | ||
| 68 | end | ||
| 69 | |||
| 70 | def extract_and_apply_options!(args) | ||
| 71 | options = args.last.is_a?(Hash) ? args.pop : {} | ||
| 72 | options.assert_valid_keys :parse | ||
| 73 | |||
| 74 | if options[:parse] | ||
| 75 | args.map! { |a| self.class.from(a) } | ||
| 76 | end | ||
| 77 | |||
| 78 | args.flatten! | ||
| 79 | end | ||
| 80 | |||
| 81 | class << self | ||
| 82 | # Returns a new TagList using the given tag string. | ||
| 83 | # | ||
| 84 | # tag_list = TagList.from("One , Two, Three") | ||
| 85 | # tag_list # ["One", "Two", "Three"] | ||
| 86 | def from(source) | ||
| 87 | returning new do |tag_list| | ||
| 88 | |||
| 89 | case source | ||
| 90 | when Array | ||
| 91 | tag_list.add(source) | ||
| 92 | else | ||
| 93 | string = source.to_s.dup | ||
| 94 | |||
| 95 | # Parse the quoted tags | ||
| 96 | [ | ||
| 97 | /\s*#{delimiter}\s*(['"])(.*?)\1\s*/, | ||
| 98 | /^\s*(['"])(.*?)\1\s*#{delimiter}?/ | ||
| 99 | ].each do |re| | ||
| 100 | string.gsub!(re) { tag_list << $2; "" } | ||
| 101 | end | ||
| 102 | |||
| 103 | tag_list.add(string.split(delimiter)) | ||
| 104 | end | ||
| 105 | end | ||
| 106 | end | ||
| 107 | end | ||
| 108 | end | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/lib/tagging.rb b/vendor/plugins/acts_as_taggable_on_steroids/lib/tagging.rb deleted file mode 100644 index 87bc44d..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/lib/tagging.rb +++ /dev/null | |||
| @@ -1,12 +0,0 @@ | |||
| 1 | class Tagging < ActiveRecord::Base #:nodoc: | ||
| 2 | belongs_to :tag | ||
| 3 | belongs_to :taggable, :polymorphic => true | ||
| 4 | |||
| 5 | def after_destroy | ||
| 6 | if Tag.destroy_unused | ||
| 7 | if tag.taggings.count.zero? | ||
| 8 | tag.destroy | ||
| 9 | end | ||
| 10 | end | ||
| 11 | end | ||
| 12 | end | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/lib/tags_helper.rb b/vendor/plugins/acts_as_taggable_on_steroids/lib/tags_helper.rb deleted file mode 100644 index d5644b7..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/lib/tags_helper.rb +++ /dev/null | |||
| @@ -1,13 +0,0 @@ | |||
| 1 | module TagsHelper | ||
| 2 | # See the README for an example using tag_cloud. | ||
| 3 | def tag_cloud(tags, classes) | ||
| 4 | return if tags.empty? | ||
| 5 | |||
| 6 | max_count = tags.sort_by(&:count).last.count.to_f | ||
| 7 | |||
| 8 | tags.each do |tag| | ||
| 9 | index = ((tag.count / max_count) * (classes.size - 1)).round | ||
| 10 | yield tag, classes[index] | ||
| 11 | end | ||
| 12 | end | ||
| 13 | end | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/test/abstract_unit.rb b/vendor/plugins/acts_as_taggable_on_steroids/test/abstract_unit.rb deleted file mode 100644 index f480387..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/test/abstract_unit.rb +++ /dev/null | |||
| @@ -1,102 +0,0 @@ | |||
| 1 | require 'test/unit' | ||
| 2 | |||
| 3 | begin | ||
| 4 | require File.dirname(__FILE__) + '/../../../../config/environment' | ||
| 5 | rescue LoadError | ||
| 6 | require 'rubygems' | ||
| 7 | gem 'activerecord' | ||
| 8 | gem 'actionpack' | ||
| 9 | require 'active_record' | ||
| 10 | require 'action_controller' | ||
| 11 | end | ||
| 12 | |||
| 13 | # Search for fixtures first | ||
| 14 | fixture_path = File.dirname(__FILE__) + '/fixtures/' | ||
| 15 | ActiveSupport::Dependencies.load_paths.insert(0, fixture_path) | ||
| 16 | |||
| 17 | require "active_record/test_case" | ||
| 18 | require "active_record/fixtures" | ||
| 19 | |||
| 20 | require File.dirname(__FILE__) + '/../lib/acts_as_taggable' | ||
| 21 | require_dependency File.dirname(__FILE__) + '/../lib/tag_list' | ||
| 22 | require_dependency File.dirname(__FILE__) + '/../lib/tags_helper' | ||
| 23 | |||
| 24 | ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + '/debug.log') | ||
| 25 | ActiveRecord::Base.configurations = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml')) | ||
| 26 | ActiveRecord::Base.establish_connection(ENV['DB'] || 'mysql') | ||
| 27 | |||
| 28 | load(File.dirname(__FILE__) + '/schema.rb') | ||
| 29 | |||
| 30 | class ActiveSupport::TestCase #:nodoc: | ||
| 31 | include ActiveRecord::TestFixtures | ||
| 32 | |||
| 33 | self.fixture_path = File.dirname(__FILE__) + "/fixtures/" | ||
| 34 | |||
| 35 | self.use_transactional_fixtures = true | ||
| 36 | self.use_instantiated_fixtures = false | ||
| 37 | |||
| 38 | fixtures :all | ||
| 39 | |||
| 40 | def assert_equivalent(expected, actual, message = nil) | ||
| 41 | if expected.first.is_a?(ActiveRecord::Base) | ||
| 42 | assert_equal expected.sort_by(&:id), actual.sort_by(&:id), message | ||
| 43 | else | ||
| 44 | assert_equal expected.sort, actual.sort, message | ||
| 45 | end | ||
| 46 | end | ||
| 47 | |||
| 48 | def assert_tag_counts(tags, expected_values) | ||
| 49 | # Map the tag fixture names to real tag names | ||
| 50 | expected_values = expected_values.inject({}) do |hash, (tag, count)| | ||
| 51 | hash[tags(tag).name] = count | ||
| 52 | hash | ||
| 53 | end | ||
| 54 | |||
| 55 | tags.each do |tag| | ||
| 56 | value = expected_values.delete(tag.name) | ||
| 57 | |||
| 58 | assert_not_nil value, "Expected count for #{tag.name} was not provided" | ||
| 59 | assert_equal value, tag.count, "Expected value of #{value} for #{tag.name}, but was #{tag.count}" | ||
| 60 | end | ||
| 61 | |||
| 62 | unless expected_values.empty? | ||
| 63 | assert false, "The following tag counts were not present: #{expected_values.inspect}" | ||
| 64 | end | ||
| 65 | end | ||
| 66 | |||
| 67 | def assert_queries(num = 1) | ||
| 68 | $query_count = 0 | ||
| 69 | yield | ||
| 70 | ensure | ||
| 71 | assert_equal num, $query_count, "#{$query_count} instead of #{num} queries were executed." | ||
| 72 | end | ||
| 73 | |||
| 74 | def assert_no_queries(&block) | ||
| 75 | assert_queries(0, &block) | ||
| 76 | end | ||
| 77 | |||
| 78 | # From Rails trunk | ||
| 79 | def assert_difference(expressions, difference = 1, message = nil, &block) | ||
| 80 | expression_evaluations = [expressions].flatten.collect{|expression| lambda { eval(expression, block.binding) } } | ||
| 81 | |||
| 82 | original_values = expression_evaluations.inject([]) { |memo, expression| memo << expression.call } | ||
| 83 | yield | ||
| 84 | expression_evaluations.each_with_index do |expression, i| | ||
| 85 | assert_equal original_values[i] + difference, expression.call, message | ||
| 86 | end | ||
| 87 | end | ||
| 88 | |||
| 89 | def assert_no_difference(expressions, message = nil, &block) | ||
| 90 | assert_difference expressions, 0, message, &block | ||
| 91 | end | ||
| 92 | end | ||
| 93 | |||
| 94 | ActiveRecord::Base.connection.class.class_eval do | ||
| 95 | def execute_with_counting(sql, name = nil, &block) | ||
| 96 | $query_count ||= 0 | ||
| 97 | $query_count += 1 | ||
| 98 | execute_without_counting(sql, name, &block) | ||
| 99 | end | ||
| 100 | |||
| 101 | alias_method_chain :execute, :counting | ||
| 102 | end | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/test/acts_as_taggable_test.rb b/vendor/plugins/acts_as_taggable_on_steroids/test/acts_as_taggable_test.rb deleted file mode 100644 index 9766d34..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/test/acts_as_taggable_test.rb +++ /dev/null | |||
| @@ -1,384 +0,0 @@ | |||
| 1 | require File.dirname(__FILE__) + '/abstract_unit' | ||
| 2 | |||
| 3 | class ActsAsTaggableOnSteroidsTest < ActiveSupport::TestCase | ||
| 4 | def test_find_related_tags_with | ||
| 5 | assert_equivalent [tags(:good), tags(:bad), tags(:question)], Post.find_related_tags("nature") | ||
| 6 | assert_equivalent [tags(:nature)], Post.find_related_tags([tags(:good)]) | ||
| 7 | assert_equivalent [tags(:bad), tags(:question)], Post.find_related_tags(["Very Good", "Nature"]) | ||
| 8 | assert_equivalent [tags(:bad), tags(:question)], Post.find_related_tags([tags(:good), tags(:nature)]) | ||
| 9 | end | ||
| 10 | |||
| 11 | def test_find_tagged_with_include_and_order | ||
| 12 | assert_equal photos(:sam_sky, :sam_flower, :jonathan_dog), Photo.find_tagged_with("Nature", :order => "photos.title DESC", :include => :user) | ||
| 13 | end | ||
| 14 | |||
| 15 | def test_find_related_tags_with_non_existent_tags | ||
| 16 | assert_equal [], Post.find_related_tags("ABCDEFG") | ||
| 17 | assert_equal [], Post.find_related_tags(['HIJKLM']) | ||
| 18 | end | ||
| 19 | |||
| 20 | def test_find_related_tags_with_nothing | ||
| 21 | assert_equal [], Post.find_related_tags("") | ||
| 22 | assert_equal [], Post.find_related_tags([]) | ||
| 23 | end | ||
| 24 | |||
| 25 | def test_find_tagged_with | ||
| 26 | assert_equivalent [posts(:jonathan_sky), posts(:sam_flowers)], Post.find_tagged_with('"Very good"') | ||
| 27 | assert_equal Post.find_tagged_with('"Very good"'), Post.find_tagged_with(['Very good']) | ||
| 28 | assert_equal Post.find_tagged_with('"Very good"'), Post.find_tagged_with([tags(:good)]) | ||
| 29 | |||
| 30 | assert_equivalent [photos(:jonathan_dog), photos(:sam_flower), photos(:sam_sky)], Photo.find_tagged_with('Nature') | ||
| 31 | assert_equal Photo.find_tagged_with('Nature'), Photo.find_tagged_with(['Nature']) | ||
| 32 | assert_equal Photo.find_tagged_with('Nature'), Photo.find_tagged_with([tags(:nature)]) | ||
| 33 | |||
| 34 | assert_equivalent [photos(:jonathan_bad_cat), photos(:jonathan_dog), photos(:jonathan_questioning_dog)], Photo.find_tagged_with('"Crazy animal" Bad') | ||
| 35 | assert_equal Photo.find_tagged_with('"Crazy animal" Bad'), Photo.find_tagged_with(['Crazy animal', 'Bad']) | ||
| 36 | assert_equal Photo.find_tagged_with('"Crazy animal" Bad'), Photo.find_tagged_with([tags(:animal), tags(:bad)]) | ||
| 37 | end | ||
| 38 | |||
| 39 | def test_find_tagged_with_nothing | ||
| 40 | assert_equal [], Post.find_tagged_with("") | ||
| 41 | assert_equal [], Post.find_tagged_with([]) | ||
| 42 | end | ||
| 43 | |||
| 44 | def test_find_tagged_with_nonexistant_tags | ||
| 45 | assert_equal [], Post.find_tagged_with('ABCDEFG') | ||
| 46 | assert_equal [], Photo.find_tagged_with(['HIJKLM']) | ||
| 47 | assert_equal [], Photo.find_tagged_with([Tag.new(:name => 'unsaved tag')]) | ||
| 48 | end | ||
| 49 | |||
| 50 | def test_find_tagged_with_match_all | ||
| 51 | assert_equivalent [photos(:jonathan_dog)], Photo.find_tagged_with('Crazy animal, "Nature"', :match_all => true) | ||
| 52 | end | ||
| 53 | |||
| 54 | def test_find_tagged_with_match_all_and_include | ||
| 55 | assert_equivalent [posts(:jonathan_sky), posts(:sam_flowers)], Post.find_tagged_with(['Very good', 'Nature'], :match_all => true, :include => :tags) | ||
| 56 | end | ||
| 57 | |||
| 58 | def test_find_tagged_with_conditions | ||
| 59 | assert_equal [], Post.find_tagged_with('"Very good", Nature', :conditions => '1=0') | ||
| 60 | end | ||
| 61 | |||
| 62 | def test_find_tagged_with_duplicates_options_hash | ||
| 63 | options = { :conditions => '1=1' }.freeze | ||
| 64 | assert_nothing_raised { Post.find_tagged_with("Nature", options) } | ||
| 65 | end | ||
| 66 | |||
| 67 | def test_find_tagged_with_exclusions | ||
| 68 | assert_equivalent [photos(:jonathan_questioning_dog), photos(:jonathan_bad_cat)], Photo.find_tagged_with("Nature", :exclude => true) | ||
| 69 | assert_equivalent [posts(:jonathan_grass), posts(:jonathan_rain), posts(:jonathan_cloudy), posts(:jonathan_still_cloudy)], Post.find_tagged_with("'Very good', Bad", :exclude => true) | ||
| 70 | end | ||
| 71 | |||
| 72 | def test_find_options_for_find_tagged_with_no_tags_returns_empty_hash | ||
| 73 | assert_equal Hash.new, Post.find_options_for_find_tagged_with("") | ||
| 74 | assert_equal Hash.new, Post.find_options_for_find_tagged_with([nil]) | ||
| 75 | end | ||
| 76 | |||
| 77 | def test_find_options_for_find_tagged_with_leaves_arguments_unchanged | ||
| 78 | original_tags = photos(:jonathan_questioning_dog).tags.dup | ||
| 79 | Photo.find_options_for_find_tagged_with(photos(:jonathan_questioning_dog).tags) | ||
| 80 | assert_equal original_tags, photos(:jonathan_questioning_dog).tags | ||
| 81 | end | ||
| 82 | |||
| 83 | def test_find_options_for_find_tagged_with_respects_custom_table_name | ||
| 84 | Tagging.table_name = "categorisations" | ||
| 85 | Tag.table_name = "categories" | ||
| 86 | |||
| 87 | options = Photo.find_options_for_find_tagged_with("Hello") | ||
| 88 | |||
| 89 | assert_no_match(/ taggings /, options[:joins]) | ||
| 90 | assert_no_match(/ tags /, options[:joins]) | ||
| 91 | |||
| 92 | assert_match(/ categorisations /, options[:joins]) | ||
| 93 | assert_match(/ categories /, options[:joins]) | ||
| 94 | ensure | ||
| 95 | Tagging.table_name = "taggings" | ||
| 96 | Tag.table_name = "tags" | ||
| 97 | end | ||
| 98 | |||
| 99 | def test_include_tags_on_find_tagged_with | ||
| 100 | assert_nothing_raised do | ||
| 101 | Photo.find_tagged_with('Nature', :include => :tags) | ||
| 102 | Photo.find_tagged_with("Nature", :include => { :taggings => :tag }) | ||
| 103 | end | ||
| 104 | end | ||
| 105 | |||
| 106 | def test_basic_tag_counts_on_class | ||
| 107 | assert_tag_counts Post.tag_counts, :good => 2, :nature => 7, :question => 1, :bad => 1 | ||
| 108 | assert_tag_counts Photo.tag_counts, :good => 1, :nature => 3, :question => 1, :bad => 1, :animal => 3 | ||
| 109 | end | ||
| 110 | |||
| 111 | def test_tag_counts_on_class_with_date_conditions | ||
| 112 | assert_tag_counts Post.tag_counts(:start_at => Date.new(2006, 8, 4)), :good => 1, :nature => 5, :question => 1, :bad => 1 | ||
| 113 | assert_tag_counts Post.tag_counts(:end_at => Date.new(2006, 8, 6)), :good => 1, :nature => 4, :question => 1 | ||
| 114 | assert_tag_counts Post.tag_counts(:start_at => Date.new(2006, 8, 5), :end_at => Date.new(2006, 8, 10)), :good => 1, :nature => 4, :bad => 1 | ||
| 115 | |||
| 116 | assert_tag_counts Photo.tag_counts(:start_at => Date.new(2006, 8, 12), :end_at => Date.new(2006, 8, 19)), :good => 1, :nature => 2, :bad => 1, :question => 1, :animal => 3 | ||
| 117 | end | ||
| 118 | |||
| 119 | def test_tag_counts_on_class_with_frequencies | ||
| 120 | assert_tag_counts Photo.tag_counts(:at_least => 2), :nature => 3, :animal => 3 | ||
| 121 | assert_tag_counts Photo.tag_counts(:at_most => 2), :good => 1, :question => 1, :bad => 1 | ||
| 122 | end | ||
| 123 | |||
| 124 | def test_tag_counts_on_class_with_frequencies_and_conditions | ||
| 125 | assert_tag_counts Photo.tag_counts(:at_least => 2, :conditions => '1=1'), :nature => 3, :animal => 3 | ||
| 126 | end | ||
| 127 | |||
| 128 | def test_tag_counts_duplicates_options_hash | ||
| 129 | options = { :at_least => 2, :conditions => '1=1' }.freeze | ||
| 130 | assert_nothing_raised { Photo.tag_counts(options) } | ||
| 131 | end | ||
| 132 | |||
| 133 | def test_tag_counts_with_limit | ||
| 134 | assert_equal 2, Photo.tag_counts(:limit => 2).size | ||
| 135 | assert_equal 1, Post.tag_counts(:at_least => 4, :limit => 2).size | ||
| 136 | end | ||
| 137 | |||
| 138 | def test_tag_counts_with_limit_and_order | ||
| 139 | assert_equal [tags(:nature), tags(:good)], Post.tag_counts(:order => 'count desc', :limit => 2) | ||
| 140 | end | ||
| 141 | |||
| 142 | def test_tag_counts_on_association | ||
| 143 | assert_tag_counts users(:jonathan).posts.tag_counts, :good => 1, :nature => 5, :question => 1 | ||
| 144 | assert_tag_counts users(:sam).posts.tag_counts, :good => 1, :nature => 2, :bad => 1 | ||
| 145 | |||
| 146 | assert_tag_counts users(:jonathan).photos.tag_counts, :animal => 3, :nature => 1, :question => 1, :bad => 1 | ||
| 147 | assert_tag_counts users(:sam).photos.tag_counts, :nature => 2, :good => 1 | ||
| 148 | end | ||
| 149 | |||
| 150 | def test_tag_counts_on_association_with_options | ||
| 151 | assert_equal [], users(:jonathan).posts.tag_counts(:conditions => '1=0') | ||
| 152 | assert_tag_counts users(:jonathan).posts.tag_counts(:at_most => 2), :good => 1, :question => 1 | ||
| 153 | end | ||
| 154 | |||
| 155 | def test_tag_counts_on_has_many_through | ||
| 156 | assert_tag_counts users(:jonathan).magazines.tag_counts, :good => 1 | ||
| 157 | end | ||
| 158 | |||
| 159 | def test_tag_counts_on_model_instance | ||
| 160 | assert_tag_counts photos(:jonathan_dog).tag_counts, :animal => 3, :nature => 3 | ||
| 161 | end | ||
| 162 | |||
| 163 | def test_tag_counts_on_model_instance_merges_conditions | ||
| 164 | assert_tag_counts photos(:jonathan_dog).tag_counts(:conditions => "tags.name = 'Crazy animal'"), :animal => 3 | ||
| 165 | end | ||
| 166 | |||
| 167 | def test_tag_counts_on_model_instance_with_no_tags | ||
| 168 | photo = Photo.create! | ||
| 169 | |||
| 170 | assert_tag_counts photo.tag_counts, {} | ||
| 171 | end | ||
| 172 | |||
| 173 | def test_tag_counts_should_sanitize_scope_conditions | ||
| 174 | Photo.send :with_scope, :find => { :conditions => ["tags.id = ?", tags(:animal).id] } do | ||
| 175 | assert_tag_counts Photo.tag_counts, :animal => 3 | ||
| 176 | end | ||
| 177 | end | ||
| 178 | |||
| 179 | def test_tag_counts_respects_custom_table_names | ||
| 180 | Tagging.table_name = "categorisations" | ||
| 181 | Tag.table_name = "categories" | ||
| 182 | |||
| 183 | options = Photo.find_options_for_tag_counts(:start_at => 2.weeks.ago, :end_at => Date.today) | ||
| 184 | sql = options.values.join(' ') | ||
| 185 | |||
| 186 | assert_no_match /taggings/, sql | ||
| 187 | assert_no_match /tags/, sql | ||
| 188 | |||
| 189 | assert_match /categorisations/, sql | ||
| 190 | assert_match /categories/, sql | ||
| 191 | ensure | ||
| 192 | Tagging.table_name = "taggings" | ||
| 193 | Tag.table_name = "tags" | ||
| 194 | end | ||
| 195 | |||
| 196 | def test_tag_list_reader | ||
| 197 | assert_equivalent ["Very good", "Nature"], posts(:jonathan_sky).tag_list | ||
| 198 | assert_equivalent ["Bad", "Crazy animal"], photos(:jonathan_bad_cat).tag_list | ||
| 199 | end | ||
| 200 | |||
| 201 | def test_reassign_tag_list | ||
| 202 | assert_equivalent ["Nature", "Question"], posts(:jonathan_rain).tag_list | ||
| 203 | posts(:jonathan_rain).taggings.reload | ||
| 204 | |||
| 205 | # Only an update of the posts table should be executed, the other two queries are for savepoints | ||
| 206 | assert_queries 3 do | ||
| 207 | posts(:jonathan_rain).update_attributes!(:tag_list => posts(:jonathan_rain).tag_list.to_s) | ||
| 208 | end | ||
| 209 | |||
| 210 | assert_equivalent ["Nature", "Question"], posts(:jonathan_rain).tag_list | ||
| 211 | end | ||
| 212 | |||
| 213 | def test_new_tags | ||
| 214 | assert_equivalent ["Very good", "Nature"], posts(:jonathan_sky).tag_list | ||
| 215 | posts(:jonathan_sky).update_attributes!(:tag_list => "#{posts(:jonathan_sky).tag_list}, One, Two") | ||
| 216 | assert_equivalent ["Very good", "Nature", "One", "Two"], posts(:jonathan_sky).tag_list | ||
| 217 | end | ||
| 218 | |||
| 219 | def test_remove_tag | ||
| 220 | assert_equivalent ["Very good", "Nature"], posts(:jonathan_sky).tag_list | ||
| 221 | posts(:jonathan_sky).update_attributes!(:tag_list => "Nature") | ||
| 222 | assert_equivalent ["Nature"], posts(:jonathan_sky).tag_list | ||
| 223 | end | ||
| 224 | |||
| 225 | def test_change_case_of_tags | ||
| 226 | original_tag_names = photos(:jonathan_questioning_dog).tag_list | ||
| 227 | photos(:jonathan_questioning_dog).update_attributes!(:tag_list => photos(:jonathan_questioning_dog).tag_list.to_s.upcase) | ||
| 228 | |||
| 229 | # The new tag list is not uppercase becuase the AR finders are not case-sensitive | ||
| 230 | # and find the old tags when re-tagging with the uppercase tags. | ||
| 231 | assert_equivalent original_tag_names, photos(:jonathan_questioning_dog).reload.tag_list | ||
| 232 | end | ||
| 233 | |||
| 234 | def test_remove_and_add_tag | ||
| 235 | assert_equivalent ["Very good", "Nature"], posts(:jonathan_sky).tag_list | ||
| 236 | posts(:jonathan_sky).update_attributes!(:tag_list => "Nature, Beautiful") | ||
| 237 | assert_equivalent ["Nature", "Beautiful"], posts(:jonathan_sky).tag_list | ||
| 238 | end | ||
| 239 | |||
| 240 | def test_tags_not_saved_if_validation_fails | ||
| 241 | assert_equivalent ["Very good", "Nature"], posts(:jonathan_sky).tag_list | ||
| 242 | assert !posts(:jonathan_sky).update_attributes(:tag_list => "One, Two", :text => "") | ||
| 243 | assert_equivalent ["Very good", "Nature"], Post.find(posts(:jonathan_sky).id).tag_list | ||
| 244 | end | ||
| 245 | |||
| 246 | def test_tag_list_accessors_on_new_record | ||
| 247 | p = Post.new(:text => 'Test') | ||
| 248 | |||
| 249 | assert p.tag_list.blank? | ||
| 250 | p.tag_list = "One, Two" | ||
| 251 | assert_equal "One, Two", p.tag_list.to_s | ||
| 252 | end | ||
| 253 | |||
| 254 | def test_clear_tag_list_with_nil | ||
| 255 | p = photos(:jonathan_questioning_dog) | ||
| 256 | |||
| 257 | assert !p.tag_list.blank? | ||
| 258 | assert p.update_attributes(:tag_list => nil) | ||
| 259 | assert p.tag_list.blank? | ||
| 260 | |||
| 261 | assert p.reload.tag_list.blank? | ||
| 262 | end | ||
| 263 | |||
| 264 | def test_clear_tag_list_with_string | ||
| 265 | p = photos(:jonathan_questioning_dog) | ||
| 266 | |||
| 267 | assert !p.tag_list.blank? | ||
| 268 | assert p.update_attributes(:tag_list => ' ') | ||
| 269 | assert p.tag_list.blank? | ||
| 270 | |||
| 271 | assert p.reload.tag_list.blank? | ||
| 272 | end | ||
| 273 | |||
| 274 | def test_tag_list_reset_on_reload | ||
| 275 | p = photos(:jonathan_questioning_dog) | ||
| 276 | assert !p.tag_list.blank? | ||
| 277 | p.tag_list = nil | ||
| 278 | assert p.tag_list.blank? | ||
| 279 | assert !p.reload.tag_list.blank? | ||
| 280 | end | ||
| 281 | |||
| 282 | def test_instance_tag_counts | ||
| 283 | assert_tag_counts posts(:jonathan_sky).tag_counts, :good => 2, :nature => 7 | ||
| 284 | end | ||
| 285 | |||
| 286 | def test_tag_list_populated_when_cache_nil | ||
| 287 | assert_nil posts(:jonathan_sky).cached_tag_list | ||
| 288 | posts(:jonathan_sky).save! | ||
| 289 | assert_equal posts(:jonathan_sky).tag_list.to_s, posts(:jonathan_sky).cached_tag_list | ||
| 290 | end | ||
| 291 | |||
| 292 | def test_cached_tag_list_used | ||
| 293 | posts(:jonathan_sky).save! | ||
| 294 | posts(:jonathan_sky).reload | ||
| 295 | |||
| 296 | assert_no_queries do | ||
| 297 | assert_equivalent ["Very good", "Nature"], posts(:jonathan_sky).tag_list | ||
| 298 | end | ||
| 299 | end | ||
| 300 | |||
| 301 | def test_cached_tag_list_not_used | ||
| 302 | # Load fixture and column information | ||
| 303 | posts(:jonathan_sky).taggings(:reload) | ||
| 304 | |||
| 305 | assert_queries 1 do | ||
| 306 | # Tags association will be loaded | ||
| 307 | posts(:jonathan_sky).tag_list | ||
| 308 | end | ||
| 309 | end | ||
| 310 | |||
| 311 | def test_cached_tag_list_updated | ||
| 312 | assert_nil posts(:jonathan_sky).cached_tag_list | ||
| 313 | posts(:jonathan_sky).save! | ||
| 314 | assert_equivalent ["Very good", "Nature"], TagList.from(posts(:jonathan_sky).cached_tag_list) | ||
| 315 | posts(:jonathan_sky).update_attributes!(:tag_list => "None") | ||
| 316 | |||
| 317 | assert_equal 'None', posts(:jonathan_sky).cached_tag_list | ||
| 318 | assert_equal 'None', posts(:jonathan_sky).reload.cached_tag_list | ||
| 319 | end | ||
| 320 | |||
| 321 | def test_clearing_cached_tag_list | ||
| 322 | # Generate the cached tag list | ||
| 323 | posts(:jonathan_sky).save! | ||
| 324 | |||
| 325 | posts(:jonathan_sky).update_attributes!(:tag_list => "") | ||
| 326 | assert_equal "", posts(:jonathan_sky).cached_tag_list | ||
| 327 | end | ||
| 328 | |||
| 329 | def test_find_tagged_with_using_sti | ||
| 330 | special_post = SpecialPost.create!(:text => "Test", :tag_list => "Random") | ||
| 331 | |||
| 332 | assert_equal [special_post], SpecialPost.find_tagged_with("Random") | ||
| 333 | assert Post.find_tagged_with("Random").include?(special_post) | ||
| 334 | end | ||
| 335 | |||
| 336 | def test_tag_counts_using_sti | ||
| 337 | SpecialPost.create!(:text => "Test", :tag_list => "Nature") | ||
| 338 | |||
| 339 | assert_tag_counts SpecialPost.tag_counts, :nature => 1 | ||
| 340 | end | ||
| 341 | |||
| 342 | def test_case_insensitivity | ||
| 343 | assert_difference "Tag.count", 1 do | ||
| 344 | Post.create!(:text => "Test", :tag_list => "one") | ||
| 345 | Post.create!(:text => "Test", :tag_list => "One") | ||
| 346 | end | ||
| 347 | |||
| 348 | assert_equal Post.find_tagged_with("Nature"), Post.find_tagged_with("nature") | ||
| 349 | end | ||
| 350 | |||
| 351 | def test_tag_not_destroyed_when_unused | ||
| 352 | posts(:jonathan_sky).tag_list.add("Random") | ||
| 353 | posts(:jonathan_sky).save! | ||
| 354 | |||
| 355 | assert_no_difference 'Tag.count' do | ||
| 356 | posts(:jonathan_sky).tag_list.remove("Random") | ||
| 357 | posts(:jonathan_sky).save! | ||
| 358 | end | ||
| 359 | end | ||
| 360 | |||
| 361 | def test_tag_destroyed_when_unused | ||
| 362 | Tag.destroy_unused = true | ||
| 363 | |||
| 364 | posts(:jonathan_sky).tag_list.add("Random") | ||
| 365 | posts(:jonathan_sky).save! | ||
| 366 | |||
| 367 | assert_difference 'Tag.count', -1 do | ||
| 368 | posts(:jonathan_sky).tag_list.remove("Random") | ||
| 369 | posts(:jonathan_sky).save! | ||
| 370 | end | ||
| 371 | ensure | ||
| 372 | Tag.destroy_unused = false | ||
| 373 | end | ||
| 374 | end | ||
| 375 | |||
| 376 | class ActsAsTaggableOnSteroidsFormTest < ActiveSupport::TestCase | ||
| 377 | include ActionView::Helpers::FormHelper | ||
| 378 | |||
| 379 | def test_tag_list_contents | ||
| 380 | fields_for :post, posts(:jonathan_sky) do |f| | ||
| 381 | assert_match /Nature, Very good/, f.text_field(:tag_list) | ||
| 382 | end | ||
| 383 | end | ||
| 384 | end | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/magazine.rb b/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/magazine.rb deleted file mode 100644 index 554afe4..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/magazine.rb +++ /dev/null | |||
| @@ -1,3 +0,0 @@ | |||
| 1 | class Magazine < ActiveRecord::Base | ||
| 2 | acts_as_taggable | ||
| 3 | end | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/magazines.yml b/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/magazines.yml deleted file mode 100644 index 7124fd9..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/magazines.yml +++ /dev/null | |||
| @@ -1,5 +0,0 @@ | |||
| 1 | ruby: | ||
| 2 | name: Ruby | ||
| 3 | |||
| 4 | rails: | ||
| 5 | name: Rails | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/photo.rb b/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/photo.rb deleted file mode 100644 index 224957f..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/photo.rb +++ /dev/null | |||
| @@ -1,8 +0,0 @@ | |||
| 1 | class Photo < ActiveRecord::Base | ||
| 2 | acts_as_taggable | ||
| 3 | |||
| 4 | belongs_to :user | ||
| 5 | end | ||
| 6 | |||
| 7 | class SpecialPhoto < Photo | ||
| 8 | end | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/photos.yml b/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/photos.yml deleted file mode 100644 index bf078cf..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/photos.yml +++ /dev/null | |||
| @@ -1,19 +0,0 @@ | |||
| 1 | jonathan_dog: | ||
| 2 | user: jonathan | ||
| 3 | title: A small dog | ||
| 4 | |||
| 5 | jonathan_questioning_dog: | ||
| 6 | user: jonathan | ||
| 7 | title: What does this dog want? | ||
| 8 | |||
| 9 | jonathan_bad_cat: | ||
| 10 | user: jonathan | ||
| 11 | title: Bad cat | ||
| 12 | |||
| 13 | sam_flower: | ||
| 14 | user: sam | ||
| 15 | title: Flower | ||
| 16 | |||
| 17 | sam_sky: | ||
| 18 | user: sam | ||
| 19 | title: Sky | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/post.rb b/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/post.rb deleted file mode 100644 index bee100a..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/post.rb +++ /dev/null | |||
| @@ -1,7 +0,0 @@ | |||
| 1 | class Post < ActiveRecord::Base | ||
| 2 | acts_as_taggable | ||
| 3 | |||
| 4 | belongs_to :user | ||
| 5 | |||
| 6 | validates_presence_of :text | ||
| 7 | end | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/posts.yml b/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/posts.yml deleted file mode 100644 index 50e91bc..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/posts.yml +++ /dev/null | |||
| @@ -1,27 +0,0 @@ | |||
| 1 | jonathan_sky: | ||
| 2 | user: jonathan | ||
| 3 | text: The sky is particularly blue today | ||
| 4 | |||
| 5 | jonathan_grass: | ||
| 6 | user: jonathan | ||
| 7 | text: The grass seems very green | ||
| 8 | |||
| 9 | jonathan_rain: | ||
| 10 | user: jonathan | ||
| 11 | text: Why does the rain fall? | ||
| 12 | |||
| 13 | jonathan_cloudy: | ||
| 14 | user: jonathan | ||
| 15 | text: Is it cloudy? | ||
| 16 | |||
| 17 | jonathan_still_cloudy: | ||
| 18 | user: jonathan | ||
| 19 | text: Is it still cloudy? | ||
| 20 | |||
| 21 | sam_ground: | ||
| 22 | user: sam | ||
| 23 | text: The ground is looking too brown | ||
| 24 | |||
| 25 | sam_flowers: | ||
| 26 | user: sam | ||
| 27 | text: Why are the flowers dead? | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/special_post.rb b/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/special_post.rb deleted file mode 100644 index 366a0d5..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/special_post.rb +++ /dev/null | |||
| @@ -1,2 +0,0 @@ | |||
| 1 | class SpecialPost < Post | ||
| 2 | end | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/subscription.rb b/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/subscription.rb deleted file mode 100644 index e975cb7..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/subscription.rb +++ /dev/null | |||
| @@ -1,4 +0,0 @@ | |||
| 1 | class Subscription < ActiveRecord::Base | ||
| 2 | belongs_to :user | ||
| 3 | belongs_to :magazine | ||
| 4 | end | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/subscriptions.yml b/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/subscriptions.yml deleted file mode 100644 index d294e51..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/subscriptions.yml +++ /dev/null | |||
| @@ -1,3 +0,0 @@ | |||
| 1 | jonathan_rails: | ||
| 2 | user: jonathan | ||
| 3 | magazine: ruby | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/taggings.yml b/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/taggings.yml deleted file mode 100644 index 1193b56..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/taggings.yml +++ /dev/null | |||
| @@ -1,107 +0,0 @@ | |||
| 1 | # Posts | ||
| 2 | jonathan_sky_good: | ||
| 3 | tag: good | ||
| 4 | taggable: jonathan_sky (Post) | ||
| 5 | created_at: 2006-08-01 | ||
| 6 | |||
| 7 | jonathan_sky_nature: | ||
| 8 | tag: nature | ||
| 9 | taggable: jonathan_sky (Post) | ||
| 10 | created_at: 2006-08-02 | ||
| 11 | |||
| 12 | jonathan_grass_nature: | ||
| 13 | tag: nature | ||
| 14 | taggable: jonathan_grass (Post) | ||
| 15 | created_at: 2006-08-03 | ||
| 16 | |||
| 17 | jonathan_rain_question: | ||
| 18 | tag: question | ||
| 19 | taggable: jonathan_rain (Post) | ||
| 20 | created_at: 2006-08-04 | ||
| 21 | |||
| 22 | jonathan_rain_nature: | ||
| 23 | tag: nature | ||
| 24 | taggable: jonathan_rain (Post) | ||
| 25 | created_at: 2006-08-05 | ||
| 26 | |||
| 27 | jonathan_cloudy_nature: | ||
| 28 | tag: nature | ||
| 29 | taggable: jonathan_cloudy (Post) | ||
| 30 | created_at: 2006-08-06 | ||
| 31 | |||
| 32 | jonathan_still_cloudy_nature: | ||
| 33 | tag: nature | ||
| 34 | taggable: jonathan_still_cloudy (Post) | ||
| 35 | created_at: 2006-08-07 | ||
| 36 | |||
| 37 | sam_ground_nature: | ||
| 38 | tag: nature | ||
| 39 | taggable: sam_ground (Post) | ||
| 40 | created_at: 2006-08-08 | ||
| 41 | |||
| 42 | sam_ground_bad: | ||
| 43 | tag: bad | ||
| 44 | taggable: sam_ground (Post) | ||
| 45 | created_at: 2006-08-09 | ||
| 46 | |||
| 47 | sam_flowers_good: | ||
| 48 | tag: good | ||
| 49 | taggable: sam_flowers (Post) | ||
| 50 | created_at: 2006-08-10 | ||
| 51 | |||
| 52 | sam_flowers_nature: | ||
| 53 | tag: nature | ||
| 54 | taggable: sam_flowers (Post) | ||
| 55 | created_at: 2006-08-11 | ||
| 56 | |||
| 57 | # Photos | ||
| 58 | jonathan_dog_animal: | ||
| 59 | tag: animal | ||
| 60 | taggable: jonathan_dog (Photo) | ||
| 61 | created_at: 2006-08-12 | ||
| 62 | |||
| 63 | jonathan_dog_nature: | ||
| 64 | tag: nature | ||
| 65 | taggable: jonathan_dog (Photo) | ||
| 66 | created_at: 2006-08-13 | ||
| 67 | |||
| 68 | jonathan_questioning_dog_animal: | ||
| 69 | tag: animal | ||
| 70 | taggable: jonathan_questioning_dog (Photo) | ||
| 71 | created_at: 2006-08-14 | ||
| 72 | |||
| 73 | jonathan_questioning_dog_question: | ||
| 74 | tag: question | ||
| 75 | taggable: jonathan_questioning_dog (Photo) | ||
| 76 | created_at: 2006-08-15 | ||
| 77 | |||
| 78 | jonathan_bad_cat_bad: | ||
| 79 | tag: bad | ||
| 80 | taggable: jonathan_bad_cat (Photo) | ||
| 81 | created_at: 2006-08-16 | ||
| 82 | |||
| 83 | jonathan_bad_cat_animal: | ||
| 84 | tag: animal | ||
| 85 | taggable: jonathan_bad_cat (Photo) | ||
| 86 | created_at: 2006-08-17 | ||
| 87 | |||
| 88 | sam_flower_nature: | ||
| 89 | tag: nature | ||
| 90 | taggable: sam_flower (Photo) | ||
| 91 | created_at: 2006-08-18 | ||
| 92 | |||
| 93 | sam_flower_good: | ||
| 94 | tag: good | ||
| 95 | taggable: sam_flower (Photo) | ||
| 96 | created_at: 2006-08-19 | ||
| 97 | |||
| 98 | sam_sky_nature: | ||
| 99 | tag: nature | ||
| 100 | taggable: sam_sky (Photo) | ||
| 101 | created_at: 2006-08-20 | ||
| 102 | |||
| 103 | # Magazines | ||
| 104 | ruby_good: | ||
| 105 | tag: good | ||
| 106 | taggable: ruby (Magazine) | ||
| 107 | created_at: 2007-08-25 | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/tags.yml b/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/tags.yml deleted file mode 100644 index a3c2aa5..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/tags.yml +++ /dev/null | |||
| @@ -1,14 +0,0 @@ | |||
| 1 | good: | ||
| 2 | name: Very good | ||
| 3 | |||
| 4 | bad: | ||
| 5 | name: Bad | ||
| 6 | |||
| 7 | nature: | ||
| 8 | name: Nature | ||
| 9 | |||
| 10 | question: | ||
| 11 | name: Question | ||
| 12 | |||
| 13 | animal: | ||
| 14 | name: Crazy animal | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/user.rb b/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/user.rb deleted file mode 100644 index 8c0f787..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/user.rb +++ /dev/null | |||
| @@ -1,7 +0,0 @@ | |||
| 1 | class User < ActiveRecord::Base | ||
| 2 | has_many :posts | ||
| 3 | has_many :photos | ||
| 4 | |||
| 5 | has_many :subscriptions | ||
| 6 | has_many :magazines, :through => :subscriptions | ||
| 7 | end | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/users.yml b/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/users.yml deleted file mode 100644 index e6f22d3..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/test/fixtures/users.yml +++ /dev/null | |||
| @@ -1,5 +0,0 @@ | |||
| 1 | jonathan: | ||
| 2 | name: Jonathan | ||
| 3 | |||
| 4 | sam: | ||
| 5 | name: Sam | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/test/tag_list_test.rb b/vendor/plugins/acts_as_taggable_on_steroids/test/tag_list_test.rb deleted file mode 100644 index 17d4ab9..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/test/tag_list_test.rb +++ /dev/null | |||
| @@ -1,119 +0,0 @@ | |||
| 1 | require File.dirname(__FILE__) + '/abstract_unit' | ||
| 2 | |||
| 3 | class TagListTest < ActiveSupport::TestCase | ||
| 4 | def test_from_leaves_string_unchanged | ||
| 5 | tags = '"One ", Two' | ||
| 6 | original = tags.dup | ||
| 7 | TagList.from(tags) | ||
| 8 | assert_equal tags, original | ||
| 9 | end | ||
| 10 | |||
| 11 | def test_from_single_name | ||
| 12 | assert_equal %w(Fun), TagList.from("Fun") | ||
| 13 | assert_equal %w(Fun), TagList.from('"Fun"') | ||
| 14 | end | ||
| 15 | |||
| 16 | def test_from_blank | ||
| 17 | assert_equal [], TagList.from(nil) | ||
| 18 | assert_equal [], TagList.from("") | ||
| 19 | end | ||
| 20 | |||
| 21 | def test_from_single_quoted_tag | ||
| 22 | assert_equal ['with, comma'], TagList.from('"with, comma"') | ||
| 23 | end | ||
| 24 | |||
| 25 | def test_spaces_do_not_delineate | ||
| 26 | assert_equal ['A B', 'C'], TagList.from('A B, C') | ||
| 27 | end | ||
| 28 | |||
| 29 | def test_from_multiple_tags | ||
| 30 | assert_equivalent %w(Alpha Beta Delta Gamma), TagList.from("Alpha, Beta, Delta, Gamma") | ||
| 31 | end | ||
| 32 | |||
| 33 | def test_from_multiple_tags_with_quotes | ||
| 34 | assert_equivalent %w(Alpha Beta Delta Gamma), TagList.from('Alpha, "Beta", Gamma , "Delta"') | ||
| 35 | end | ||
| 36 | |||
| 37 | def test_from_with_single_quotes | ||
| 38 | assert_equivalent ['A B', 'C'], TagList.from("'A B', C") | ||
| 39 | end | ||
| 40 | |||
| 41 | def test_from_multiple_tags_with_quote_and_commas | ||
| 42 | assert_equivalent ['Alpha, Beta', 'Delta', 'Gamma, something'], TagList.from('"Alpha, Beta", Delta, "Gamma, something"') | ||
| 43 | end | ||
| 44 | |||
| 45 | def test_from_with_inner_quotes | ||
| 46 | assert_equivalent ["House", "Drum 'n' Bass", "Trance"], TagList.from("House, Drum 'n' Bass, Trance") | ||
| 47 | assert_equivalent ["House", "Drum'n'Bass", "Trance"], TagList.from("House, Drum'n'Bass, Trance") | ||
| 48 | end | ||
| 49 | |||
| 50 | def test_from_removes_white_space | ||
| 51 | assert_equivalent %w(Alpha Beta), TagList.from('" Alpha ", "Beta "') | ||
| 52 | assert_equivalent %w(Alpha Beta), TagList.from(' Alpha, Beta ') | ||
| 53 | end | ||
| 54 | |||
| 55 | def test_from_and_new_treat_both_accept_arrays | ||
| 56 | tags = ["One", "Two"] | ||
| 57 | |||
| 58 | assert_equal TagList.from(tags), TagList.new(tags) | ||
| 59 | end | ||
| 60 | |||
| 61 | def test_alternative_delimiter | ||
| 62 | TagList.delimiter = " " | ||
| 63 | |||
| 64 | assert_equal %w(One Two), TagList.from("One Two") | ||
| 65 | assert_equal ['One two', 'three', 'four'], TagList.from('"One two" three four') | ||
| 66 | ensure | ||
| 67 | TagList.delimiter = "," | ||
| 68 | end | ||
| 69 | |||
| 70 | def test_duplicate_tags_removed | ||
| 71 | assert_equal %w(One), TagList.from("One, One") | ||
| 72 | end | ||
| 73 | |||
| 74 | def test_to_s_with_commas | ||
| 75 | assert_equal "Question, Crazy Animal", TagList.new("Question", "Crazy Animal").to_s | ||
| 76 | end | ||
| 77 | |||
| 78 | def test_to_s_with_alternative_delimiter | ||
| 79 | TagList.delimiter = " " | ||
| 80 | |||
| 81 | assert_equal '"Crazy Animal" Question', TagList.new("Crazy Animal", "Question").to_s | ||
| 82 | ensure | ||
| 83 | TagList.delimiter = "," | ||
| 84 | end | ||
| 85 | |||
| 86 | def test_add | ||
| 87 | tag_list = TagList.new("One") | ||
| 88 | assert_equal %w(One), tag_list | ||
| 89 | |||
| 90 | assert_equal %w(One Two), tag_list.add("Two") | ||
| 91 | assert_equal %w(One Two Three), tag_list.add(["Three"]) | ||
| 92 | end | ||
| 93 | |||
| 94 | def test_remove | ||
| 95 | tag_list = TagList.new("One", "Two") | ||
| 96 | assert_equal %w(Two), tag_list.remove("One") | ||
| 97 | assert_equal %w(), tag_list.remove(["Two"]) | ||
| 98 | end | ||
| 99 | |||
| 100 | def test_new_with_parsing | ||
| 101 | assert_equal %w(One Two), TagList.new("One, Two", :parse => true) | ||
| 102 | end | ||
| 103 | |||
| 104 | def test_add_with_parsing | ||
| 105 | assert_equal %w(One Two), TagList.new.add("One, Two", :parse => true) | ||
| 106 | end | ||
| 107 | |||
| 108 | def test_remove_with_parsing | ||
| 109 | tag_list = TagList.from("Three, Four, Five") | ||
| 110 | assert_equal %w(Four), tag_list.remove("Three, Five", :parse => true) | ||
| 111 | end | ||
| 112 | |||
| 113 | def test_toggle | ||
| 114 | tag_list = TagList.new("One", "Two") | ||
| 115 | assert_equal %w(One Three), tag_list.toggle("Two", "Three") | ||
| 116 | assert_equal %w(), tag_list.toggle("One", "Three") | ||
| 117 | assert_equal %w(Four), tag_list.toggle("Four") | ||
| 118 | end | ||
| 119 | end | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/test/tag_test.rb b/vendor/plugins/acts_as_taggable_on_steroids/test/tag_test.rb deleted file mode 100644 index 97dd249..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/test/tag_test.rb +++ /dev/null | |||
| @@ -1,62 +0,0 @@ | |||
| 1 | require File.dirname(__FILE__) + '/abstract_unit' | ||
| 2 | |||
| 3 | class TagTest < ActiveSupport::TestCase | ||
| 4 | def test_name_required | ||
| 5 | t = Tag.create | ||
| 6 | assert_match /blank/, t.errors[:name].to_s | ||
| 7 | end | ||
| 8 | |||
| 9 | def test_name_unique | ||
| 10 | t = Tag.create!(:name => "My tag") | ||
| 11 | duplicate = t.clone | ||
| 12 | |||
| 13 | assert !duplicate.save | ||
| 14 | assert_match /taken/, duplicate.errors[:name].to_s | ||
| 15 | end | ||
| 16 | |||
| 17 | def test_taggings | ||
| 18 | assert_equivalent [taggings(:jonathan_sky_good), taggings(:sam_flowers_good), taggings(:sam_flower_good), taggings(:ruby_good)], tags(:good).taggings | ||
| 19 | assert_equivalent [taggings(:sam_ground_bad), taggings(:jonathan_bad_cat_bad)], tags(:bad).taggings | ||
| 20 | end | ||
| 21 | |||
| 22 | def test_to_s | ||
| 23 | assert_equal tags(:good).name, tags(:good).to_s | ||
| 24 | end | ||
| 25 | |||
| 26 | def test_equality | ||
| 27 | assert_equal tags(:good), tags(:good) | ||
| 28 | assert_equal Tag.find(tags(:good).id), Tag.find(tags(:good).id) | ||
| 29 | assert_equal Tag.new(:name => 'A'), Tag.new(:name => 'A') | ||
| 30 | assert_not_equal Tag.new(:name => 'A'), Tag.new(:name => 'B') | ||
| 31 | end | ||
| 32 | |||
| 33 | def test_taggings_removed_when_tag_destroyed | ||
| 34 | assert_difference "Tagging.count", -Tagging.count(:conditions => { :tag_id => tags(:good).id }) do | ||
| 35 | assert tags(:good).destroy | ||
| 36 | end | ||
| 37 | end | ||
| 38 | |||
| 39 | def test_all_counts | ||
| 40 | assert_tag_counts Tag.counts, :good => 4, :bad => 2, :nature => 10, :question => 2, :animal => 3 | ||
| 41 | end | ||
| 42 | |||
| 43 | def test_all_counts_with_string_conditions | ||
| 44 | assert_tag_counts Tag.counts(:conditions => 'taggings.created_at >= \'2006-08-15\''), | ||
| 45 | :question => 1, :bad => 1, :animal => 1, :nature => 2, :good => 2 | ||
| 46 | end | ||
| 47 | |||
| 48 | def test_all_counts_with_array_conditions | ||
| 49 | assert_tag_counts Tag.counts(:conditions => ['taggings.created_at >= ?', '2006-08-15']), | ||
| 50 | :question => 1, :bad => 1, :animal => 1, :nature => 2, :good => 2 | ||
| 51 | end | ||
| 52 | |||
| 53 | def test_all_counts_with_hash_conditions | ||
| 54 | tag_counts = Tag.counts( | ||
| 55 | :conditions => { | ||
| 56 | :taggings => { :created_at => (DateTime.parse('2006-08-14 23:59') .. DateTime.parse('4000-01-01')) } | ||
| 57 | } | ||
| 58 | ) | ||
| 59 | |||
| 60 | assert_tag_counts tag_counts, :question => 1, :bad => 1, :animal => 1, :nature => 2, :good => 2 | ||
| 61 | end | ||
| 62 | end | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/test/tagging_test.rb b/vendor/plugins/acts_as_taggable_on_steroids/test/tagging_test.rb deleted file mode 100644 index bea4583..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/test/tagging_test.rb +++ /dev/null | |||
| @@ -1,11 +0,0 @@ | |||
| 1 | require File.dirname(__FILE__) + '/abstract_unit' | ||
| 2 | |||
| 3 | class TaggingTest < ActiveSupport::TestCase | ||
| 4 | def test_tag | ||
| 5 | assert_equal tags(:good), taggings(:jonathan_sky_good).tag | ||
| 6 | end | ||
| 7 | |||
| 8 | def test_taggable | ||
| 9 | assert_equal posts(:jonathan_sky), taggings(:jonathan_sky_good).taggable | ||
| 10 | end | ||
| 11 | end | ||
diff --git a/vendor/plugins/acts_as_taggable_on_steroids/test/tags_helper_test.rb b/vendor/plugins/acts_as_taggable_on_steroids/test/tags_helper_test.rb deleted file mode 100644 index c482909..0000000 --- a/vendor/plugins/acts_as_taggable_on_steroids/test/tags_helper_test.rb +++ /dev/null | |||
| @@ -1,25 +0,0 @@ | |||
| 1 | require File.dirname(__FILE__) + '/abstract_unit' | ||
| 2 | |||
| 3 | class TagsHelperTest < ActiveSupport::TestCase | ||
| 4 | include TagsHelper | ||
| 5 | |||
| 6 | def test_tag_cloud | ||
| 7 | cloud_elements = [] | ||
| 8 | |||
| 9 | tag_cloud Post.tag_counts, %w(css1 css2 css3 css4) do |tag, css_class| | ||
| 10 | cloud_elements << [tag, css_class] | ||
| 11 | end | ||
| 12 | |||
| 13 | assert cloud_elements.include?([tags(:good), "css2"]) | ||
| 14 | assert cloud_elements.include?([tags(:bad), "css1"]) | ||
| 15 | assert cloud_elements.include?([tags(:nature), "css4"]) | ||
| 16 | assert cloud_elements.include?([tags(:question), "css1"]) | ||
| 17 | assert_equal 4, cloud_elements.size | ||
| 18 | end | ||
| 19 | |||
| 20 | def test_tag_cloud_when_no_tags | ||
| 21 | tag_cloud SpecialPost.tag_counts, %w(css1) do | ||
| 22 | assert false, "tag_cloud should not yield" | ||
| 23 | end | ||
| 24 | end | ||
| 25 | end | ||
diff --git a/vendor/plugins/awesome_nested_set/.autotest b/vendor/plugins/awesome_nested_set/.autotest deleted file mode 100644 index 54518a4..0000000 --- a/vendor/plugins/awesome_nested_set/.autotest +++ /dev/null | |||
| @@ -1,13 +0,0 @@ | |||
| 1 | Autotest.add_hook :initialize do |at| | ||
| 2 | at.clear_mappings | ||
| 3 | |||
| 4 | at.add_mapping %r%^lib/(.*)\.rb$% do |_, m| | ||
| 5 | at.files_matching %r%^test/#{m[1]}_test.rb$% | ||
| 6 | end | ||
| 7 | |||
| 8 | at.add_mapping(%r%^test/.*\.rb$%) {|filename, _| filename } | ||
| 9 | |||
| 10 | at.add_mapping %r%^test/fixtures/(.*)s.yml% do |_, _| | ||
| 11 | at.files_matching %r%^test/.*\.rb$% | ||
| 12 | end | ||
| 13 | end \ No newline at end of file | ||
diff --git a/vendor/plugins/awesome_nested_set/MIT-LICENSE b/vendor/plugins/awesome_nested_set/MIT-LICENSE deleted file mode 100644 index 570ecf8..0000000 --- a/vendor/plugins/awesome_nested_set/MIT-LICENSE +++ /dev/null | |||
| @@ -1,20 +0,0 @@ | |||
| 1 | Copyright (c) 2007 [name of plugin creator] | ||
| 2 | |||
| 3 | Permission is hereby granted, free of charge, to any person obtaining | ||
| 4 | a copy of this software and associated documentation files (the | ||
| 5 | "Software"), to deal in the Software without restriction, including | ||
| 6 | without limitation the rights to use, copy, modify, merge, publish, | ||
| 7 | distribute, sublicense, and/or sell copies of the Software, and to | ||
| 8 | permit persons to whom the Software is furnished to do so, subject to | ||
| 9 | the following conditions: | ||
| 10 | |||
| 11 | The above copyright notice and this permission notice shall be | ||
| 12 | included in all copies or substantial portions of the Software. | ||
| 13 | |||
| 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
| 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
| 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
| 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
| 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
| 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
| 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
diff --git a/vendor/plugins/awesome_nested_set/README.rdoc b/vendor/plugins/awesome_nested_set/README.rdoc deleted file mode 100644 index 884016d..0000000 --- a/vendor/plugins/awesome_nested_set/README.rdoc +++ /dev/null | |||
| @@ -1,79 +0,0 @@ | |||
| 1 | = AwesomeNestedSet | ||
| 2 | |||
| 3 | Awesome Nested Set is an implementation of the nested set pattern for ActiveRecord models. It is replacement for acts_as_nested_set and BetterNestedSet, but awesomer. It supports Rails 2.1 and later. | ||
| 4 | |||
| 5 | == What makes this so awesome? | ||
| 6 | |||
| 7 | This is a new implementation of nested set based off of BetterNestedSet that fixes some bugs, removes tons of duplication, adds a few useful methods, and adds STI support. | ||
| 8 | |||
| 9 | == Installation | ||
| 10 | |||
| 11 | Install as a plugin: | ||
| 12 | |||
| 13 | script/plugin install git://github.com/collectiveidea/awesome_nested_set.git | ||
| 14 | |||
| 15 | == Usage | ||
| 16 | |||
| 17 | To make use of awesome_nested_set, your model needs to have 3 fields: lft, rgt, and parent_id: | ||
| 18 | |||
| 19 | class CreateCategories < ActiveRecord::Migration | ||
| 20 | def self.up | ||
| 21 | create_table :categories do |t| | ||
| 22 | t.string :name | ||
| 23 | t.integer :parent_id | ||
| 24 | t.integer :lft | ||
| 25 | t.integer :rgt | ||
| 26 | end | ||
| 27 | end | ||
| 28 | |||
| 29 | def self.down | ||
| 30 | drop_table :categories | ||
| 31 | end | ||
| 32 | end | ||
| 33 | |||
| 34 | Enable the nested set functionality by declaring acts_as_nested_set on your model | ||
| 35 | |||
| 36 | class Category < ActiveRecord::Base | ||
| 37 | acts_as_nested_set | ||
| 38 | end | ||
| 39 | |||
| 40 | Run `rake rdoc` to generate the API docs and see CollectiveIdea::Acts::NestedSet::SingletonMethods for more info. | ||
| 41 | |||
| 42 | == View Helper | ||
| 43 | |||
| 44 | The view helper is called #nested_set_options. | ||
| 45 | |||
| 46 | Example usage: | ||
| 47 | |||
| 48 | <%= f.select :parent_id, nested_set_options(Category, @category) {|i| "#{'-' * i.level} #{i.name}" } %> | ||
| 49 | |||
| 50 | <%= select_tag 'parent_id', options_for_select(nested_set_options(Category) {|i| "#{'-' * i.level} #{i.name}" } ) %> | ||
| 51 | |||
| 52 | See CollectiveIdea::Acts::NestedSet::Helper for more information about the helpers. | ||
| 53 | |||
| 54 | == References | ||
| 55 | |||
| 56 | You can learn more about nested sets at: | ||
| 57 | |||
| 58 | http://www.dbmsmag.com/9603d06.html | ||
| 59 | http://threebit.net/tutorials/nestedset/tutorial1.html | ||
| 60 | http://api.rubyonrails.com/classes/ActiveRecord/Acts/NestedSet/ClassMethods.html | ||
| 61 | http://opensource.symetrie.com/trac/better_nested_set/ | ||
| 62 | |||
| 63 | == How to contribute | ||
| 64 | |||
| 65 | If you find what you might think is a bug: | ||
| 66 | |||
| 67 | 1. Check the GitHub issue tracker to see if anyone else has had the same issue. | ||
| 68 | http://github.com/collectiveidea/awesome_nested_set/issues/ | ||
| 69 | 2. If you don't see anything, create an issue with information on how to reproduce it. | ||
| 70 | |||
| 71 | If you want to contribute an enhancement or a fix: | ||
| 72 | |||
| 73 | 1. Fork the project on github. | ||
| 74 | http://github.com/collectiveidea/awesome_nested_set/ | ||
| 75 | 2. Make your changes with tests. | ||
| 76 | 3. Commit the changes without making changes to the Rakefile, VERSION, or any other files that aren't related to your enhancement or fix | ||
| 77 | 4. Send a pull request. | ||
| 78 | |||
| 79 | Copyright ©2008 Collective Idea, released under the MIT license \ No newline at end of file | ||
diff --git a/vendor/plugins/awesome_nested_set/Rakefile b/vendor/plugins/awesome_nested_set/Rakefile deleted file mode 100644 index ce70813..0000000 --- a/vendor/plugins/awesome_nested_set/Rakefile +++ /dev/null | |||
| @@ -1,54 +0,0 @@ | |||
| 1 | begin | ||
| 2 | require 'jeweler' | ||
| 3 | rescue LoadError | ||
| 4 | puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com" | ||
| 5 | exit 1 | ||
| 6 | end | ||
| 7 | require 'rake/testtask' | ||
| 8 | require 'rake/rdoctask' | ||
| 9 | require 'rcov/rcovtask' | ||
| 10 | require "load_multi_rails_rake_tasks" | ||
| 11 | |||
| 12 | Jeweler::Tasks.new do |s| | ||
| 13 | s.name = "awesome_nested_set" | ||
| 14 | s.summary = "An awesome nested set implementation for Active Record" | ||
| 15 | s.description = s.summary | ||
| 16 | s.email = "info@collectiveidea.com" | ||
| 17 | s.homepage = "http://github.com/collectiveidea/awesome_nested_set" | ||
| 18 | s.authors = ["Brandon Keepers", "Daniel Morrison"] | ||
| 19 | s.add_dependency "activerecord", ['>= 1.1'] | ||
| 20 | s.has_rdoc = true | ||
| 21 | s.extra_rdoc_files = [ "README.rdoc"] | ||
| 22 | s.rdoc_options = ["--main", "README.rdoc", "--inline-source", "--line-numbers"] | ||
| 23 | s.test_files = Dir['test/**/*.{yml,rb}'] | ||
| 24 | end | ||
| 25 | |||
| 26 | desc 'Default: run unit tests.' | ||
| 27 | task :default => :test | ||
| 28 | |||
| 29 | desc 'Test the awesome_nested_set plugin.' | ||
| 30 | Rake::TestTask.new(:test) do |t| | ||
| 31 | t.libs += ['lib', 'test'] | ||
| 32 | t.pattern = 'test/**/*_test.rb' | ||
| 33 | t.verbose = true | ||
| 34 | end | ||
| 35 | |||
| 36 | desc 'Generate documentation for the awesome_nested_set plugin.' | ||
| 37 | Rake::RDocTask.new(:rdoc) do |rdoc| | ||
| 38 | rdoc.rdoc_dir = 'rdoc' | ||
| 39 | rdoc.title = 'AwesomeNestedSet' | ||
| 40 | rdoc.options << '--line-numbers' << '--inline-source' | ||
| 41 | rdoc.rdoc_files.include('README.rdoc') | ||
| 42 | rdoc.rdoc_files.include('lib/**/*.rb') | ||
| 43 | end | ||
| 44 | |||
| 45 | namespace :test do | ||
| 46 | desc "just rcov minus html output" | ||
| 47 | Rcov::RcovTask.new(:coverage) do |t| | ||
| 48 | t.libs << 'test' | ||
| 49 | t.test_files = FileList['test/**/*_test.rb'] | ||
| 50 | t.output_dir = 'coverage' | ||
| 51 | t.verbose = true | ||
| 52 | t.rcov_opts = %w(--exclude test,/usr/lib/ruby,/Library/Ruby,lib/awesome_nested_set/named_scope.rb --sort coverage) | ||
| 53 | end | ||
| 54 | end \ No newline at end of file | ||
diff --git a/vendor/plugins/awesome_nested_set/VERSION b/vendor/plugins/awesome_nested_set/VERSION deleted file mode 100644 index 9df886c..0000000 --- a/vendor/plugins/awesome_nested_set/VERSION +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | 1.4.2 | ||
diff --git a/vendor/plugins/awesome_nested_set/awesome_nested_set.gemspec b/vendor/plugins/awesome_nested_set/awesome_nested_set.gemspec deleted file mode 100644 index 81108c5..0000000 --- a/vendor/plugins/awesome_nested_set/awesome_nested_set.gemspec +++ /dev/null | |||
| @@ -1,68 +0,0 @@ | |||
| 1 | # -*- encoding: utf-8 -*- | ||
| 2 | |||
| 3 | Gem::Specification.new do |s| | ||
| 4 | s.name = %q{awesome_nested_set} | ||
| 5 | s.version = "1.4.2" | ||
| 6 | |||
| 7 | s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= | ||
| 8 | s.authors = ["Brandon Keepers", "Daniel Morrison"] | ||
| 9 | s.date = %q{2009-09-08} | ||
| 10 | s.description = %q{An awesome nested set implementation for Active Record} | ||
| 11 | s.email = %q{info@collectiveidea.com} | ||
| 12 | s.extra_rdoc_files = [ | ||
| 13 | "README.rdoc" | ||
| 14 | ] | ||
| 15 | s.files = [ | ||
| 16 | ".autotest", | ||
| 17 | ".gitignore", | ||
| 18 | "MIT-LICENSE", | ||
| 19 | "README.rdoc", | ||
| 20 | "Rakefile", | ||
| 21 | "VERSION", | ||
| 22 | "awesome_nested_set.gemspec", | ||
| 23 | "init.rb", | ||
| 24 | "lib/awesome_nested_set.rb", | ||
| 25 | "lib/awesome_nested_set/helper.rb", | ||
| 26 | "rails/init.rb", | ||
| 27 | "test/application.rb", | ||
| 28 | "test/awesome_nested_set/helper_test.rb", | ||
| 29 | "test/awesome_nested_set_test.rb", | ||
| 30 | "test/db/database.yml", | ||
| 31 | "test/db/schema.rb", | ||
| 32 | "test/fixtures/categories.yml", | ||
| 33 | "test/fixtures/category.rb", | ||
| 34 | "test/fixtures/departments.yml", | ||
| 35 | "test/fixtures/notes.yml", | ||
| 36 | "test/test_helper.rb" | ||
| 37 | ] | ||
| 38 | s.homepage = %q{http://github.com/collectiveidea/awesome_nested_set} | ||
| 39 | s.rdoc_options = ["--main", "README.rdoc", "--inline-source", "--line-numbers"] | ||
| 40 | s.require_paths = ["lib"] | ||
| 41 | s.rubygems_version = %q{1.3.3} | ||
| 42 | s.summary = %q{An awesome nested set implementation for Active Record} | ||
| 43 | s.test_files = [ | ||
| 44 | "test/db/database.yml", | ||
| 45 | "test/fixtures/categories.yml", | ||
| 46 | "test/fixtures/departments.yml", | ||
| 47 | "test/fixtures/notes.yml", | ||
| 48 | "test/application.rb", | ||
| 49 | "test/awesome_nested_set/helper_test.rb", | ||
| 50 | "test/awesome_nested_set_test.rb", | ||
| 51 | "test/db/schema.rb", | ||
| 52 | "test/fixtures/category.rb", | ||
| 53 | "test/test_helper.rb" | ||
| 54 | ] | ||
| 55 | |||
| 56 | if s.respond_to? :specification_version then | ||
| 57 | current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION | ||
| 58 | s.specification_version = 3 | ||
| 59 | |||
| 60 | if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then | ||
| 61 | s.add_runtime_dependency(%q<activerecord>, [">= 1.1"]) | ||
| 62 | else | ||
| 63 | s.add_dependency(%q<activerecord>, [">= 1.1"]) | ||
| 64 | end | ||
| 65 | else | ||
| 66 | s.add_dependency(%q<activerecord>, [">= 1.1"]) | ||
| 67 | end | ||
| 68 | end | ||
diff --git a/vendor/plugins/awesome_nested_set/init.rb b/vendor/plugins/awesome_nested_set/init.rb deleted file mode 100644 index 43dc7c2..0000000 --- a/vendor/plugins/awesome_nested_set/init.rb +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | require File.dirname(__FILE__) + "/rails/init" | ||
diff --git a/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb b/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb deleted file mode 100644 index 015aa0f..0000000 --- a/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb +++ /dev/null | |||
| @@ -1,577 +0,0 @@ | |||
| 1 | module CollectiveIdea #:nodoc: | ||
| 2 | module Acts #:nodoc: | ||
| 3 | module NestedSet #:nodoc: | ||
| 4 | def self.included(base) | ||
| 5 | base.extend(SingletonMethods) | ||
| 6 | end | ||
| 7 | |||
| 8 | # This acts provides Nested Set functionality. Nested Set is a smart way to implement | ||
| 9 | # an _ordered_ tree, with the added feature that you can select the children and all of their | ||
| 10 | # descendants with a single query. The drawback is that insertion or move need some complex | ||
| 11 | # sql queries. But everything is done here by this module! | ||
| 12 | # | ||
| 13 | # Nested sets are appropriate each time you want either an orderd tree (menus, | ||
| 14 | # commercial categories) or an efficient way of querying big trees (threaded posts). | ||
| 15 | # | ||
| 16 | # == API | ||
| 17 | # | ||
| 18 | # Methods names are aligned with acts_as_tree as much as possible to make replacment from one | ||
| 19 | # by another easier. | ||
| 20 | # | ||
| 21 | # item.children.create(:name => "child1") | ||
| 22 | # | ||
| 23 | module SingletonMethods | ||
| 24 | # Configuration options are: | ||
| 25 | # | ||
| 26 | # * +:parent_column+ - specifies the column name to use for keeping the position integer (default: parent_id) | ||
| 27 | # * +:left_column+ - column name for left boundry data, default "lft" | ||
| 28 | # * +:right_column+ - column name for right boundry data, default "rgt" | ||
| 29 | # * +:scope+ - restricts what is to be considered a list. Given a symbol, it'll attach "_id" | ||
| 30 | # (if it hasn't been already) and use that as the foreign key restriction. You | ||
| 31 | # can also pass an array to scope by multiple attributes. | ||
| 32 | # Example: <tt>acts_as_nested_set :scope => [:notable_id, :notable_type]</tt> | ||
| 33 | # * +:dependent+ - behavior for cascading destroy. If set to :destroy, all the | ||
| 34 | # child objects are destroyed alongside this object by calling their destroy | ||
| 35 | # method. If set to :delete_all (default), all the child objects are deleted | ||
| 36 | # without calling their destroy method. | ||
| 37 | # | ||
| 38 | # See CollectiveIdea::Acts::NestedSet::ClassMethods for a list of class methods and | ||
| 39 | # CollectiveIdea::Acts::NestedSet::InstanceMethods for a list of instance methods added | ||
| 40 | # to acts_as_nested_set models | ||
| 41 | def acts_as_nested_set(options = {}) | ||
| 42 | options = { | ||
| 43 | :parent_column => 'parent_id', | ||
| 44 | :left_column => 'lft', | ||
| 45 | :right_column => 'rgt', | ||
| 46 | :dependent => :delete_all, # or :destroy | ||
| 47 | }.merge(options) | ||
| 48 | |||
| 49 | if options[:scope].is_a?(Symbol) && options[:scope].to_s !~ /_id$/ | ||
| 50 | options[:scope] = "#{options[:scope]}_id".intern | ||
| 51 | end | ||
| 52 | |||
| 53 | write_inheritable_attribute :acts_as_nested_set_options, options | ||
| 54 | class_inheritable_reader :acts_as_nested_set_options | ||
| 55 | |||
| 56 | unless self.is_a?(ClassMethods) | ||
| 57 | include Comparable | ||
| 58 | include Columns | ||
| 59 | include InstanceMethods | ||
| 60 | extend Columns | ||
| 61 | extend ClassMethods | ||
| 62 | |||
| 63 | belongs_to :parent, :class_name => self.base_class.class_name, | ||
| 64 | :foreign_key => parent_column_name | ||
| 65 | has_many :children, :class_name => self.base_class.class_name, | ||
| 66 | :foreign_key => parent_column_name, :order => quoted_left_column_name | ||
| 67 | |||
| 68 | attr_accessor :skip_before_destroy | ||
| 69 | |||
| 70 | # no bulk assignment | ||
| 71 | attr_protected left_column_name.intern, | ||
| 72 | right_column_name.intern | ||
| 73 | |||
| 74 | before_create :set_default_left_and_right | ||
| 75 | before_save :store_new_parent | ||
| 76 | after_save :move_to_new_parent | ||
| 77 | before_destroy :destroy_descendants | ||
| 78 | |||
| 79 | # no assignment to structure fields | ||
| 80 | [left_column_name, right_column_name].each do |column| | ||
| 81 | module_eval <<-"end_eval", __FILE__, __LINE__ | ||
| 82 | def #{column}=(x) | ||
| 83 | raise ActiveRecord::ActiveRecordError, "Unauthorized assignment to #{column}: it's an internal field handled by acts_as_nested_set code, use move_to_* methods instead." | ||
| 84 | end | ||
| 85 | end_eval | ||
| 86 | end | ||
| 87 | |||
| 88 | named_scope :roots, :conditions => {parent_column_name => nil}, :order => quoted_left_column_name | ||
| 89 | named_scope :leaves, :conditions => "#{quoted_right_column_name} - #{quoted_left_column_name} = 1", :order => quoted_left_column_name | ||
| 90 | |||
| 91 | define_callbacks("before_move", "after_move") if self.respond_to?(:define_callbacks) | ||
| 92 | end | ||
| 93 | |||
| 94 | end | ||
| 95 | |||
| 96 | end | ||
| 97 | |||
| 98 | module ClassMethods | ||
| 99 | |||
| 100 | # Returns the first root | ||
| 101 | def root | ||
| 102 | roots.find(:first) | ||
| 103 | end | ||
| 104 | |||
| 105 | def valid? | ||
| 106 | left_and_rights_valid? && no_duplicates_for_columns? && all_roots_valid? | ||
| 107 | end | ||
| 108 | |||
| 109 | def left_and_rights_valid? | ||
| 110 | count( | ||
| 111 | :joins => "LEFT OUTER JOIN #{quoted_table_name} AS parent ON " + | ||
| 112 | "#{quoted_table_name}.#{quoted_parent_column_name} = parent.#{primary_key}", | ||
| 113 | :conditions => | ||
| 114 | "#{quoted_table_name}.#{quoted_left_column_name} IS NULL OR " + | ||
| 115 | "#{quoted_table_name}.#{quoted_right_column_name} IS NULL OR " + | ||
| 116 | "#{quoted_table_name}.#{quoted_left_column_name} >= " + | ||
| 117 | "#{quoted_table_name}.#{quoted_right_column_name} OR " + | ||
| 118 | "(#{quoted_table_name}.#{quoted_parent_column_name} IS NOT NULL AND " + | ||
| 119 | "(#{quoted_table_name}.#{quoted_left_column_name} <= parent.#{quoted_left_column_name} OR " + | ||
| 120 | "#{quoted_table_name}.#{quoted_right_column_name} >= parent.#{quoted_right_column_name}))" | ||
| 121 | ) == 0 | ||
| 122 | end | ||
| 123 | |||
| 124 | def no_duplicates_for_columns? | ||
| 125 | scope_string = Array(acts_as_nested_set_options[:scope]).map do |c| | ||
| 126 | connection.quote_column_name(c) | ||
| 127 | end.push(nil).join(", ") | ||
| 128 | [quoted_left_column_name, quoted_right_column_name].all? do |column| | ||
| 129 | # No duplicates | ||
| 130 | find(:first, | ||
| 131 | :select => "#{scope_string}#{column}, COUNT(#{column})", | ||
| 132 | :group => "#{scope_string}#{column} | ||
| 133 | HAVING COUNT(#{column}) > 1").nil? | ||
| 134 | end | ||
| 135 | end | ||
| 136 | |||
| 137 | # Wrapper for each_root_valid? that can deal with scope. | ||
| 138 | def all_roots_valid? | ||
| 139 | if acts_as_nested_set_options[:scope] | ||
| 140 | roots(:group => scope_column_names).group_by{|record| scope_column_names.collect{|col| record.send(col.to_sym)}}.all? do |scope, grouped_roots| | ||
| 141 | each_root_valid?(grouped_roots) | ||
| 142 | end | ||
| 143 | else | ||
| 144 | each_root_valid?(roots) | ||
| 145 | end | ||
| 146 | end | ||
| 147 | |||
| 148 | def each_root_valid?(roots_to_validate) | ||
| 149 | left = right = 0 | ||
| 150 | roots_to_validate.all? do |root| | ||
| 151 | returning(root.left > left && root.right > right) do | ||
| 152 | left = root.left | ||
| 153 | right = root.right | ||
| 154 | end | ||
| 155 | end | ||
| 156 | end | ||
| 157 | |||
| 158 | # Rebuilds the left & rights if unset or invalid. Also very useful for converting from acts_as_tree. | ||
| 159 | def rebuild! | ||
| 160 | # Don't rebuild a valid tree. | ||
| 161 | return true if valid? | ||
| 162 | |||
| 163 | scope = lambda{|node|} | ||
| 164 | if acts_as_nested_set_options[:scope] | ||
| 165 | scope = lambda{|node| | ||
| 166 | scope_column_names.inject(""){|str, column_name| | ||
| 167 | str << "AND #{connection.quote_column_name(column_name)} = #{connection.quote(node.send(column_name.to_sym))} " | ||
| 168 | } | ||
| 169 | } | ||
| 170 | end | ||
| 171 | indices = {} | ||
| 172 | |||
| 173 | set_left_and_rights = lambda do |node| | ||
| 174 | # set left | ||
| 175 | node[left_column_name] = indices[scope.call(node)] += 1 | ||
| 176 | # find | ||
| 177 | find(:all, :conditions => ["#{quoted_parent_column_name} = ? #{scope.call(node)}", node], :order => "#{quoted_left_column_name}, #{quoted_right_column_name}, id").each{|n| set_left_and_rights.call(n) } | ||
| 178 | # set right | ||
| 179 | node[right_column_name] = indices[scope.call(node)] += 1 | ||
| 180 | node.save! | ||
| 181 | end | ||
| 182 | |||
| 183 | # Find root node(s) | ||
| 184 | root_nodes = find(:all, :conditions => "#{quoted_parent_column_name} IS NULL", :order => "#{quoted_left_column_name}, #{quoted_right_column_name}, id").each do |root_node| | ||
| 185 | # setup index for this scope | ||
| 186 | indices[scope.call(root_node)] ||= 0 | ||
| 187 | set_left_and_rights.call(root_node) | ||
| 188 | end | ||
| 189 | end | ||
| 190 | |||
| 191 | # Iterates over tree elements and determines the current level in the tree. | ||
| 192 | # Only accepts default ordering, odering by an other column than lft | ||
| 193 | # does not work. This method is much more efficent than calling level | ||
| 194 | # because it doesn't require any additional database queries. | ||
| 195 | # | ||
| 196 | # Example: | ||
| 197 | # Category.each_with_level(Category.root.self_and_descendants) do |o, level| | ||
| 198 | # | ||
| 199 | def each_with_level(objects) | ||
| 200 | path = [nil] | ||
| 201 | objects.each do |o| | ||
| 202 | if o.parent_id != path.last | ||
| 203 | # we are on a new level, did we decent or ascent? | ||
| 204 | if path.include?(o.parent_id) | ||
| 205 | # remove wrong wrong tailing paths elements | ||
| 206 | path.pop while path.last != o.parent_id | ||
| 207 | else | ||
| 208 | path << o.parent_id | ||
| 209 | end | ||
| 210 | end | ||
| 211 | yield(o, path.length - 1) | ||
| 212 | end | ||
| 213 | end | ||
| 214 | end | ||
| 215 | |||
| 216 | # Mixed into both classes and instances to provide easy access to the column names | ||
| 217 | module Columns | ||
| 218 | def left_column_name | ||
| 219 | acts_as_nested_set_options[:left_column] | ||
| 220 | end | ||
| 221 | |||
| 222 | def right_column_name | ||
| 223 | acts_as_nested_set_options[:right_column] | ||
| 224 | end | ||
| 225 | |||
| 226 | def parent_column_name | ||
| 227 | acts_as_nested_set_options[:parent_column] | ||
| 228 | end | ||
| 229 | |||
| 230 | def scope_column_names | ||
| 231 | Array(acts_as_nested_set_options[:scope]) | ||
| 232 | end | ||
| 233 | |||
| 234 | def quoted_left_column_name | ||
| 235 | connection.quote_column_name(left_column_name) | ||
| 236 | end | ||
| 237 | |||
| 238 | def quoted_right_column_name | ||
| 239 | connection.quote_column_name(right_column_name) | ||
| 240 | end | ||
| 241 | |||
| 242 | def quoted_parent_column_name | ||
| 243 | connection.quote_column_name(parent_column_name) | ||
| 244 | end | ||
| 245 | |||
| 246 | def quoted_scope_column_names | ||
| 247 | scope_column_names.collect {|column_name| connection.quote_column_name(column_name) } | ||
| 248 | end | ||
| 249 | end | ||
| 250 | |||
| 251 | # Any instance method that returns a collection makes use of Rails 2.1's named_scope (which is bundled for Rails 2.0), so it can be treated as a finder. | ||
| 252 | # | ||
| 253 | # category.self_and_descendants.count | ||
| 254 | # category.ancestors.find(:all, :conditions => "name like '%foo%'") | ||
| 255 | module InstanceMethods | ||
| 256 | # Value of the parent column | ||
| 257 | def parent_id | ||
| 258 | self[parent_column_name] | ||
| 259 | end | ||
| 260 | |||
| 261 | # Value of the left column | ||
| 262 | def left | ||
| 263 | self[left_column_name] | ||
| 264 | end | ||
| 265 | |||
| 266 | # Value of the right column | ||
| 267 | def right | ||
| 268 | self[right_column_name] | ||
| 269 | end | ||
| 270 | |||
| 271 | # Returns true if this is a root node. | ||
| 272 | def root? | ||
| 273 | parent_id.nil? | ||
| 274 | end | ||
| 275 | |||
| 276 | def leaf? | ||
| 277 | !new_record? && right - left == 1 | ||
| 278 | end | ||
| 279 | |||
| 280 | # Returns true is this is a child node | ||
| 281 | def child? | ||
| 282 | !parent_id.nil? | ||
| 283 | end | ||
| 284 | |||
| 285 | # order by left column | ||
| 286 | def <=>(x) | ||
| 287 | left <=> x.left | ||
| 288 | end | ||
| 289 | |||
| 290 | # Redefine to act like active record | ||
| 291 | def ==(comparison_object) | ||
| 292 | comparison_object.equal?(self) || | ||
| 293 | (comparison_object.instance_of?(self.class) && | ||
| 294 | comparison_object.id == id && | ||
| 295 | !comparison_object.new_record?) | ||
| 296 | end | ||
| 297 | |||
| 298 | # Returns root | ||
| 299 | def root | ||
| 300 | self_and_ancestors.find(:first) | ||
| 301 | end | ||
| 302 | |||
| 303 | # Returns the array of all parents and self | ||
| 304 | def self_and_ancestors | ||
| 305 | nested_set_scope.scoped :conditions => [ | ||
| 306 | "#{self.class.quoted_table_name}.#{quoted_left_column_name} <= ? AND #{self.class.quoted_table_name}.#{quoted_right_column_name} >= ?", left, right | ||
| 307 | ] | ||
| 308 | end | ||
| 309 | |||
| 310 | # Returns an array of all parents | ||
| 311 | def ancestors | ||
| 312 | without_self self_and_ancestors | ||
| 313 | end | ||
| 314 | |||
| 315 | # Returns the array of all children of the parent, including self | ||
| 316 | def self_and_siblings | ||
| 317 | nested_set_scope.scoped :conditions => {parent_column_name => parent_id} | ||
| 318 | end | ||
| 319 | |||
| 320 | # Returns the array of all children of the parent, except self | ||
| 321 | def siblings | ||
| 322 | without_self self_and_siblings | ||
| 323 | end | ||
| 324 | |||
| 325 | # Returns a set of all of its nested children which do not have children | ||
| 326 | def leaves | ||
| 327 | descendants.scoped :conditions => "#{self.class.quoted_table_name}.#{quoted_right_column_name} - #{self.class.quoted_table_name}.#{quoted_left_column_name} = 1" | ||
| 328 | end | ||
| 329 | |||
| 330 | # Returns the level of this object in the tree | ||
| 331 | # root level is 0 | ||
| 332 | def level | ||
| 333 | parent_id.nil? ? 0 : ancestors.count | ||
| 334 | end | ||
| 335 | |||
| 336 | # Returns a set of itself and all of its nested children | ||
| 337 | def self_and_descendants | ||
| 338 | nested_set_scope.scoped :conditions => [ | ||
| 339 | "#{self.class.quoted_table_name}.#{quoted_left_column_name} >= ? AND #{self.class.quoted_table_name}.#{quoted_right_column_name} <= ?", left, right | ||
| 340 | ] | ||
| 341 | end | ||
| 342 | |||
| 343 | # Returns a set of all of its children and nested children | ||
| 344 | def descendants | ||
| 345 | without_self self_and_descendants | ||
| 346 | end | ||
| 347 | |||
| 348 | def is_descendant_of?(other) | ||
| 349 | other.left < self.left && self.left < other.right && same_scope?(other) | ||
| 350 | end | ||
| 351 | |||
| 352 | def is_or_is_descendant_of?(other) | ||
| 353 | other.left <= self.left && self.left < other.right && same_scope?(other) | ||
| 354 | end | ||
| 355 | |||
| 356 | def is_ancestor_of?(other) | ||
| 357 | self.left < other.left && other.left < self.right && same_scope?(other) | ||
| 358 | end | ||
| 359 | |||
| 360 | def is_or_is_ancestor_of?(other) | ||
| 361 | self.left <= other.left && other.left < self.right && same_scope?(other) | ||
| 362 | end | ||
| 363 | |||
| 364 | # Check if other model is in the same scope | ||
| 365 | def same_scope?(other) | ||
| 366 | Array(acts_as_nested_set_options[:scope]).all? do |attr| | ||
| 367 | self.send(attr) == other.send(attr) | ||
| 368 | end | ||
| 369 | end | ||
| 370 | |||
| 371 | # Find the first sibling to the left | ||
| 372 | def left_sibling | ||
| 373 | siblings.find(:first, :conditions => ["#{self.class.quoted_table_name}.#{quoted_left_column_name} < ?", left], | ||
| 374 | :order => "#{self.class.quoted_table_name}.#{quoted_left_column_name} DESC") | ||
| 375 | end | ||
| 376 | |||
| 377 | # Find the first sibling to the right | ||
| 378 | def right_sibling | ||
| 379 | siblings.find(:first, :conditions => ["#{self.class.quoted_table_name}.#{quoted_left_column_name} > ?", left]) | ||
| 380 | end | ||
| 381 | |||
| 382 | # Shorthand method for finding the left sibling and moving to the left of it. | ||
| 383 | def move_left | ||
| 384 | move_to_left_of left_sibling | ||
| 385 | end | ||
| 386 | |||
| 387 | # Shorthand method for finding the right sibling and moving to the right of it. | ||
| 388 | def move_right | ||
| 389 | move_to_right_of right_sibling | ||
| 390 | end | ||
| 391 | |||
| 392 | # Move the node to the left of another node (you can pass id only) | ||
| 393 | def move_to_left_of(node) | ||
| 394 | move_to node, :left | ||
| 395 | end | ||
| 396 | |||
| 397 | # Move the node to the left of another node (you can pass id only) | ||
| 398 | def move_to_right_of(node) | ||
| 399 | move_to node, :right | ||
| 400 | end | ||
| 401 | |||
| 402 | # Move the node to the child of another node (you can pass id only) | ||
| 403 | def move_to_child_of(node) | ||
| 404 | move_to node, :child | ||
| 405 | end | ||
| 406 | |||
| 407 | # Move the node to root nodes | ||
| 408 | def move_to_root | ||
| 409 | move_to nil, :root | ||
| 410 | end | ||
| 411 | |||
| 412 | def move_possible?(target) | ||
| 413 | self != target && # Can't target self | ||
| 414 | same_scope?(target) && # can't be in different scopes | ||
| 415 | # !(left..right).include?(target.left..target.right) # this needs tested more | ||
| 416 | # detect impossible move | ||
| 417 | !((left <= target.left && right >= target.left) or (left <= target.right && right >= target.right)) | ||
| 418 | end | ||
| 419 | |||
| 420 | def to_text | ||
| 421 | self_and_descendants.map do |node| | ||
| 422 | "#{'*'*(node.level+1)} #{node.id} #{node.to_s} (#{node.parent_id}, #{node.left}, #{node.right})" | ||
| 423 | end.join("\n") | ||
| 424 | end | ||
| 425 | |||
| 426 | protected | ||
| 427 | |||
| 428 | def without_self(scope) | ||
| 429 | scope.scoped :conditions => ["#{self.class.quoted_table_name}.#{self.class.primary_key} != ?", self] | ||
| 430 | end | ||
| 431 | |||
| 432 | # All nested set queries should use this nested_set_scope, which performs finds on | ||
| 433 | # the base ActiveRecord class, using the :scope declared in the acts_as_nested_set | ||
| 434 | # declaration. | ||
| 435 | def nested_set_scope | ||
| 436 | options = {:order => quoted_left_column_name} | ||
| 437 | scopes = Array(acts_as_nested_set_options[:scope]) | ||
| 438 | options[:conditions] = scopes.inject({}) do |conditions,attr| | ||
| 439 | conditions.merge attr => self[attr] | ||
| 440 | end unless scopes.empty? | ||
| 441 | self.class.base_class.scoped options | ||
| 442 | end | ||
| 443 | |||
| 444 | def store_new_parent | ||
| 445 | @move_to_new_parent_id = send("#{parent_column_name}_changed?") ? parent_id : false | ||
| 446 | true # force callback to return true | ||
| 447 | end | ||
| 448 | |||
| 449 | def move_to_new_parent | ||
| 450 | if @move_to_new_parent_id.nil? | ||
| 451 | move_to_root | ||
| 452 | elsif @move_to_new_parent_id | ||
| 453 | move_to_child_of(@move_to_new_parent_id) | ||
| 454 | end | ||
| 455 | end | ||
| 456 | |||
| 457 | # on creation, set automatically lft and rgt to the end of the tree | ||
| 458 | def set_default_left_and_right | ||
| 459 | maxright = nested_set_scope.maximum(right_column_name) || 0 | ||
| 460 | # adds the new node to the right of all existing nodes | ||
| 461 | self[left_column_name] = maxright + 1 | ||
| 462 | self[right_column_name] = maxright + 2 | ||
| 463 | end | ||
| 464 | |||
| 465 | # Prunes a branch off of the tree, shifting all of the elements on the right | ||
| 466 | # back to the left so the counts still work. | ||
| 467 | def destroy_descendants | ||
| 468 | return if right.nil? || left.nil? || skip_before_destroy | ||
| 469 | |||
| 470 | self.class.base_class.transaction do | ||
| 471 | if acts_as_nested_set_options[:dependent] == :destroy | ||
| 472 | descendants.each do |model| | ||
| 473 | model.skip_before_destroy = true | ||
| 474 | model.destroy | ||
| 475 | end | ||
| 476 | else | ||
| 477 | nested_set_scope.delete_all( | ||
| 478 | ["#{quoted_left_column_name} > ? AND #{quoted_right_column_name} < ?", | ||
| 479 | left, right] | ||
| 480 | ) | ||
| 481 | end | ||
| 482 | |||
| 483 | # update lefts and rights for remaining nodes | ||
| 484 | diff = right - left + 1 | ||
| 485 | nested_set_scope.update_all( | ||
| 486 | ["#{quoted_left_column_name} = (#{quoted_left_column_name} - ?)", diff], | ||
| 487 | ["#{quoted_left_column_name} > ?", right] | ||
| 488 | ) | ||
| 489 | nested_set_scope.update_all( | ||
| 490 | ["#{quoted_right_column_name} = (#{quoted_right_column_name} - ?)", diff], | ||
| 491 | ["#{quoted_right_column_name} > ?", right] | ||
| 492 | ) | ||
| 493 | |||
| 494 | # Don't allow multiple calls to destroy to corrupt the set | ||
| 495 | self.skip_before_destroy = true | ||
| 496 | end | ||
| 497 | end | ||
| 498 | |||
| 499 | # reload left, right, and parent | ||
| 500 | def reload_nested_set | ||
| 501 | reload(:select => "#{quoted_left_column_name}, " + | ||
| 502 | "#{quoted_right_column_name}, #{quoted_parent_column_name}") | ||
| 503 | end | ||
| 504 | |||
| 505 | def move_to(target, position) | ||
| 506 | raise ActiveRecord::ActiveRecordError, "You cannot move a new node" if self.new_record? | ||
| 507 | return if callback(:before_move) == false | ||
| 508 | transaction do | ||
| 509 | if target.is_a? self.class.base_class | ||
| 510 | target.reload_nested_set | ||
| 511 | elsif position != :root | ||
| 512 | # load object if node is not an object | ||
| 513 | target = nested_set_scope.find(target) | ||
| 514 | end | ||
| 515 | self.reload_nested_set | ||
| 516 | |||
| 517 | unless position == :root || move_possible?(target) | ||
| 518 | raise ActiveRecord::ActiveRecordError, "Impossible move, target node cannot be inside moved tree." | ||
| 519 | end | ||
| 520 | |||
| 521 | bound = case position | ||
| 522 | when :child; target[right_column_name] | ||
| 523 | when :left; target[left_column_name] | ||
| 524 | when :right; target[right_column_name] + 1 | ||
| 525 | when :root; 1 | ||
| 526 | else raise ActiveRecord::ActiveRecordError, "Position should be :child, :left, :right or :root ('#{position}' received)." | ||
| 527 | end | ||
| 528 | |||
| 529 | if bound > self[right_column_name] | ||
| 530 | bound = bound - 1 | ||
| 531 | other_bound = self[right_column_name] + 1 | ||
| 532 | else | ||
| 533 | other_bound = self[left_column_name] - 1 | ||
| 534 | end | ||
| 535 | |||
| 536 | # there would be no change | ||
| 537 | return if bound == self[right_column_name] || bound == self[left_column_name] | ||
| 538 | |||
| 539 | # we have defined the boundaries of two non-overlapping intervals, | ||
| 540 | # so sorting puts both the intervals and their boundaries in order | ||
| 541 | a, b, c, d = [self[left_column_name], self[right_column_name], bound, other_bound].sort | ||
| 542 | |||
| 543 | new_parent = case position | ||
| 544 | when :child; target.id | ||
| 545 | when :root; nil | ||
| 546 | else target[parent_column_name] | ||
| 547 | end | ||
| 548 | |||
| 549 | self.class.base_class.update_all([ | ||
| 550 | "#{quoted_left_column_name} = CASE " + | ||
| 551 | "WHEN #{quoted_left_column_name} BETWEEN :a AND :b " + | ||
| 552 | "THEN #{quoted_left_column_name} + :d - :b " + | ||
| 553 | "WHEN #{quoted_left_column_name} BETWEEN :c AND :d " + | ||
| 554 | "THEN #{quoted_left_column_name} + :a - :c " + | ||
| 555 | "ELSE #{quoted_left_column_name} END, " + | ||
| 556 | "#{quoted_right_column_name} = CASE " + | ||
| 557 | "WHEN #{quoted_right_column_name} BETWEEN :a AND :b " + | ||
| 558 | "THEN #{quoted_right_column_name} + :d - :b " + | ||
| 559 | "WHEN #{quoted_right_column_name} BETWEEN :c AND :d " + | ||
| 560 | "THEN #{quoted_right_column_name} + :a - :c " + | ||
| 561 | "ELSE #{quoted_right_column_name} END, " + | ||
| 562 | "#{quoted_parent_column_name} = CASE " + | ||
| 563 | "WHEN #{self.class.base_class.primary_key} = :id THEN :new_parent " + | ||
| 564 | "ELSE #{quoted_parent_column_name} END", | ||
| 565 | {:a => a, :b => b, :c => c, :d => d, :id => self.id, :new_parent => new_parent} | ||
| 566 | ], nested_set_scope.proxy_options[:conditions]) | ||
| 567 | end | ||
| 568 | target.reload_nested_set if target | ||
| 569 | self.reload_nested_set | ||
| 570 | callback(:after_move) | ||
| 571 | end | ||
| 572 | |||
| 573 | end | ||
| 574 | |||
| 575 | end | ||
| 576 | end | ||
| 577 | end | ||
diff --git a/vendor/plugins/awesome_nested_set/lib/awesome_nested_set/helper.rb b/vendor/plugins/awesome_nested_set/lib/awesome_nested_set/helper.rb deleted file mode 100644 index 09c803f..0000000 --- a/vendor/plugins/awesome_nested_set/lib/awesome_nested_set/helper.rb +++ /dev/null | |||
| @@ -1,40 +0,0 @@ | |||
| 1 | module CollectiveIdea #:nodoc: | ||
| 2 | module Acts #:nodoc: | ||
| 3 | module NestedSet #:nodoc: | ||
| 4 | # This module provides some helpers for the model classes using acts_as_nested_set. | ||
| 5 | # It is included by default in all views. | ||
| 6 | # | ||
| 7 | module Helper | ||
| 8 | # Returns options for select. | ||
| 9 | # You can exclude some items from the tree. | ||
| 10 | # You can pass a block receiving an item and returning the string displayed in the select. | ||
| 11 | # | ||
| 12 | # == Params | ||
| 13 | # * +class_or_item+ - Class name or top level times | ||
| 14 | # * +mover+ - The item that is being move, used to exlude impossible moves | ||
| 15 | # * +&block+ - a block that will be used to display: { |item| ... item.name } | ||
| 16 | # | ||
| 17 | # == Usage | ||
| 18 | # | ||
| 19 | # <%= f.select :parent_id, nested_set_options(Category, @category) {|i| | ||
| 20 | # "#{'–' * i.level} #{i.name}" | ||
| 21 | # }) %> | ||
| 22 | # | ||
| 23 | def nested_set_options(class_or_item, mover = nil) | ||
| 24 | class_or_item = class_or_item.roots if class_or_item.is_a?(Class) | ||
| 25 | items = Array(class_or_item) | ||
| 26 | result = [] | ||
| 27 | items.each do |root| | ||
| 28 | result += root.self_and_descendants.map do |i| | ||
| 29 | if mover.nil? || mover.new_record? || mover.move_possible?(i) | ||
| 30 | [yield(i), i.id] | ||
| 31 | end | ||
| 32 | end.compact | ||
| 33 | end | ||
| 34 | result | ||
| 35 | end | ||
| 36 | |||
| 37 | end | ||
| 38 | end | ||
| 39 | end | ||
| 40 | end \ No newline at end of file | ||
diff --git a/vendor/plugins/awesome_nested_set/rails/init.rb b/vendor/plugins/awesome_nested_set/rails/init.rb deleted file mode 100644 index 2ff1336..0000000 --- a/vendor/plugins/awesome_nested_set/rails/init.rb +++ /dev/null | |||
| @@ -1,12 +0,0 @@ | |||
| 1 | require 'awesome_nested_set' | ||
| 2 | |||
| 3 | ActiveRecord::Base.class_eval do | ||
| 4 | include CollectiveIdea::Acts::NestedSet | ||
| 5 | end | ||
| 6 | |||
| 7 | if defined?(ActionView) | ||
| 8 | require 'awesome_nested_set/helper' | ||
| 9 | ActionView::Base.class_eval do | ||
| 10 | include CollectiveIdea::Acts::NestedSet::Helper | ||
| 11 | end | ||
| 12 | end \ No newline at end of file | ||
diff --git a/vendor/plugins/awesome_nested_set/test/application.rb b/vendor/plugins/awesome_nested_set/test/application.rb deleted file mode 100644 index 0e6eacf..0000000 --- a/vendor/plugins/awesome_nested_set/test/application.rb +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | # This file is here to satisfy test_help from Rails < 2.3 \ No newline at end of file | ||
diff --git a/vendor/plugins/awesome_nested_set/test/awesome_nested_set/helper_test.rb b/vendor/plugins/awesome_nested_set/test/awesome_nested_set/helper_test.rb deleted file mode 100644 index 888323c..0000000 --- a/vendor/plugins/awesome_nested_set/test/awesome_nested_set/helper_test.rb +++ /dev/null | |||
| @@ -1,41 +0,0 @@ | |||
| 1 | require 'test_helper' | ||
| 2 | |||
| 3 | module CollectiveIdea | ||
| 4 | module Acts #:nodoc: | ||
| 5 | module NestedSet #:nodoc: | ||
| 6 | class AwesomeNestedSetTest < TestCaseClass | ||
| 7 | include Helper | ||
| 8 | fixtures :categories | ||
| 9 | |||
| 10 | def test_nested_set_options | ||
| 11 | expected = [ | ||
| 12 | [" Top Level", 1], | ||
| 13 | ["- Child 1", 2], | ||
| 14 | ['- Child 2', 3], | ||
| 15 | ['-- Child 2.1', 4], | ||
| 16 | ['- Child 3', 5], | ||
| 17 | [" Top Level 2", 6] | ||
| 18 | ] | ||
| 19 | actual = nested_set_options(Category) do |c| | ||
| 20 | "#{'-' * c.level} #{c.name}" | ||
| 21 | end | ||
| 22 | assert_equal expected, actual | ||
| 23 | end | ||
| 24 | |||
| 25 | def test_nested_set_options_with_mover | ||
| 26 | expected = [ | ||
| 27 | [" Top Level", 1], | ||
| 28 | ["- Child 1", 2], | ||
| 29 | ['- Child 3', 5], | ||
| 30 | [" Top Level 2", 6] | ||
| 31 | ] | ||
| 32 | actual = nested_set_options(Category, categories(:child_2)) do |c| | ||
| 33 | "#{'-' * c.level} #{c.name}" | ||
| 34 | end | ||
| 35 | assert_equal expected, actual | ||
| 36 | end | ||
| 37 | |||
| 38 | end | ||
| 39 | end | ||
| 40 | end | ||
| 41 | end | ||
diff --git a/vendor/plugins/awesome_nested_set/test/awesome_nested_set_test.rb b/vendor/plugins/awesome_nested_set/test/awesome_nested_set_test.rb deleted file mode 100644 index 7b587de..0000000 --- a/vendor/plugins/awesome_nested_set/test/awesome_nested_set_test.rb +++ /dev/null | |||
| @@ -1,748 +0,0 @@ | |||
| 1 | require 'test_helper' | ||
| 2 | |||
| 3 | class Note < ActiveRecord::Base | ||
| 4 | acts_as_nested_set :scope => [:notable_id, :notable_type] | ||
| 5 | end | ||
| 6 | class Default < ActiveRecord::Base | ||
| 7 | acts_as_nested_set | ||
| 8 | set_table_name 'categories' | ||
| 9 | end | ||
| 10 | class ScopedCategory < ActiveRecord::Base | ||
| 11 | acts_as_nested_set :scope => :organization | ||
| 12 | set_table_name 'categories' | ||
| 13 | end | ||
| 14 | class RenamedColumns < ActiveRecord::Base | ||
| 15 | acts_as_nested_set :parent_column => 'mother_id', :left_column => 'red', :right_column => 'black' | ||
| 16 | end | ||
| 17 | |||
| 18 | class AwesomeNestedSetTest < TestCaseClass | ||
| 19 | |||
| 20 | def test_left_column_default | ||
| 21 | assert_equal 'lft', Default.acts_as_nested_set_options[:left_column] | ||
| 22 | end | ||
| 23 | |||
| 24 | def test_right_column_default | ||
| 25 | assert_equal 'rgt', Default.acts_as_nested_set_options[:right_column] | ||
| 26 | end | ||
| 27 | |||
| 28 | def test_parent_column_default | ||
| 29 | assert_equal 'parent_id', Default.acts_as_nested_set_options[:parent_column] | ||
| 30 | end | ||
| 31 | |||
| 32 | def test_scope_default | ||
| 33 | assert_nil Default.acts_as_nested_set_options[:scope] | ||
| 34 | end | ||
| 35 | |||
| 36 | def test_left_column_name | ||
| 37 | assert_equal 'lft', Default.left_column_name | ||
| 38 | assert_equal 'lft', Default.new.left_column_name | ||
| 39 | assert_equal 'red', RenamedColumns.left_column_name | ||
| 40 | assert_equal 'red', RenamedColumns.new.left_column_name | ||
| 41 | end | ||
| 42 | |||
| 43 | def test_right_column_name | ||
| 44 | assert_equal 'rgt', Default.right_column_name | ||
| 45 | assert_equal 'rgt', Default.new.right_column_name | ||
| 46 | assert_equal 'black', RenamedColumns.right_column_name | ||
| 47 | assert_equal 'black', RenamedColumns.new.right_column_name | ||
| 48 | end | ||
| 49 | |||
| 50 | def test_parent_column_name | ||
| 51 | assert_equal 'parent_id', Default.parent_column_name | ||
| 52 | assert_equal 'parent_id', Default.new.parent_column_name | ||
| 53 | assert_equal 'mother_id', RenamedColumns.parent_column_name | ||
| 54 | assert_equal 'mother_id', RenamedColumns.new.parent_column_name | ||
| 55 | end | ||
| 56 | |||
| 57 | def test_creation_with_altered_column_names | ||
| 58 | assert_nothing_raised do | ||
| 59 | RenamedColumns.create!() | ||
| 60 | end | ||
| 61 | end | ||
| 62 | |||
| 63 | def test_quoted_left_column_name | ||
| 64 | quoted = Default.connection.quote_column_name('lft') | ||
| 65 | assert_equal quoted, Default.quoted_left_column_name | ||
| 66 | assert_equal quoted, Default.new.quoted_left_column_name | ||
| 67 | end | ||
| 68 | |||
| 69 | def test_quoted_right_column_name | ||
| 70 | quoted = Default.connection.quote_column_name('rgt') | ||
| 71 | assert_equal quoted, Default.quoted_right_column_name | ||
| 72 | assert_equal quoted, Default.new.quoted_right_column_name | ||
| 73 | end | ||
| 74 | |||
| 75 | def test_left_column_protected_from_assignment | ||
| 76 | assert_raises(ActiveRecord::ActiveRecordError) { Category.new.lft = 1 } | ||
| 77 | end | ||
| 78 | |||
| 79 | def test_right_column_protected_from_assignment | ||
| 80 | assert_raises(ActiveRecord::ActiveRecordError) { Category.new.rgt = 1 } | ||
| 81 | end | ||
| 82 | |||
| 83 | def test_colums_protected_on_initialize | ||
| 84 | c = Category.new(:lft => 1, :rgt => 2) | ||
| 85 | assert_nil c.lft | ||
| 86 | assert_nil c.rgt | ||
| 87 | end | ||
| 88 | |||
| 89 | def test_scoped_appends_id | ||
| 90 | assert_equal :organization_id, ScopedCategory.acts_as_nested_set_options[:scope] | ||
| 91 | end | ||
| 92 | |||
| 93 | def test_roots_class_method | ||
| 94 | assert_equal Category.find_all_by_parent_id(nil), Category.roots | ||
| 95 | end | ||
| 96 | |||
| 97 | def test_root_class_method | ||
| 98 | assert_equal categories(:top_level), Category.root | ||
| 99 | end | ||
| 100 | |||
| 101 | def test_root | ||
| 102 | assert_equal categories(:top_level), categories(:child_3).root | ||
| 103 | end | ||
| 104 | |||
| 105 | def test_root? | ||
| 106 | assert categories(:top_level).root? | ||
| 107 | assert categories(:top_level_2).root? | ||
| 108 | end | ||
| 109 | |||
| 110 | def test_leaves_class_method | ||
| 111 | assert_equal Category.find(:all, :conditions => "#{Category.right_column_name} - #{Category.left_column_name} = 1"), Category.leaves | ||
| 112 | assert_equal Category.leaves.count, 4 | ||
| 113 | assert (Category.leaves.include? categories(:child_1)) | ||
| 114 | assert (Category.leaves.include? categories(:child_2_1)) | ||
| 115 | assert (Category.leaves.include? categories(:child_3)) | ||
| 116 | assert (Category.leaves.include? categories(:top_level_2)) | ||
| 117 | end | ||
| 118 | |||
| 119 | def test_leaf | ||
| 120 | assert categories(:child_1).leaf? | ||
| 121 | assert categories(:child_2_1).leaf? | ||
| 122 | assert categories(:child_3).leaf? | ||
| 123 | assert categories(:top_level_2).leaf? | ||
| 124 | |||
| 125 | assert !categories(:top_level).leaf? | ||
| 126 | assert !categories(:child_2).leaf? | ||
| 127 | assert !Category.new.leaf? | ||
| 128 | end | ||
| 129 | |||
| 130 | |||
| 131 | def test_parent | ||
| 132 | assert_equal categories(:child_2), categories(:child_2_1).parent | ||
| 133 | end | ||
| 134 | |||
| 135 | def test_self_and_ancestors | ||
| 136 | child = categories(:child_2_1) | ||
| 137 | self_and_ancestors = [categories(:top_level), categories(:child_2), child] | ||
| 138 | assert_equal self_and_ancestors, child.self_and_ancestors | ||
| 139 | end | ||
| 140 | |||
| 141 | def test_ancestors | ||
| 142 | child = categories(:child_2_1) | ||
| 143 | ancestors = [categories(:top_level), categories(:child_2)] | ||
| 144 | assert_equal ancestors, child.ancestors | ||
| 145 | end | ||
| 146 | |||
| 147 | def test_self_and_siblings | ||
| 148 | child = categories(:child_2) | ||
| 149 | self_and_siblings = [categories(:child_1), child, categories(:child_3)] | ||
| 150 | assert_equal self_and_siblings, child.self_and_siblings | ||
| 151 | assert_nothing_raised do | ||
| 152 | tops = [categories(:top_level), categories(:top_level_2)] | ||
| 153 | assert_equal tops, categories(:top_level).self_and_siblings | ||
| 154 | end | ||
| 155 | end | ||
| 156 | |||
| 157 | def test_siblings | ||
| 158 | child = categories(:child_2) | ||
| 159 | siblings = [categories(:child_1), categories(:child_3)] | ||
| 160 | assert_equal siblings, child.siblings | ||
| 161 | end | ||
| 162 | |||
| 163 | def test_leaves | ||
| 164 | leaves = [categories(:child_1), categories(:child_2_1), categories(:child_3), categories(:top_level_2)] | ||
| 165 | assert categories(:top_level).leaves, leaves | ||
| 166 | end | ||
| 167 | |||
| 168 | def test_level | ||
| 169 | assert_equal 0, categories(:top_level).level | ||
| 170 | assert_equal 1, categories(:child_1).level | ||
| 171 | assert_equal 2, categories(:child_2_1).level | ||
| 172 | end | ||
| 173 | |||
| 174 | def test_has_children? | ||
| 175 | assert categories(:child_2_1).children.empty? | ||
| 176 | assert !categories(:child_2).children.empty? | ||
| 177 | assert !categories(:top_level).children.empty? | ||
| 178 | end | ||
| 179 | |||
| 180 | def test_self_and_descendents | ||
| 181 | parent = categories(:top_level) | ||
| 182 | self_and_descendants = [parent, categories(:child_1), categories(:child_2), | ||
| 183 | categories(:child_2_1), categories(:child_3)] | ||
| 184 | assert_equal self_and_descendants, parent.self_and_descendants | ||
| 185 | assert_equal self_and_descendants, parent.self_and_descendants.count | ||
| 186 | end | ||
| 187 | |||
| 188 | def test_descendents | ||
| 189 | lawyers = Category.create!(:name => "lawyers") | ||
| 190 | us = Category.create!(:name => "United States") | ||
| 191 | us.move_to_child_of(lawyers) | ||
| 192 | patent = Category.create!(:name => "Patent Law") | ||
| 193 | patent.move_to_child_of(us) | ||
| 194 | lawyers.reload | ||
| 195 | |||
| 196 | assert_equal 1, lawyers.children.size | ||
| 197 | assert_equal 1, us.children.size | ||
| 198 | assert_equal 2, lawyers.descendants.size | ||
| 199 | end | ||
| 200 | |||
| 201 | def test_self_and_descendents | ||
| 202 | parent = categories(:top_level) | ||
| 203 | descendants = [categories(:child_1), categories(:child_2), | ||
| 204 | categories(:child_2_1), categories(:child_3)] | ||
| 205 | assert_equal descendants, parent.descendants | ||
| 206 | end | ||
| 207 | |||
| 208 | def test_children | ||
| 209 | category = categories(:top_level) | ||
| 210 | category.children.each {|c| assert_equal category.id, c.parent_id } | ||
| 211 | end | ||
| 212 | |||
| 213 | def test_order_of_children | ||
| 214 | categories(:child_2).move_left | ||
| 215 | assert_equal categories(:child_2), categories(:top_level).children[0] | ||
| 216 | assert_equal categories(:child_1), categories(:top_level).children[1] | ||
| 217 | assert_equal categories(:child_3), categories(:top_level).children[2] | ||
| 218 | end | ||
| 219 | |||
| 220 | def test_is_or_is_ancestor_of? | ||
| 221 | assert categories(:top_level).is_or_is_ancestor_of?(categories(:child_1)) | ||
| 222 | assert categories(:top_level).is_or_is_ancestor_of?(categories(:child_2_1)) | ||
| 223 | assert categories(:child_2).is_or_is_ancestor_of?(categories(:child_2_1)) | ||
| 224 | assert !categories(:child_2_1).is_or_is_ancestor_of?(categories(:child_2)) | ||
| 225 | assert !categories(:child_1).is_or_is_ancestor_of?(categories(:child_2)) | ||
| 226 | assert categories(:child_1).is_or_is_ancestor_of?(categories(:child_1)) | ||
| 227 | end | ||
| 228 | |||
| 229 | def test_is_ancestor_of? | ||
| 230 | assert categories(:top_level).is_ancestor_of?(categories(:child_1)) | ||
| 231 | assert categories(:top_level).is_ancestor_of?(categories(:child_2_1)) | ||
| 232 | assert categories(:child_2).is_ancestor_of?(categories(:child_2_1)) | ||
| 233 | assert !categories(:child_2_1).is_ancestor_of?(categories(:child_2)) | ||
| 234 | assert !categories(:child_1).is_ancestor_of?(categories(:child_2)) | ||
| 235 | assert !categories(:child_1).is_ancestor_of?(categories(:child_1)) | ||
| 236 | end | ||
| 237 | |||
| 238 | def test_is_or_is_ancestor_of_with_scope | ||
| 239 | root = ScopedCategory.root | ||
| 240 | child = root.children.first | ||
| 241 | assert root.is_or_is_ancestor_of?(child) | ||
| 242 | child.update_attribute :organization_id, 'different' | ||
| 243 | assert !root.is_or_is_ancestor_of?(child) | ||
| 244 | end | ||
| 245 | |||
| 246 | def test_is_or_is_descendant_of? | ||
| 247 | assert categories(:child_1).is_or_is_descendant_of?(categories(:top_level)) | ||
| 248 | assert categories(:child_2_1).is_or_is_descendant_of?(categories(:top_level)) | ||
| 249 | assert categories(:child_2_1).is_or_is_descendant_of?(categories(:child_2)) | ||
| 250 | assert !categories(:child_2).is_or_is_descendant_of?(categories(:child_2_1)) | ||
| 251 | assert !categories(:child_2).is_or_is_descendant_of?(categories(:child_1)) | ||
| 252 | assert categories(:child_1).is_or_is_descendant_of?(categories(:child_1)) | ||
| 253 | end | ||
| 254 | |||
| 255 | def test_is_descendant_of? | ||
| 256 | assert categories(:child_1).is_descendant_of?(categories(:top_level)) | ||
| 257 | assert categories(:child_2_1).is_descendant_of?(categories(:top_level)) | ||
| 258 | assert categories(:child_2_1).is_descendant_of?(categories(:child_2)) | ||
| 259 | assert !categories(:child_2).is_descendant_of?(categories(:child_2_1)) | ||
| 260 | assert !categories(:child_2).is_descendant_of?(categories(:child_1)) | ||
| 261 | assert !categories(:child_1).is_descendant_of?(categories(:child_1)) | ||
| 262 | end | ||
| 263 | |||
| 264 | def test_is_or_is_descendant_of_with_scope | ||
| 265 | root = ScopedCategory.root | ||
| 266 | child = root.children.first | ||
| 267 | assert child.is_or_is_descendant_of?(root) | ||
| 268 | child.update_attribute :organization_id, 'different' | ||
| 269 | assert !child.is_or_is_descendant_of?(root) | ||
| 270 | end | ||
| 271 | |||
| 272 | def test_same_scope? | ||
| 273 | root = ScopedCategory.root | ||
| 274 | child = root.children.first | ||
| 275 | assert child.same_scope?(root) | ||
| 276 | child.update_attribute :organization_id, 'different' | ||
| 277 | assert !child.same_scope?(root) | ||
| 278 | end | ||
| 279 | |||
| 280 | def test_left_sibling | ||
| 281 | assert_equal categories(:child_1), categories(:child_2).left_sibling | ||
| 282 | assert_equal categories(:child_2), categories(:child_3).left_sibling | ||
| 283 | end | ||
| 284 | |||
| 285 | def test_left_sibling_of_root | ||
| 286 | assert_nil categories(:top_level).left_sibling | ||
| 287 | end | ||
| 288 | |||
| 289 | def test_left_sibling_without_siblings | ||
| 290 | assert_nil categories(:child_2_1).left_sibling | ||
| 291 | end | ||
| 292 | |||
| 293 | def test_left_sibling_of_leftmost_node | ||
| 294 | assert_nil categories(:child_1).left_sibling | ||
| 295 | end | ||
| 296 | |||
| 297 | def test_right_sibling | ||
| 298 | assert_equal categories(:child_3), categories(:child_2).right_sibling | ||
| 299 | assert_equal categories(:child_2), categories(:child_1).right_sibling | ||
| 300 | end | ||
| 301 | |||
| 302 | def test_right_sibling_of_root | ||
| 303 | assert_equal categories(:top_level_2), categories(:top_level).right_sibling | ||
| 304 | assert_nil categories(:top_level_2).right_sibling | ||
| 305 | end | ||
| 306 | |||
| 307 | def test_right_sibling_without_siblings | ||
| 308 | assert_nil categories(:child_2_1).right_sibling | ||
| 309 | end | ||
| 310 | |||
| 311 | def test_right_sibling_of_rightmost_node | ||
| 312 | assert_nil categories(:child_3).right_sibling | ||
| 313 | end | ||
| 314 | |||
| 315 | def test_move_left | ||
| 316 | categories(:child_2).move_left | ||
| 317 | assert_nil categories(:child_2).left_sibling | ||
| 318 | assert_equal categories(:child_1), categories(:child_2).right_sibling | ||
| 319 | assert Category.valid? | ||
| 320 | end | ||
| 321 | |||
| 322 | def test_move_right | ||
| 323 | categories(:child_2).move_right | ||
| 324 | assert_nil categories(:child_2).right_sibling | ||
| 325 | assert_equal categories(:child_3), categories(:child_2).left_sibling | ||
| 326 | assert Category.valid? | ||
| 327 | end | ||
| 328 | |||
| 329 | def test_move_to_left_of | ||
| 330 | categories(:child_3).move_to_left_of(categories(:child_1)) | ||
| 331 | assert_nil categories(:child_3).left_sibling | ||
| 332 | assert_equal categories(:child_1), categories(:child_3).right_sibling | ||
| 333 | assert Category.valid? | ||
| 334 | end | ||
| 335 | |||
| 336 | def test_move_to_right_of | ||
| 337 | categories(:child_1).move_to_right_of(categories(:child_3)) | ||
| 338 | assert_nil categories(:child_1).right_sibling | ||
| 339 | assert_equal categories(:child_3), categories(:child_1).left_sibling | ||
| 340 | assert Category.valid? | ||
| 341 | end | ||
| 342 | |||
| 343 | def test_move_to_root | ||
| 344 | categories(:child_2).move_to_root | ||
| 345 | assert_nil categories(:child_2).parent | ||
| 346 | assert_equal 0, categories(:child_2).level | ||
| 347 | assert_equal 1, categories(:child_2_1).level | ||
| 348 | assert_equal 1, categories(:child_2).left | ||
| 349 | assert_equal 4, categories(:child_2).right | ||
| 350 | assert Category.valid? | ||
| 351 | end | ||
| 352 | |||
| 353 | def test_move_to_child_of | ||
| 354 | categories(:child_1).move_to_child_of(categories(:child_3)) | ||
| 355 | assert_equal categories(:child_3).id, categories(:child_1).parent_id | ||
| 356 | assert Category.valid? | ||
| 357 | end | ||
| 358 | |||
| 359 | def test_move_to_child_of_appends_to_end | ||
| 360 | child = Category.create! :name => 'New Child' | ||
| 361 | child.move_to_child_of categories(:top_level) | ||
| 362 | assert_equal child, categories(:top_level).children.last | ||
| 363 | end | ||
| 364 | |||
| 365 | def test_subtree_move_to_child_of | ||
| 366 | assert_equal 4, categories(:child_2).left | ||
| 367 | assert_equal 7, categories(:child_2).right | ||
| 368 | |||
| 369 | assert_equal 2, categories(:child_1).left | ||
| 370 | assert_equal 3, categories(:child_1).right | ||
| 371 | |||
| 372 | categories(:child_2).move_to_child_of(categories(:child_1)) | ||
| 373 | assert Category.valid? | ||
| 374 | assert_equal categories(:child_1).id, categories(:child_2).parent_id | ||
| 375 | |||
| 376 | assert_equal 3, categories(:child_2).left | ||
| 377 | assert_equal 6, categories(:child_2).right | ||
| 378 | assert_equal 2, categories(:child_1).left | ||
| 379 | assert_equal 7, categories(:child_1).right | ||
| 380 | end | ||
| 381 | |||
| 382 | def test_slightly_difficult_move_to_child_of | ||
| 383 | assert_equal 11, categories(:top_level_2).left | ||
| 384 | assert_equal 12, categories(:top_level_2).right | ||
| 385 | |||
| 386 | # create a new top-level node and move single-node top-level tree inside it. | ||
| 387 | new_top = Category.create(:name => 'New Top') | ||
| 388 | assert_equal 13, new_top.left | ||
| 389 | assert_equal 14, new_top.right | ||
| 390 | |||
| 391 | categories(:top_level_2).move_to_child_of(new_top) | ||
| 392 | |||
| 393 | assert Category.valid? | ||
| 394 | assert_equal new_top.id, categories(:top_level_2).parent_id | ||
| 395 | |||
| 396 | assert_equal 12, categories(:top_level_2).left | ||
| 397 | assert_equal 13, categories(:top_level_2).right | ||
| 398 | assert_equal 11, new_top.left | ||
| 399 | assert_equal 14, new_top.right | ||
| 400 | end | ||
| 401 | |||
| 402 | def test_difficult_move_to_child_of | ||
| 403 | assert_equal 1, categories(:top_level).left | ||
| 404 | assert_equal 10, categories(:top_level).right | ||
| 405 | assert_equal 5, categories(:child_2_1).left | ||
| 406 | assert_equal 6, categories(:child_2_1).right | ||
| 407 | |||
| 408 | # create a new top-level node and move an entire top-level tree inside it. | ||
| 409 | new_top = Category.create(:name => 'New Top') | ||
| 410 | categories(:top_level).move_to_child_of(new_top) | ||
| 411 | categories(:child_2_1).reload | ||
| 412 | assert Category.valid? | ||
| 413 | assert_equal new_top.id, categories(:top_level).parent_id | ||
| 414 | |||
| 415 | assert_equal 4, categories(:top_level).left | ||
| 416 | assert_equal 13, categories(:top_level).right | ||
| 417 | assert_equal 8, categories(:child_2_1).left | ||
| 418 | assert_equal 9, categories(:child_2_1).right | ||
| 419 | end | ||
| 420 | |||
| 421 | #rebuild swaps the position of the 2 children when added using move_to_child twice onto same parent | ||
| 422 | def test_move_to_child_more_than_once_per_parent_rebuild | ||
| 423 | root1 = Category.create(:name => 'Root1') | ||
| 424 | root2 = Category.create(:name => 'Root2') | ||
| 425 | root3 = Category.create(:name => 'Root3') | ||
| 426 | |||
| 427 | root2.move_to_child_of root1 | ||
| 428 | root3.move_to_child_of root1 | ||
| 429 | |||
| 430 | output = Category.roots.last.to_text | ||
| 431 | Category.update_all('lft = null, rgt = null') | ||
| 432 | Category.rebuild! | ||
| 433 | |||
| 434 | assert_equal Category.roots.last.to_text, output | ||
| 435 | end | ||
| 436 | |||
| 437 | # doing move_to_child twice onto same parent from the furthest right first | ||
| 438 | def test_move_to_child_more_than_once_per_parent_outside_in | ||
| 439 | node1 = Category.create(:name => 'Node-1') | ||
| 440 | node2 = Category.create(:name => 'Node-2') | ||
| 441 | node3 = Category.create(:name => 'Node-3') | ||
| 442 | |||
| 443 | node2.move_to_child_of node1 | ||
| 444 | node3.move_to_child_of node1 | ||
| 445 | |||
| 446 | output = Category.roots.last.to_text | ||
| 447 | Category.update_all('lft = null, rgt = null') | ||
| 448 | Category.rebuild! | ||
| 449 | |||
| 450 | assert_equal Category.roots.last.to_text, output | ||
| 451 | end | ||
| 452 | |||
| 453 | |||
| 454 | def test_valid_with_null_lefts | ||
| 455 | assert Category.valid? | ||
| 456 | Category.update_all('lft = null') | ||
| 457 | assert !Category.valid? | ||
| 458 | end | ||
| 459 | |||
| 460 | def test_valid_with_null_rights | ||
| 461 | assert Category.valid? | ||
| 462 | Category.update_all('rgt = null') | ||
| 463 | assert !Category.valid? | ||
| 464 | end | ||
| 465 | |||
| 466 | def test_valid_with_missing_intermediate_node | ||
| 467 | # Even though child_2_1 will still exist, it is a sign of a sloppy delete, not an invalid tree. | ||
| 468 | assert Category.valid? | ||
| 469 | Category.delete(categories(:child_2).id) | ||
| 470 | assert Category.valid? | ||
| 471 | end | ||
| 472 | |||
| 473 | def test_valid_with_overlapping_and_rights | ||
| 474 | assert Category.valid? | ||
| 475 | categories(:top_level_2)['lft'] = 0 | ||
| 476 | categories(:top_level_2).save | ||
| 477 | assert !Category.valid? | ||
| 478 | end | ||
| 479 | |||
| 480 | def test_rebuild | ||
| 481 | assert Category.valid? | ||
| 482 | before_text = Category.root.to_text | ||
| 483 | Category.update_all('lft = null, rgt = null') | ||
| 484 | Category.rebuild! | ||
| 485 | assert Category.valid? | ||
| 486 | assert_equal before_text, Category.root.to_text | ||
| 487 | end | ||
| 488 | |||
| 489 | def test_move_possible_for_sibling | ||
| 490 | assert categories(:child_2).move_possible?(categories(:child_1)) | ||
| 491 | end | ||
| 492 | |||
| 493 | def test_move_not_possible_to_self | ||
| 494 | assert !categories(:top_level).move_possible?(categories(:top_level)) | ||
| 495 | end | ||
| 496 | |||
| 497 | def test_move_not_possible_to_parent | ||
| 498 | categories(:top_level).descendants.each do |descendant| | ||
| 499 | assert !categories(:top_level).move_possible?(descendant) | ||
| 500 | assert descendant.move_possible?(categories(:top_level)) | ||
| 501 | end | ||
| 502 | end | ||
| 503 | |||
| 504 | def test_is_or_is_ancestor_of? | ||
| 505 | [:child_1, :child_2, :child_2_1, :child_3].each do |c| | ||
| 506 | assert categories(:top_level).is_or_is_ancestor_of?(categories(c)) | ||
| 507 | end | ||
| 508 | assert !categories(:top_level).is_or_is_ancestor_of?(categories(:top_level_2)) | ||
| 509 | end | ||
| 510 | |||
| 511 | def test_left_and_rights_valid_with_blank_left | ||
| 512 | assert Category.left_and_rights_valid? | ||
| 513 | categories(:child_2)[:lft] = nil | ||
| 514 | categories(:child_2).save(false) | ||
| 515 | assert !Category.left_and_rights_valid? | ||
| 516 | end | ||
| 517 | |||
| 518 | def test_left_and_rights_valid_with_blank_right | ||
| 519 | assert Category.left_and_rights_valid? | ||
| 520 | categories(:child_2)[:rgt] = nil | ||
| 521 | categories(:child_2).save(false) | ||
| 522 | assert !Category.left_and_rights_valid? | ||
| 523 | end | ||
| 524 | |||
| 525 | def test_left_and_rights_valid_with_equal | ||
| 526 | assert Category.left_and_rights_valid? | ||
| 527 | categories(:top_level_2)[:lft] = categories(:top_level_2)[:rgt] | ||
| 528 | categories(:top_level_2).save(false) | ||
| 529 | assert !Category.left_and_rights_valid? | ||
| 530 | end | ||
| 531 | |||
| 532 | def test_left_and_rights_valid_with_left_equal_to_parent | ||
| 533 | assert Category.left_and_rights_valid? | ||
| 534 | categories(:child_2)[:lft] = categories(:top_level)[:lft] | ||
| 535 | categories(:child_2).save(false) | ||
| 536 | assert !Category.left_and_rights_valid? | ||
| 537 | end | ||
| 538 | |||
| 539 | def test_left_and_rights_valid_with_right_equal_to_parent | ||
| 540 | assert Category.left_and_rights_valid? | ||
| 541 | categories(:child_2)[:rgt] = categories(:top_level)[:rgt] | ||
| 542 | categories(:child_2).save(false) | ||
| 543 | assert !Category.left_and_rights_valid? | ||
| 544 | end | ||
| 545 | |||
| 546 | def test_moving_dirty_objects_doesnt_invalidate_tree | ||
| 547 | r1 = Category.create | ||
| 548 | r2 = Category.create | ||
| 549 | r3 = Category.create | ||
| 550 | r4 = Category.create | ||
| 551 | nodes = [r1, r2, r3, r4] | ||
| 552 | |||
| 553 | r2.move_to_child_of(r1) | ||
| 554 | assert Category.valid? | ||
| 555 | |||
| 556 | r3.move_to_child_of(r1) | ||
| 557 | assert Category.valid? | ||
| 558 | |||
| 559 | r4.move_to_child_of(r2) | ||
| 560 | assert Category.valid? | ||
| 561 | end | ||
| 562 | |||
| 563 | def test_multi_scoped_no_duplicates_for_columns? | ||
| 564 | assert_nothing_raised do | ||
| 565 | Note.no_duplicates_for_columns? | ||
| 566 | end | ||
| 567 | end | ||
| 568 | |||
| 569 | def test_multi_scoped_all_roots_valid? | ||
| 570 | assert_nothing_raised do | ||
| 571 | Note.all_roots_valid? | ||
| 572 | end | ||
| 573 | end | ||
| 574 | |||
| 575 | def test_multi_scoped | ||
| 576 | note1 = Note.create!(:body => "A", :notable_id => 2, :notable_type => 'Category') | ||
| 577 | note2 = Note.create!(:body => "B", :notable_id => 2, :notable_type => 'Category') | ||
| 578 | note3 = Note.create!(:body => "C", :notable_id => 2, :notable_type => 'Default') | ||
| 579 | |||
| 580 | assert_equal [note1, note2], note1.self_and_siblings | ||
| 581 | assert_equal [note3], note3.self_and_siblings | ||
| 582 | end | ||
| 583 | |||
| 584 | def test_multi_scoped_rebuild | ||
| 585 | root = Note.create!(:body => "A", :notable_id => 3, :notable_type => 'Category') | ||
| 586 | child1 = Note.create!(:body => "B", :notable_id => 3, :notable_type => 'Category') | ||
| 587 | child2 = Note.create!(:body => "C", :notable_id => 3, :notable_type => 'Category') | ||
| 588 | |||
| 589 | child1.move_to_child_of root | ||
| 590 | child2.move_to_child_of root | ||
| 591 | |||
| 592 | Note.update_all('lft = null, rgt = null') | ||
| 593 | Note.rebuild! | ||
| 594 | |||
| 595 | assert_equal Note.roots.find_by_body('A'), root | ||
| 596 | assert_equal [child1, child2], Note.roots.find_by_body('A').children | ||
| 597 | end | ||
| 598 | |||
| 599 | def test_same_scope_with_multi_scopes | ||
| 600 | assert_nothing_raised do | ||
| 601 | notes(:scope1).same_scope?(notes(:child_1)) | ||
| 602 | end | ||
| 603 | assert notes(:scope1).same_scope?(notes(:child_1)) | ||
| 604 | assert notes(:child_1).same_scope?(notes(:scope1)) | ||
| 605 | assert !notes(:scope1).same_scope?(notes(:scope2)) | ||
| 606 | end | ||
| 607 | |||
| 608 | def test_quoting_of_multi_scope_column_names | ||
| 609 | assert_equal ["\"notable_id\"", "\"notable_type\""], Note.quoted_scope_column_names | ||
| 610 | end | ||
| 611 | |||
| 612 | def test_equal_in_same_scope | ||
| 613 | assert_equal notes(:scope1), notes(:scope1) | ||
| 614 | assert_not_equal notes(:scope1), notes(:child_1) | ||
| 615 | end | ||
| 616 | |||
| 617 | def test_equal_in_different_scopes | ||
| 618 | assert_not_equal notes(:scope1), notes(:scope2) | ||
| 619 | end | ||
| 620 | |||
| 621 | def test_delete_does_not_invalidate | ||
| 622 | Category.acts_as_nested_set_options[:dependent] = :delete | ||
| 623 | categories(:child_2).destroy | ||
| 624 | assert Category.valid? | ||
| 625 | end | ||
| 626 | |||
| 627 | def test_destroy_does_not_invalidate | ||
| 628 | Category.acts_as_nested_set_options[:dependent] = :destroy | ||
| 629 | categories(:child_2).destroy | ||
| 630 | assert Category.valid? | ||
| 631 | end | ||
| 632 | |||
| 633 | def test_destroy_multiple_times_does_not_invalidate | ||
| 634 | Category.acts_as_nested_set_options[:dependent] = :destroy | ||
| 635 | categories(:child_2).destroy | ||
| 636 | categories(:child_2).destroy | ||
| 637 | assert Category.valid? | ||
| 638 | end | ||
| 639 | |||
| 640 | def test_assigning_parent_id_on_create | ||
| 641 | category = Category.create!(:name => "Child", :parent_id => categories(:child_2).id) | ||
| 642 | assert_equal categories(:child_2), category.parent | ||
| 643 | assert_equal categories(:child_2).id, category.parent_id | ||
| 644 | assert_not_nil category.left | ||
| 645 | assert_not_nil category.right | ||
| 646 | assert Category.valid? | ||
| 647 | end | ||
| 648 | |||
| 649 | def test_assigning_parent_on_create | ||
| 650 | category = Category.create!(:name => "Child", :parent => categories(:child_2)) | ||
| 651 | assert_equal categories(:child_2), category.parent | ||
| 652 | assert_equal categories(:child_2).id, category.parent_id | ||
| 653 | assert_not_nil category.left | ||
| 654 | assert_not_nil category.right | ||
| 655 | assert Category.valid? | ||
| 656 | end | ||
| 657 | |||
| 658 | def test_assigning_parent_id_to_nil_on_create | ||
| 659 | category = Category.create!(:name => "New Root", :parent_id => nil) | ||
| 660 | assert_nil category.parent | ||
| 661 | assert_nil category.parent_id | ||
| 662 | assert_not_nil category.left | ||
| 663 | assert_not_nil category.right | ||
| 664 | assert Category.valid? | ||
| 665 | end | ||
| 666 | |||
| 667 | def test_assigning_parent_id_on_update | ||
| 668 | category = categories(:child_2_1) | ||
| 669 | category.parent_id = categories(:child_3).id | ||
| 670 | category.save | ||
| 671 | assert_equal categories(:child_3), category.parent | ||
| 672 | assert_equal categories(:child_3).id, category.parent_id | ||
| 673 | assert Category.valid? | ||
| 674 | end | ||
| 675 | |||
| 676 | def test_assigning_parent_on_update | ||
| 677 | category = categories(:child_2_1) | ||
| 678 | category.parent = categories(:child_3) | ||
| 679 | category.save | ||
| 680 | assert_equal categories(:child_3), category.parent | ||
| 681 | assert_equal categories(:child_3).id, category.parent_id | ||
| 682 | assert Category.valid? | ||
| 683 | end | ||
| 684 | |||
| 685 | def test_assigning_parent_id_to_nil_on_update | ||
| 686 | category = categories(:child_2_1) | ||
| 687 | category.parent_id = nil | ||
| 688 | category.save | ||
| 689 | assert_nil category.parent | ||
| 690 | assert_nil category.parent_id | ||
| 691 | assert Category.valid? | ||
| 692 | end | ||
| 693 | |||
| 694 | def test_creating_child_from_parent | ||
| 695 | category = categories(:child_2).children.create!(:name => "Child") | ||
| 696 | assert_equal categories(:child_2), category.parent | ||
| 697 | assert_equal categories(:child_2).id, category.parent_id | ||
| 698 | assert_not_nil category.left | ||
| 699 | assert_not_nil category.right | ||
| 700 | assert Category.valid? | ||
| 701 | end | ||
| 702 | |||
| 703 | def check_structure(entries, structure) | ||
| 704 | structure = structure.dup | ||
| 705 | Category.each_with_level(entries) do |category, level| | ||
| 706 | expected_level, expected_name = structure.shift | ||
| 707 | assert_equal expected_name, category.name, "wrong category" | ||
| 708 | assert_equal expected_level, level, "wrong level for #{category.name}" | ||
| 709 | end | ||
| 710 | end | ||
| 711 | |||
| 712 | def test_each_with_level | ||
| 713 | levels = [ | ||
| 714 | [0, "Top Level"], | ||
| 715 | [1, "Child 1"], | ||
| 716 | [1, "Child 2"], | ||
| 717 | [2, "Child 2.1"], | ||
| 718 | [1, "Child 3" ]] | ||
| 719 | |||
| 720 | check_structure(Category.root.self_and_descendants, levels) | ||
| 721 | |||
| 722 | # test some deeper structures | ||
| 723 | category = Category.find_by_name("Child 1") | ||
| 724 | c1 = Category.new(:name => "Child 1.1") | ||
| 725 | c2 = Category.new(:name => "Child 1.1.1") | ||
| 726 | c3 = Category.new(:name => "Child 1.1.1.1") | ||
| 727 | c4 = Category.new(:name => "Child 1.2") | ||
| 728 | [c1, c2, c3, c4].each(&:save!) | ||
| 729 | |||
| 730 | c1.move_to_child_of(category) | ||
| 731 | c2.move_to_child_of(c1) | ||
| 732 | c3.move_to_child_of(c2) | ||
| 733 | c4.move_to_child_of(category) | ||
| 734 | |||
| 735 | levels = [ | ||
| 736 | [0, "Top Level"], | ||
| 737 | [1, "Child 1"], | ||
| 738 | [2, "Child 1.1"], | ||
| 739 | [3, "Child 1.1.1"], | ||
| 740 | [4, "Child 1.1.1.1"], | ||
| 741 | [2, "Child 1.2"], | ||
| 742 | [1, "Child 2"], | ||
| 743 | [2, "Child 2.1"], | ||
| 744 | [1, "Child 3" ]] | ||
| 745 | |||
| 746 | check_structure(Category.root.self_and_descendants, levels) | ||
| 747 | end | ||
| 748 | end | ||
diff --git a/vendor/plugins/awesome_nested_set/test/fixtures/categories.yml b/vendor/plugins/awesome_nested_set/test/fixtures/categories.yml deleted file mode 100644 index bc8e078..0000000 --- a/vendor/plugins/awesome_nested_set/test/fixtures/categories.yml +++ /dev/null | |||
| @@ -1,34 +0,0 @@ | |||
| 1 | top_level: | ||
| 2 | id: 1 | ||
| 3 | name: Top Level | ||
| 4 | lft: 1 | ||
| 5 | rgt: 10 | ||
| 6 | child_1: | ||
| 7 | id: 2 | ||
| 8 | name: Child 1 | ||
| 9 | parent_id: 1 | ||
| 10 | lft: 2 | ||
| 11 | rgt: 3 | ||
| 12 | child_2: | ||
| 13 | id: 3 | ||
| 14 | name: Child 2 | ||
| 15 | parent_id: 1 | ||
| 16 | lft: 4 | ||
| 17 | rgt: 7 | ||
| 18 | child_2_1: | ||
| 19 | id: 4 | ||
| 20 | name: Child 2.1 | ||
| 21 | parent_id: 3 | ||
| 22 | lft: 5 | ||
| 23 | rgt: 6 | ||
| 24 | child_3: | ||
| 25 | id: 5 | ||
| 26 | name: Child 3 | ||
| 27 | parent_id: 1 | ||
| 28 | lft: 8 | ||
| 29 | rgt: 9 | ||
| 30 | top_level_2: | ||
| 31 | id: 6 | ||
| 32 | name: Top Level 2 | ||
| 33 | lft: 11 | ||
| 34 | rgt: 12 | ||
diff --git a/vendor/plugins/awesome_nested_set/test/fixtures/category.rb b/vendor/plugins/awesome_nested_set/test/fixtures/category.rb deleted file mode 100644 index 506b0da..0000000 --- a/vendor/plugins/awesome_nested_set/test/fixtures/category.rb +++ /dev/null | |||
| @@ -1,15 +0,0 @@ | |||
| 1 | class Category < ActiveRecord::Base | ||
| 2 | acts_as_nested_set | ||
| 3 | |||
| 4 | def to_s | ||
| 5 | name | ||
| 6 | end | ||
| 7 | |||
| 8 | def recurse &block | ||
| 9 | block.call self, lambda{ | ||
| 10 | self.children.each do |child| | ||
| 11 | child.recurse &block | ||
| 12 | end | ||
| 13 | } | ||
| 14 | end | ||
| 15 | end \ No newline at end of file | ||
diff --git a/vendor/plugins/awesome_nested_set/test/fixtures/departments.yml b/vendor/plugins/awesome_nested_set/test/fixtures/departments.yml deleted file mode 100644 index e50a944..0000000 --- a/vendor/plugins/awesome_nested_set/test/fixtures/departments.yml +++ /dev/null | |||
| @@ -1,3 +0,0 @@ | |||
| 1 | top: | ||
| 2 | id: 1 | ||
| 3 | name: Top \ No newline at end of file | ||
diff --git a/vendor/plugins/awesome_nested_set/test/fixtures/notes.yml b/vendor/plugins/awesome_nested_set/test/fixtures/notes.yml deleted file mode 100644 index 004a533..0000000 --- a/vendor/plugins/awesome_nested_set/test/fixtures/notes.yml +++ /dev/null | |||
| @@ -1,38 +0,0 @@ | |||
| 1 | scope1: | ||
| 2 | id: 1 | ||
| 3 | body: Top Level | ||
| 4 | lft: 1 | ||
| 5 | rgt: 10 | ||
| 6 | notable_id: 1 | ||
| 7 | notable_type: Category | ||
| 8 | child_1: | ||
| 9 | id: 2 | ||
| 10 | body: Child 1 | ||
| 11 | parent_id: 1 | ||
| 12 | lft: 2 | ||
| 13 | rgt: 3 | ||
| 14 | notable_id: 1 | ||
| 15 | notable_type: Category | ||
| 16 | child_2: | ||
| 17 | id: 3 | ||
| 18 | body: Child 2 | ||
| 19 | parent_id: 1 | ||
| 20 | lft: 4 | ||
| 21 | rgt: 7 | ||
| 22 | notable_id: 1 | ||
| 23 | notable_type: Category | ||
| 24 | child_3: | ||
| 25 | id: 4 | ||
| 26 | body: Child 3 | ||
| 27 | parent_id: 1 | ||
| 28 | lft: 8 | ||
| 29 | rgt: 9 | ||
| 30 | notable_id: 1 | ||
| 31 | notable_type: Category | ||
| 32 | scope2: | ||
| 33 | id: 5 | ||
| 34 | body: Top Level 2 | ||
| 35 | lft: 1 | ||
| 36 | rgt: 2 | ||
| 37 | notable_id: 1 | ||
| 38 | notable_type: Departments | ||
diff --git a/vendor/plugins/awesome_nested_set/test/test_helper.rb b/vendor/plugins/awesome_nested_set/test/test_helper.rb deleted file mode 100644 index 05d8855..0000000 --- a/vendor/plugins/awesome_nested_set/test/test_helper.rb +++ /dev/null | |||
| @@ -1,29 +0,0 @@ | |||
| 1 | $:.unshift(File.dirname(__FILE__) + '/../lib') | ||
| 2 | plugin_test_dir = File.dirname(__FILE__) | ||
| 3 | RAILS_ROOT = plugin_test_dir | ||
| 4 | |||
| 5 | require 'rubygems' | ||
| 6 | require 'test/unit' | ||
| 7 | require 'multi_rails_init' | ||
| 8 | require 'test_help' | ||
| 9 | |||
| 10 | require plugin_test_dir + '/../init.rb' | ||
| 11 | |||
| 12 | TestCaseClass = ActiveSupport::TestCase rescue Test::Unit::TestCase | ||
| 13 | |||
| 14 | ActiveRecord::Base.logger = Logger.new(plugin_test_dir + "/debug.log") | ||
| 15 | |||
| 16 | ActiveRecord::Base.configurations = YAML::load(IO.read(plugin_test_dir + "/db/database.yml")) | ||
| 17 | ActiveRecord::Base.establish_connection(ENV["DB"] || "sqlite3mem") | ||
| 18 | ActiveRecord::Migration.verbose = false | ||
| 19 | load(File.join(plugin_test_dir, "db", "schema.rb")) | ||
| 20 | |||
| 21 | Dir["#{plugin_test_dir}/fixtures/*.rb"].each {|file| require file } | ||
| 22 | |||
| 23 | class TestCaseClass #:nodoc: | ||
| 24 | self.fixture_path = File.dirname(__FILE__) + "/fixtures/" | ||
| 25 | self.use_transactional_fixtures = true | ||
| 26 | self.use_instantiated_fixtures = false | ||
| 27 | |||
| 28 | fixtures :categories, :notes, :departments | ||
| 29 | end | ||
diff --git a/vendor/plugins/exception_notification/README b/vendor/plugins/exception_notification/README deleted file mode 100644 index 9a47c41..0000000 --- a/vendor/plugins/exception_notification/README +++ /dev/null | |||
| @@ -1,111 +0,0 @@ | |||
| 1 | = Exception Notifier Plugin for Rails | ||
| 2 | |||
| 3 | The Exception Notifier plugin provides a mailer object and a default set of | ||
| 4 | templates for sending email notifications when errors occur in a Rails | ||
| 5 | application. The plugin is configurable, allowing programmers to specify: | ||
| 6 | |||
| 7 | * the sender address of the email | ||
| 8 | * the recipient addresses | ||
| 9 | * the text used to prefix the subject line | ||
| 10 | |||
| 11 | The email includes information about the current request, session, and | ||
| 12 | environment, and also gives a backtrace of the exception. | ||
| 13 | |||
| 14 | == Usage | ||
| 15 | |||
| 16 | First, include the ExceptionNotifiable mixin in whichever controller you want | ||
| 17 | to generate error emails (typically ApplicationController): | ||
| 18 | |||
| 19 | class ApplicationController < ActionController::Base | ||
| 20 | include ExceptionNotifiable | ||
| 21 | ... | ||
| 22 | end | ||
| 23 | |||
| 24 | Then, specify the email recipients in your environment: | ||
| 25 | |||
| 26 | ExceptionNotifier.exception_recipients = %w(joe@schmoe.com bill@schmoe.com) | ||
| 27 | |||
| 28 | And that's it! The defaults take care of the rest. | ||
| 29 | |||
| 30 | == Configuration | ||
| 31 | |||
| 32 | You can tweak other values to your liking, as well. In your environment file, | ||
| 33 | just set any or all of the following values: | ||
| 34 | |||
| 35 | # defaults to exception.notifier@default.com | ||
| 36 | ExceptionNotifier.sender_address = | ||
| 37 | %("Application Error" <app.error@myapp.com>) | ||
| 38 | |||
| 39 | # defaults to "[ERROR] " | ||
| 40 | ExceptionNotifier.email_prefix = "[APP] " | ||
| 41 | |||
| 42 | Email notifications will only occur when the IP address is determined not to | ||
| 43 | be local. You can specify certain addresses to always be local so that you'll | ||
| 44 | get a detailed error instead of the generic error page. You do this in your | ||
| 45 | controller (or even per-controller): | ||
| 46 | |||
| 47 | consider_local "64.72.18.143", "14.17.21.25" | ||
| 48 | |||
| 49 | You can specify subnet masks as well, so that all matching addresses are | ||
| 50 | considered local: | ||
| 51 | |||
| 52 | consider_local "64.72.18.143/24" | ||
| 53 | |||
| 54 | The address "127.0.0.1" is always considered local. If you want to completely | ||
| 55 | reset the list of all addresses (for instance, if you wanted "127.0.0.1" to | ||
| 56 | NOT be considered local), you can simply do, somewhere in your controller: | ||
| 57 | |||
| 58 | local_addresses.clear | ||
| 59 | |||
| 60 | == Customization | ||
| 61 | |||
| 62 | By default, the notification email includes four parts: request, session, | ||
| 63 | environment, and backtrace (in that order). You can customize how each of those | ||
| 64 | sections are rendered by placing a partial named for that part in your | ||
| 65 | app/views/exception_notifier directory (e.g., _session.rhtml). Each partial has | ||
| 66 | access to the following variables: | ||
| 67 | |||
| 68 | * @controller: the controller that caused the error | ||
| 69 | * @request: the current request object | ||
| 70 | * @exception: the exception that was raised | ||
| 71 | * @host: the name of the host that made the request | ||
| 72 | * @backtrace: a sanitized version of the exception's backtrace | ||
| 73 | * @rails_root: a sanitized version of RAILS_ROOT | ||
| 74 | * @data: a hash of optional data values that were passed to the notifier | ||
| 75 | * @sections: the array of sections to include in the email | ||
| 76 | |||
| 77 | You can reorder the sections, or exclude sections completely, by altering the | ||
| 78 | ExceptionNotifier.sections variable. You can even add new sections that | ||
| 79 | describe application-specific data--just add the section's name to the list | ||
| 80 | (whereever you'd like), and define the corresponding partial. Then, if your | ||
| 81 | new section requires information that isn't available by default, make sure | ||
| 82 | it is made available to the email using the exception_data macro: | ||
| 83 | |||
| 84 | class ApplicationController < ActionController::Base | ||
| 85 | ... | ||
| 86 | protected | ||
| 87 | exception_data :additional_data | ||
| 88 | |||
| 89 | def additional_data | ||
| 90 | { :document => @document, | ||
| 91 | :person => @person } | ||
| 92 | end | ||
| 93 | ... | ||
| 94 | end | ||
| 95 | |||
| 96 | In the above case, @document and @person would be made available to the email | ||
| 97 | renderer, allowing your new section(s) to access and display them. See the | ||
| 98 | existing sections defined by the plugin for examples of how to write your own. | ||
| 99 | |||
| 100 | == Advanced Customization | ||
| 101 | |||
| 102 | By default, the email notifier will only notify on critical errors. For | ||
| 103 | ActiveRecord::RecordNotFound and ActionController::UnknownAction, it will | ||
| 104 | simply render the contents of your public/404.html file. Other exceptions | ||
| 105 | will render public/500.html and will send the email notification. If you want | ||
| 106 | to use different rules for the notification, you will need to implement your | ||
| 107 | own rescue_action_in_public method. You can look at the default implementation | ||
| 108 | in ExceptionNotifiable for an example of how to go about that. | ||
| 109 | |||
| 110 | |||
| 111 | Copyright (c) 2005 Jamis Buck, released under the MIT license \ No newline at end of file | ||
diff --git a/vendor/plugins/exception_notification/init.rb b/vendor/plugins/exception_notification/init.rb deleted file mode 100644 index 4d9d76e..0000000 --- a/vendor/plugins/exception_notification/init.rb +++ /dev/null | |||
| @@ -1,4 +0,0 @@ | |||
| 1 | require "action_mailer" | ||
| 2 | require "exception_notifier" | ||
| 3 | require "exception_notifiable" | ||
| 4 | require "exception_notifier_helper" | ||
diff --git a/vendor/plugins/exception_notification/lib/exception_notifiable.rb b/vendor/plugins/exception_notification/lib/exception_notifiable.rb deleted file mode 100644 index d5e28fc..0000000 --- a/vendor/plugins/exception_notification/lib/exception_notifiable.rb +++ /dev/null | |||
| @@ -1,99 +0,0 @@ | |||
| 1 | require 'ipaddr' | ||
| 2 | |||
| 3 | # Copyright (c) 2005 Jamis Buck | ||
| 4 | # | ||
| 5 | # Permission is hereby granted, free of charge, to any person obtaining | ||
| 6 | # a copy of this software and associated documentation files (the | ||
| 7 | # "Software"), to deal in the Software without restriction, including | ||
| 8 | # without limitation the rights to use, copy, modify, merge, publish, | ||
| 9 | # distribute, sublicense, and/or sell copies of the Software, and to | ||
| 10 | # permit persons to whom the Software is furnished to do so, subject to | ||
| 11 | # the following conditions: | ||
| 12 | # | ||
| 13 | # The above copyright notice and this permission notice shall be | ||
| 14 | # included in all copies or substantial portions of the Software. | ||
| 15 | # | ||
| 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
| 17 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
| 18 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
| 19 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
| 20 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
| 21 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
| 22 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 23 | module ExceptionNotifiable | ||
| 24 | def self.included(target) | ||
| 25 | target.extend(ClassMethods) | ||
| 26 | end | ||
| 27 | |||
| 28 | module ClassMethods | ||
| 29 | def consider_local(*args) | ||
| 30 | local_addresses.concat(args.flatten.map { |a| IPAddr.new(a) }) | ||
| 31 | end | ||
| 32 | |||
| 33 | def local_addresses | ||
| 34 | addresses = read_inheritable_attribute(:local_addresses) | ||
| 35 | unless addresses | ||
| 36 | addresses = [IPAddr.new("127.0.0.1")] | ||
| 37 | write_inheritable_attribute(:local_addresses, addresses) | ||
| 38 | end | ||
| 39 | addresses | ||
| 40 | end | ||
| 41 | |||
| 42 | def exception_data(deliverer=self) | ||
| 43 | if deliverer == self | ||
| 44 | read_inheritable_attribute(:exception_data) | ||
| 45 | else | ||
| 46 | write_inheritable_attribute(:exception_data, deliverer) | ||
| 47 | end | ||
| 48 | end | ||
| 49 | |||
| 50 | def exceptions_to_treat_as_404 | ||
| 51 | exceptions = [ActiveRecord::RecordNotFound, | ||
| 52 | ActionController::UnknownController, | ||
| 53 | ActionController::UnknownAction] | ||
| 54 | exceptions << ActionController::RoutingError if ActionController.const_defined?(:RoutingError) | ||
| 55 | exceptions | ||
| 56 | end | ||
| 57 | end | ||
| 58 | |||
| 59 | private | ||
| 60 | |||
| 61 | def local_request? | ||
| 62 | remote = IPAddr.new(request.remote_ip) | ||
| 63 | !self.class.local_addresses.detect { |addr| addr.include?(remote) }.nil? | ||
| 64 | end | ||
| 65 | |||
| 66 | def render_404 | ||
| 67 | respond_to do |type| | ||
| 68 | type.html { render :file => "#{RAILS_ROOT}/public/404.html", :status => "404 Not Found" } | ||
| 69 | type.all { render :nothing => true, :status => "404 Not Found" } | ||
| 70 | end | ||
| 71 | end | ||
| 72 | |||
| 73 | def render_500 | ||
| 74 | respond_to do |type| | ||
| 75 | type.html { render :file => "#{RAILS_ROOT}/public/500.html", :status => "500 Error" } | ||
| 76 | type.all { render :nothing => true, :status => "500 Error" } | ||
| 77 | end | ||
| 78 | end | ||
| 79 | |||
| 80 | def rescue_action_in_public(exception) | ||
| 81 | case exception | ||
| 82 | when *self.class.exceptions_to_treat_as_404 | ||
| 83 | render_404 | ||
| 84 | |||
| 85 | else | ||
| 86 | render_500 | ||
| 87 | |||
| 88 | deliverer = self.class.exception_data | ||
| 89 | data = case deliverer | ||
| 90 | when nil then {} | ||
| 91 | when Symbol then send(deliverer) | ||
| 92 | when Proc then deliverer.call(self) | ||
| 93 | end | ||
| 94 | |||
| 95 | ExceptionNotifier.deliver_exception_notification(exception, self, | ||
| 96 | request, data) | ||
| 97 | end | ||
| 98 | end | ||
| 99 | end | ||
diff --git a/vendor/plugins/exception_notification/lib/exception_notifier.rb b/vendor/plugins/exception_notification/lib/exception_notifier.rb deleted file mode 100644 index 72e2e1a..0000000 --- a/vendor/plugins/exception_notification/lib/exception_notifier.rb +++ /dev/null | |||
| @@ -1,66 +0,0 @@ | |||
| 1 | require 'pathname' | ||
| 2 | |||
| 3 | # Copyright (c) 2005 Jamis Buck | ||
| 4 | # | ||
| 5 | # Permission is hereby granted, free of charge, to any person obtaining | ||
| 6 | # a copy of this software and associated documentation files (the | ||
| 7 | # "Software"), to deal in the Software without restriction, including | ||
| 8 | # without limitation the rights to use, copy, modify, merge, publish, | ||
| 9 | # distribute, sublicense, and/or sell copies of the Software, and to | ||
| 10 | # permit persons to whom the Software is furnished to do so, subject to | ||
| 11 | # the following conditions: | ||
| 12 | # | ||
| 13 | # The above copyright notice and this permission notice shall be | ||
| 14 | # included in all copies or substantial portions of the Software. | ||
| 15 | # | ||
| 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
| 17 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
| 18 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
| 19 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
| 20 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
| 21 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
| 22 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 23 | class ExceptionNotifier < ActionMailer::Base | ||
| 24 | @@sender_address = %("Exception Notifier" <exception.notifier@default.com>) | ||
| 25 | cattr_accessor :sender_address | ||
| 26 | |||
| 27 | @@exception_recipients = [] | ||
| 28 | cattr_accessor :exception_recipients | ||
| 29 | |||
| 30 | @@email_prefix = "[ERROR] " | ||
| 31 | cattr_accessor :email_prefix | ||
| 32 | |||
| 33 | @@sections = %w(request session environment backtrace) | ||
| 34 | cattr_accessor :sections | ||
| 35 | |||
| 36 | self.template_root = "#{File.dirname(__FILE__)}/../views" | ||
| 37 | |||
| 38 | def self.reloadable?() false end | ||
| 39 | |||
| 40 | def exception_notification(exception, controller, request, data={}) | ||
| 41 | content_type "text/plain" | ||
| 42 | |||
| 43 | subject "#{email_prefix}#{controller.controller_name}##{controller.action_name} (#{exception.class}) #{exception.message.inspect}" | ||
| 44 | |||
| 45 | recipients exception_recipients | ||
| 46 | from sender_address | ||
| 47 | |||
| 48 | body data.merge({ :controller => controller, :request => request, | ||
| 49 | :exception => exception, :host => (request.env["HTTP_X_FORWARDED_HOST"] || request.env["HTTP_HOST"]), | ||
| 50 | :backtrace => sanitize_backtrace(exception.backtrace), | ||
| 51 | :rails_root => rails_root, :data => data, | ||
| 52 | :sections => sections }) | ||
| 53 | end | ||
| 54 | |||
| 55 | private | ||
| 56 | |||
| 57 | def sanitize_backtrace(trace) | ||
| 58 | re = Regexp.new(/^#{Regexp.escape(rails_root)}/) | ||
| 59 | trace.map { |line| Pathname.new(line.gsub(re, "[RAILS_ROOT]")).cleanpath.to_s } | ||
| 60 | end | ||
| 61 | |||
| 62 | def rails_root | ||
| 63 | @rails_root ||= Pathname.new(RAILS_ROOT).cleanpath.to_s | ||
| 64 | end | ||
| 65 | |||
| 66 | end | ||
diff --git a/vendor/plugins/exception_notification/lib/exception_notifier_helper.rb b/vendor/plugins/exception_notification/lib/exception_notifier_helper.rb deleted file mode 100644 index d3dc63a..0000000 --- a/vendor/plugins/exception_notification/lib/exception_notifier_helper.rb +++ /dev/null | |||
| @@ -1,78 +0,0 @@ | |||
| 1 | require 'pp' | ||
| 2 | |||
| 3 | # Copyright (c) 2005 Jamis Buck | ||
| 4 | # | ||
| 5 | # Permission is hereby granted, free of charge, to any person obtaining | ||
| 6 | # a copy of this software and associated documentation files (the | ||
| 7 | # "Software"), to deal in the Software without restriction, including | ||
| 8 | # without limitation the rights to use, copy, modify, merge, publish, | ||
| 9 | # distribute, sublicense, and/or sell copies of the Software, and to | ||
| 10 | # permit persons to whom the Software is furnished to do so, subject to | ||
| 11 | # the following conditions: | ||
| 12 | # | ||
| 13 | # The above copyright notice and this permission notice shall be | ||
| 14 | # included in all copies or substantial portions of the Software. | ||
| 15 | # | ||
| 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
| 17 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
| 18 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
| 19 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
| 20 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
| 21 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
| 22 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 23 | module ExceptionNotifierHelper | ||
| 24 | VIEW_PATH = "views/exception_notifier" | ||
| 25 | APP_PATH = "#{RAILS_ROOT}/app/#{VIEW_PATH}" | ||
| 26 | PARAM_FILTER_REPLACEMENT = "[FILTERED]" | ||
| 27 | |||
| 28 | def render_section(section) | ||
| 29 | RAILS_DEFAULT_LOGGER.info("rendering section #{section.inspect}") | ||
| 30 | summary = render_overridable(section).strip | ||
| 31 | unless summary.blank? | ||
| 32 | title = render_overridable(:title, :locals => { :title => section }).strip | ||
| 33 | "#{title}\n\n#{summary.gsub(/^/, " ")}\n\n" | ||
| 34 | end | ||
| 35 | end | ||
| 36 | |||
| 37 | def render_overridable(partial, options={}) | ||
| 38 | if File.exist?(path = "#{APP_PATH}/_#{partial}.rhtml") | ||
| 39 | render(options.merge(:file => path, :use_full_path => false)) | ||
| 40 | elsif File.exist?(path = "#{File.dirname(__FILE__)}/../#{VIEW_PATH}/_#{partial}.rhtml") | ||
| 41 | render(options.merge(:file => path, :use_full_path => false)) | ||
| 42 | else | ||
| 43 | "" | ||
| 44 | end | ||
| 45 | end | ||
| 46 | |||
| 47 | def inspect_model_object(model, locals={}) | ||
| 48 | render_overridable(:inspect_model, | ||
| 49 | :locals => { :inspect_model => model, | ||
| 50 | :show_instance_variables => true, | ||
| 51 | :show_attributes => true }.merge(locals)) | ||
| 52 | end | ||
| 53 | |||
| 54 | def inspect_value(value) | ||
| 55 | len = 512 | ||
| 56 | result = object_to_yaml(value).gsub(/\n/, "\n ").strip | ||
| 57 | result = result[0,len] + "... (#{result.length-len} bytes more)" if result.length > len+20 | ||
| 58 | result | ||
| 59 | end | ||
| 60 | |||
| 61 | def object_to_yaml(object) | ||
| 62 | object.to_yaml.sub(/^---\s*/m, "") | ||
| 63 | end | ||
| 64 | |||
| 65 | def exclude_raw_post_parameters? | ||
| 66 | @controller && @controller.respond_to?(:filter_parameters) | ||
| 67 | end | ||
| 68 | |||
| 69 | def filter_sensitive_post_data_parameters(parameters) | ||
| 70 | exclude_raw_post_parameters? ? @controller.__send__(:filter_parameters, parameters) : parameters | ||
| 71 | end | ||
| 72 | |||
| 73 | def filter_sensitive_post_data_from_env(env_key, env_value) | ||
| 74 | return env_value unless exclude_raw_post_parameters? | ||
| 75 | return PARAM_FILTER_REPLACEMENT if (env_key =~ /RAW_POST_DATA/i) | ||
| 76 | return @controller.__send__(:filter_parameters, {env_key => env_value}).values[0] | ||
| 77 | end | ||
| 78 | end | ||
diff --git a/vendor/plugins/exception_notification/test/exception_notifier_helper_test.rb b/vendor/plugins/exception_notification/test/exception_notifier_helper_test.rb deleted file mode 100644 index dd47637..0000000 --- a/vendor/plugins/exception_notification/test/exception_notifier_helper_test.rb +++ /dev/null | |||
| @@ -1,61 +0,0 @@ | |||
| 1 | require 'test_helper' | ||
| 2 | require 'exception_notifier_helper' | ||
| 3 | |||
| 4 | class ExceptionNotifierHelperTest < Test::Unit::TestCase | ||
| 5 | |||
| 6 | class ExceptionNotifierHelperIncludeTarget | ||
| 7 | include ExceptionNotifierHelper | ||
| 8 | end | ||
| 9 | |||
| 10 | def setup | ||
| 11 | @helper = ExceptionNotifierHelperIncludeTarget.new | ||
| 12 | end | ||
| 13 | |||
| 14 | # No controller | ||
| 15 | |||
| 16 | def test_should_not_exclude_raw_post_parameters_if_no_controller | ||
| 17 | assert !@helper.exclude_raw_post_parameters? | ||
| 18 | end | ||
| 19 | |||
| 20 | # Controller, no filtering | ||
| 21 | |||
| 22 | class ControllerWithoutFilterParameters; end | ||
| 23 | |||
| 24 | def test_should_not_filter_env_values_for_raw_post_data_keys_if_controller_can_not_filter_parameters | ||
| 25 | stub_controller(ControllerWithoutFilterParameters.new) | ||
| 26 | assert @helper.filter_sensitive_post_data_from_env("RAW_POST_DATA", "secret").include?("secret") | ||
| 27 | end | ||
| 28 | def test_should_not_exclude_raw_post_parameters_if_controller_can_not_filter_parameters | ||
| 29 | stub_controller(ControllerWithoutFilterParameters.new) | ||
| 30 | assert !@helper.exclude_raw_post_parameters? | ||
| 31 | end | ||
| 32 | def test_should_return_params_if_controller_can_not_filter_parameters | ||
| 33 | stub_controller(ControllerWithoutFilterParameters.new) | ||
| 34 | assert_equal :params, @helper.filter_sensitive_post_data_parameters(:params) | ||
| 35 | end | ||
| 36 | |||
| 37 | # Controller with filtering | ||
| 38 | |||
| 39 | class ControllerWithFilterParameters | ||
| 40 | def filter_parameters(params); :filtered end | ||
| 41 | end | ||
| 42 | |||
| 43 | def test_should_filter_env_values_for_raw_post_data_keys_if_controller_can_filter_parameters | ||
| 44 | stub_controller(ControllerWithFilterParameters.new) | ||
| 45 | assert !@helper.filter_sensitive_post_data_from_env("RAW_POST_DATA", "secret").include?("secret") | ||
| 46 | assert @helper.filter_sensitive_post_data_from_env("SOME_OTHER_KEY", "secret").include?("secret") | ||
| 47 | end | ||
| 48 | def test_should_exclude_raw_post_parameters_if_controller_can_filter_parameters | ||
| 49 | stub_controller(ControllerWithFilterParameters.new) | ||
| 50 | assert @helper.exclude_raw_post_parameters? | ||
| 51 | end | ||
| 52 | def test_should_delegate_param_filtering_to_controller_if_controller_can_filter_parameters | ||
| 53 | stub_controller(ControllerWithFilterParameters.new) | ||
| 54 | assert_equal :filtered, @helper.filter_sensitive_post_data_parameters(:params) | ||
| 55 | end | ||
| 56 | |||
| 57 | private | ||
| 58 | def stub_controller(controller) | ||
| 59 | @helper.instance_variable_set(:@controller, controller) | ||
| 60 | end | ||
| 61 | end \ No newline at end of file | ||
diff --git a/vendor/plugins/exception_notification/test/test_helper.rb b/vendor/plugins/exception_notification/test/test_helper.rb deleted file mode 100644 index bbe6fc5..0000000 --- a/vendor/plugins/exception_notification/test/test_helper.rb +++ /dev/null | |||
| @@ -1,7 +0,0 @@ | |||
| 1 | require 'test/unit' | ||
| 2 | require 'rubygems' | ||
| 3 | require 'active_support' | ||
| 4 | |||
| 5 | $:.unshift File.join(File.dirname(__FILE__), '../lib') | ||
| 6 | |||
| 7 | RAILS_ROOT = '.' unless defined?(RAILS_ROOT) | ||
diff --git a/vendor/plugins/exception_notification/views/exception_notifier/_backtrace.rhtml b/vendor/plugins/exception_notification/views/exception_notifier/_backtrace.rhtml deleted file mode 100644 index 7d13ba0..0000000 --- a/vendor/plugins/exception_notification/views/exception_notifier/_backtrace.rhtml +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | <%= @backtrace.join "\n" %> | ||
diff --git a/vendor/plugins/exception_notification/views/exception_notifier/_environment.rhtml b/vendor/plugins/exception_notification/views/exception_notifier/_environment.rhtml deleted file mode 100644 index 42dd803..0000000 --- a/vendor/plugins/exception_notification/views/exception_notifier/_environment.rhtml +++ /dev/null | |||
| @@ -1,7 +0,0 @@ | |||
| 1 | <% max = @request.env.keys.max { |a,b| a.length <=> b.length } -%> | ||
| 2 | <% @request.env.keys.sort.each do |key| -%> | ||
| 3 | * <%= "%-*s: %s" % [max.length, key, filter_sensitive_post_data_from_env(key, @request.env[key].to_s.strip)] %> | ||
| 4 | <% end -%> | ||
| 5 | |||
| 6 | * Process: <%= $$ %> | ||
| 7 | * Server : <%= `hostname -s`.chomp %> | ||
diff --git a/vendor/plugins/exception_notification/views/exception_notifier/_inspect_model.rhtml b/vendor/plugins/exception_notification/views/exception_notifier/_inspect_model.rhtml deleted file mode 100644 index e817847..0000000 --- a/vendor/plugins/exception_notification/views/exception_notifier/_inspect_model.rhtml +++ /dev/null | |||
| @@ -1,16 +0,0 @@ | |||
| 1 | <% if show_attributes -%> | ||
| 2 | [attributes] | ||
| 3 | <% attrs = inspect_model.attributes -%> | ||
| 4 | <% max = attrs.keys.max { |a,b| a.length <=> b.length } -%> | ||
| 5 | <% attrs.keys.sort.each do |attr| -%> | ||
| 6 | * <%= "%*-s: %s" % [max.length, attr, object_to_yaml(attrs[attr]).gsub(/\n/, "\n ").strip] %> | ||
| 7 | <% end -%> | ||
| 8 | <% end -%> | ||
| 9 | |||
| 10 | <% if show_instance_variables -%> | ||
| 11 | [instance variables] | ||
| 12 | <% inspect_model.instance_variables.sort.each do |variable| -%> | ||
| 13 | <%- next if variable == "@attributes" -%> | ||
| 14 | * <%= variable %>: <%= inspect_value(inspect_model.instance_variable_get(variable)) %> | ||
| 15 | <% end -%> | ||
| 16 | <% end -%> | ||
diff --git a/vendor/plugins/exception_notification/views/exception_notifier/_request.rhtml b/vendor/plugins/exception_notification/views/exception_notifier/_request.rhtml deleted file mode 100644 index 2542309..0000000 --- a/vendor/plugins/exception_notification/views/exception_notifier/_request.rhtml +++ /dev/null | |||
| @@ -1,4 +0,0 @@ | |||
| 1 | * URL : <%= @request.protocol %><%= @host %><%= @request.request_uri %> | ||
| 2 | * IP address: <%= @request.env["HTTP_X_FORWARDED_FOR"] || @request.env["REMOTE_ADDR"] %> | ||
| 3 | * Parameters: <%= filter_sensitive_post_data_parameters(@request.parameters).inspect %> | ||
| 4 | * Rails root: <%= @rails_root %> | ||
diff --git a/vendor/plugins/exception_notification/views/exception_notifier/_session.rhtml b/vendor/plugins/exception_notification/views/exception_notifier/_session.rhtml deleted file mode 100644 index 283c862..0000000 --- a/vendor/plugins/exception_notification/views/exception_notifier/_session.rhtml +++ /dev/null | |||
| @@ -1,2 +0,0 @@ | |||
| 1 | * session id: <%= @request.session.instance_variable_get(:@session_id).inspect %> | ||
| 2 | * data: <%= PP.pp(@request.session.instance_variable_get(:@data),"").gsub(/\n/, "\n ").strip %> | ||
diff --git a/vendor/plugins/exception_notification/views/exception_notifier/_title.rhtml b/vendor/plugins/exception_notification/views/exception_notifier/_title.rhtml deleted file mode 100644 index 1ed5a3f..0000000 --- a/vendor/plugins/exception_notification/views/exception_notifier/_title.rhtml +++ /dev/null | |||
| @@ -1,3 +0,0 @@ | |||
| 1 | ------------------------------- | ||
| 2 | <%= title.to_s.humanize %>: | ||
| 3 | ------------------------------- | ||
diff --git a/vendor/plugins/exception_notification/views/exception_notifier/exception_notification.rhtml b/vendor/plugins/exception_notification/views/exception_notifier/exception_notification.rhtml deleted file mode 100644 index ec30c4a..0000000 --- a/vendor/plugins/exception_notification/views/exception_notifier/exception_notification.rhtml +++ /dev/null | |||
| @@ -1,6 +0,0 @@ | |||
| 1 | A <%= @exception.class %> occurred in <%= @controller.controller_name %>#<%= @controller.action_name %>: | ||
| 2 | |||
| 3 | <%= @exception.message %> | ||
| 4 | <%= @backtrace.first %> | ||
| 5 | |||
| 6 | <%= @sections.map { |section| render_section(section) }.join %> | ||
diff --git a/vendor/plugins/globalize2/LICENSE b/vendor/plugins/globalize2/LICENSE deleted file mode 100644 index 94a6b81..0000000 --- a/vendor/plugins/globalize2/LICENSE +++ /dev/null | |||
| @@ -1,21 +0,0 @@ | |||
| 1 | The MIT License | ||
| 2 | |||
| 3 | Copyright (c) 2008, 2009 Joshua Harvey | ||
| 4 | |||
| 5 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 6 | of this software and associated documentation files (the "Software"), to deal | ||
| 7 | in the Software without restriction, including without limitation the rights | ||
| 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 9 | copies of the Software, and to permit persons to whom the Software is | ||
| 10 | furnished to do so, subject to the following conditions: | ||
| 11 | |||
| 12 | The above copyright notice and this permission notice shall be included in | ||
| 13 | all copies or substantial portions of the Software. | ||
| 14 | |||
| 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 21 | THE SOFTWARE. \ No newline at end of file | ||
diff --git a/vendor/plugins/globalize2/README.textile b/vendor/plugins/globalize2/README.textile deleted file mode 100644 index 7155a7c..0000000 --- a/vendor/plugins/globalize2/README.textile +++ /dev/null | |||
| @@ -1,65 +0,0 @@ | |||
| 1 | h1. Globalize2 | ||
| 2 | |||
| 3 | Globalize2 is the successor of Globalize for Rails. | ||
| 4 | |||
| 5 | It is compatible with and builds on the new "I18n api in Ruby on Rails":http://guides.rubyonrails.org/i18n.html. and adds model translations to ActiveRecord. | ||
| 6 | |||
| 7 | Globalize2 is much more lightweight and compatible than its predecessor was. Model translations in Globalize2 use default ActiveRecord features and do not limit any ActiveRecord functionality any more. | ||
| 8 | |||
| 9 | h2. Requirements | ||
| 10 | |||
| 11 | ActiveRecord | ||
| 12 | I18n | ||
| 13 | |||
| 14 | (or Rails > 2.2) | ||
| 15 | |||
| 16 | h2. Installation | ||
| 17 | |||
| 18 | To install Globalize2 with its default setup just use: | ||
| 19 | |||
| 20 | <pre><code> | ||
| 21 | script/plugin install git://github.com/joshmh/globalize2.git | ||
| 22 | </code></pre> | ||
| 23 | |||
| 24 | h2. Model translations | ||
| 25 | |||
| 26 | Model translations allow you to translate your models' attribute values. E.g. | ||
| 27 | |||
| 28 | <pre><code> | ||
| 29 | class Post < ActiveRecord::Base | ||
| 30 | translates :title, :text | ||
| 31 | end | ||
| 32 | </code></pre> | ||
| 33 | |||
| 34 | Allows you to values for the attributes :title and :text per locale: | ||
| 35 | |||
| 36 | <pre><code> | ||
| 37 | I18n.locale = :en | ||
| 38 | post.title # => Globalize2 rocks! | ||
| 39 | |||
| 40 | I18n.locale = :he | ||
| 41 | post.title # => גלובאלייז2 שולט! | ||
| 42 | </code></pre> | ||
| 43 | |||
| 44 | In order to make this work, you'll need to add the appropriate translation tables. Globalize2 comes with a handy helper method to help you do this. It's called @create_translation_table!@. Here's an example: | ||
| 45 | |||
| 46 | <pre><code> | ||
| 47 | class CreatePosts < ActiveRecord::Migration | ||
| 48 | def self.up | ||
| 49 | create_table :posts do |t| | ||
| 50 | t.timestamps | ||
| 51 | end | ||
| 52 | Post.create_translation_table! :title => :string, :text => :text | ||
| 53 | end | ||
| 54 | def self.down | ||
| 55 | drop_table :posts | ||
| 56 | Post.drop_translation_table! | ||
| 57 | end | ||
| 58 | end | ||
| 59 | </code></pre> | ||
| 60 | |||
| 61 | Note that the ActiveRecord model @Post@ must already exist and have a @translates@ directive listing the translated fields. | ||
| 62 | |||
| 63 | h2. Migration from Globalize | ||
| 64 | |||
| 65 | See this script by Tomasz Stachewicz: http://gist.github.com/120867 | ||
diff --git a/vendor/plugins/globalize2/Rakefile b/vendor/plugins/globalize2/Rakefile deleted file mode 100644 index ee80713..0000000 --- a/vendor/plugins/globalize2/Rakefile +++ /dev/null | |||
| @@ -1,39 +0,0 @@ | |||
| 1 | require 'rake' | ||
| 2 | require 'rake/testtask' | ||
| 3 | require 'rake/rdoctask' | ||
| 4 | |||
| 5 | desc 'Default: run unit tests.' | ||
| 6 | task :default => :test | ||
| 7 | |||
| 8 | desc 'Test the globalize2 plugin.' | ||
| 9 | Rake::TestTask.new(:test) do |t| | ||
| 10 | t.libs << 'lib' | ||
| 11 | t.pattern = 'test/**/*_test.rb' | ||
| 12 | t.verbose = true | ||
| 13 | end | ||
| 14 | |||
| 15 | desc 'Generate documentation for the globalize2 plugin.' | ||
| 16 | Rake::RDocTask.new(:rdoc) do |rdoc| | ||
| 17 | rdoc.rdoc_dir = 'rdoc' | ||
| 18 | rdoc.title = 'Globalize2' | ||
| 19 | rdoc.options << '--line-numbers' << '--inline-source' | ||
| 20 | rdoc.rdoc_files.include('README') | ||
| 21 | rdoc.rdoc_files.include('lib/**/*.rb') | ||
| 22 | end | ||
| 23 | |||
| 24 | begin | ||
| 25 | require 'jeweler' | ||
| 26 | Jeweler::Tasks.new do |s| | ||
| 27 | s.name = "globalize2" | ||
| 28 | s.summary = "Rails I18n: de-facto standard library for ActiveRecord data translation" | ||
| 29 | s.description = "Rails I18n: de-facto standard library for ActiveRecord data translation" | ||
| 30 | s.email = "joshmh@gmail.com" | ||
| 31 | s.homepage = "http://github.com/joshmh/globalize2" | ||
| 32 | # s.rubyforge_project = '' | ||
| 33 | s.authors = ["Sven Fuchs, Joshua Harvey, Clemens Kofler"] | ||
| 34 | # s.add_development_dependency '' | ||
| 35 | end | ||
| 36 | Jeweler::GemcutterTasks.new | ||
| 37 | rescue LoadError | ||
| 38 | puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com" | ||
| 39 | end | ||
diff --git a/vendor/plugins/globalize2/VERSION b/vendor/plugins/globalize2/VERSION deleted file mode 100644 index 0ea3a94..0000000 --- a/vendor/plugins/globalize2/VERSION +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | 0.2.0 | ||
diff --git a/vendor/plugins/globalize2/generators/db_backend.rb b/vendor/plugins/globalize2/generators/db_backend.rb deleted file mode 100644 index e69de29..0000000 --- a/vendor/plugins/globalize2/generators/db_backend.rb +++ /dev/null | |||
diff --git a/vendor/plugins/globalize2/generators/templates/db_backend_migration.rb b/vendor/plugins/globalize2/generators/templates/db_backend_migration.rb deleted file mode 100644 index 0f02611..0000000 --- a/vendor/plugins/globalize2/generators/templates/db_backend_migration.rb +++ /dev/null | |||
| @@ -1,25 +0,0 @@ | |||
| 1 | class ActsAsTaggableMigration < ActiveRecord::Migration | ||
| 2 | def self.up | ||
| 3 | create_table :globalize_translations do |t| | ||
| 4 | t.string :locale, :null => false | ||
| 5 | t.string :key, :null => false | ||
| 6 | t.string :translation | ||
| 7 | t.timestamps | ||
| 8 | end | ||
| 9 | |||
| 10 | # TODO: FINISH DOING MIGRATION -- stopped in the middle | ||
| 11 | |||
| 12 | create_table :globalize_translations_map do |t| | ||
| 13 | t.string :key, :null => false | ||
| 14 | t.integer :translation_id, :null => false | ||
| 15 | end | ||
| 16 | |||
| 17 | add_index :taggings, :tag_id | ||
| 18 | add_index :taggings, [:taggable_id, :taggable_type] | ||
| 19 | end | ||
| 20 | |||
| 21 | def self.down | ||
| 22 | drop_table :globalize_translations | ||
| 23 | drop_table :tags | ||
| 24 | end | ||
| 25 | end | ||
diff --git a/vendor/plugins/globalize2/globalize2.gemspec b/vendor/plugins/globalize2/globalize2.gemspec deleted file mode 100644 index 6ad93d3..0000000 --- a/vendor/plugins/globalize2/globalize2.gemspec +++ /dev/null | |||
| @@ -1,82 +0,0 @@ | |||
| 1 | # Generated by jeweler | ||
| 2 | # DO NOT EDIT THIS FILE DIRECTLY | ||
| 3 | # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command | ||
| 4 | # -*- encoding: utf-8 -*- | ||
| 5 | |||
| 6 | Gem::Specification.new do |s| | ||
| 7 | s.name = %q{globalize2} | ||
| 8 | s.version = "0.2.0" | ||
| 9 | |||
| 10 | s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= | ||
| 11 | s.authors = ["Sven Fuchs, Joshua Harvey, Clemens Kofler"] | ||
| 12 | s.date = %q{2009-12-25} | ||
| 13 | s.description = %q{Rails I18n: de-facto standard library for ActiveRecord data translation} | ||
| 14 | s.email = %q{joshmh@gmail.com} | ||
| 15 | s.extra_rdoc_files = [ | ||
| 16 | "LICENSE", | ||
| 17 | "README.textile" | ||
| 18 | ] | ||
| 19 | s.files = [ | ||
| 20 | ".gitignore", | ||
| 21 | "LICENSE", | ||
| 22 | "README.textile", | ||
| 23 | "Rakefile", | ||
| 24 | "VERSION", | ||
| 25 | "generators/db_backend.rb", | ||
| 26 | "generators/templates/db_backend_migration.rb", | ||
| 27 | "globalize2.gemspec", | ||
| 28 | "init.rb", | ||
| 29 | "lib/globalize.rb", | ||
| 30 | "lib/globalize/active_record.rb", | ||
| 31 | "lib/globalize/active_record/adapter.rb", | ||
| 32 | "lib/globalize/active_record/attributes.rb", | ||
| 33 | "lib/globalize/active_record/migration.rb", | ||
| 34 | "lib/i18n/missing_translations_log_handler.rb", | ||
| 35 | "lib/i18n/missing_translations_raise_handler.rb", | ||
| 36 | "notes.textile", | ||
| 37 | "test/active_record/fallbacks_test.rb", | ||
| 38 | "test/active_record/migration_test.rb", | ||
| 39 | "test/active_record/sti_translated_test.rb", | ||
| 40 | "test/active_record/translates_test.rb", | ||
| 41 | "test/active_record/translation_class_test.rb", | ||
| 42 | "test/active_record/validation_tests.rb", | ||
| 43 | "test/active_record_test.rb", | ||
| 44 | "test/all.rb", | ||
| 45 | "test/data/models.rb", | ||
| 46 | "test/data/no_globalize_schema.rb", | ||
| 47 | "test/data/schema.rb", | ||
| 48 | "test/i18n/missing_translations_test.rb", | ||
| 49 | "test/test_helper.rb" | ||
| 50 | ] | ||
| 51 | s.homepage = %q{http://github.com/joshmh/globalize2} | ||
| 52 | s.rdoc_options = ["--charset=UTF-8"] | ||
| 53 | s.require_paths = ["lib"] | ||
| 54 | s.rubygems_version = %q{1.3.5} | ||
| 55 | s.summary = %q{Rails I18n: de-facto standard library for ActiveRecord data translation} | ||
| 56 | s.test_files = [ | ||
| 57 | "test/active_record/fallbacks_test.rb", | ||
| 58 | "test/active_record/migration_test.rb", | ||
| 59 | "test/active_record/sti_translated_test.rb", | ||
| 60 | "test/active_record/translates_test.rb", | ||
| 61 | "test/active_record/translation_class_test.rb", | ||
| 62 | "test/active_record/validation_tests.rb", | ||
| 63 | "test/active_record_test.rb", | ||
| 64 | "test/all.rb", | ||
| 65 | "test/data/models.rb", | ||
| 66 | "test/data/no_globalize_schema.rb", | ||
| 67 | "test/data/schema.rb", | ||
| 68 | "test/i18n/missing_translations_test.rb", | ||
| 69 | "test/test_helper.rb" | ||
| 70 | ] | ||
| 71 | |||
| 72 | if s.respond_to? :specification_version then | ||
| 73 | current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION | ||
| 74 | s.specification_version = 3 | ||
| 75 | |||
| 76 | if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then | ||
| 77 | else | ||
| 78 | end | ||
| 79 | else | ||
| 80 | end | ||
| 81 | end | ||
| 82 | |||
diff --git a/vendor/plugins/globalize2/init.rb b/vendor/plugins/globalize2/init.rb deleted file mode 100644 index a408925..0000000 --- a/vendor/plugins/globalize2/init.rb +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | require 'globalize' | ||
diff --git a/vendor/plugins/globalize2/lib/globalize.rb b/vendor/plugins/globalize2/lib/globalize.rb deleted file mode 100644 index 67c1878..0000000 --- a/vendor/plugins/globalize2/lib/globalize.rb +++ /dev/null | |||
| @@ -1,15 +0,0 @@ | |||
| 1 | module Globalize | ||
| 2 | autoload :ActiveRecord, 'globalize/active_record' | ||
| 3 | |||
| 4 | class << self | ||
| 5 | def fallbacks? | ||
| 6 | I18n.respond_to?(:fallbacks) | ||
| 7 | end | ||
| 8 | |||
| 9 | def fallbacks(locale) | ||
| 10 | fallbacks? ? I18n.fallbacks[locale] : [locale.to_sym] | ||
| 11 | end | ||
| 12 | end | ||
| 13 | end | ||
| 14 | |||
| 15 | ActiveRecord::Base.send(:include, Globalize::ActiveRecord) | ||
diff --git a/vendor/plugins/globalize2/lib/globalize/active_record.rb b/vendor/plugins/globalize2/lib/globalize/active_record.rb deleted file mode 100644 index d2a843f..0000000 --- a/vendor/plugins/globalize2/lib/globalize/active_record.rb +++ /dev/null | |||
| @@ -1,194 +0,0 @@ | |||
| 1 | module Globalize | ||
| 2 | class MigrationError < StandardError; end | ||
| 3 | class MigrationMissingTranslatedField < MigrationError; end | ||
| 4 | class BadMigrationFieldType < MigrationError; end | ||
| 5 | |||
| 6 | module ActiveRecord | ||
| 7 | autoload :Adapter, 'globalize/active_record/adapter' | ||
| 8 | autoload :Attributes, 'globalize/active_record/attributes' | ||
| 9 | autoload :Migration, 'globalize/active_record/migration' | ||
| 10 | |||
| 11 | def self.included(base) | ||
| 12 | base.extend ActMacro | ||
| 13 | end | ||
| 14 | |||
| 15 | class << self | ||
| 16 | def build_translation_class(target, options) | ||
| 17 | options[:table_name] ||= "#{target.table_name.singularize}_translations" | ||
| 18 | |||
| 19 | klass = target.const_defined?(:Translation) ? | ||
| 20 | target.const_get(:Translation) : | ||
| 21 | target.const_set(:Translation, Class.new(::ActiveRecord::Base)) | ||
| 22 | |||
| 23 | klass.class_eval do | ||
| 24 | set_table_name(options[:table_name]) | ||
| 25 | belongs_to target.name.underscore.gsub('/', '_') | ||
| 26 | def locale; read_attribute(:locale).to_sym; end | ||
| 27 | def locale=(locale); write_attribute(:locale, locale.to_s); end | ||
| 28 | end | ||
| 29 | |||
| 30 | klass | ||
| 31 | end | ||
| 32 | end | ||
| 33 | |||
| 34 | module ActMacro | ||
| 35 | def locale | ||
| 36 | (defined?(@@locale) && @@locale) | ||
| 37 | end | ||
| 38 | |||
| 39 | def locale=(locale) | ||
| 40 | @@locale = locale | ||
| 41 | end | ||
| 42 | |||
| 43 | def translates(*attr_names) | ||
| 44 | return if translates? | ||
| 45 | options = attr_names.extract_options! | ||
| 46 | |||
| 47 | class_inheritable_accessor :translation_class, :translated_attribute_names | ||
| 48 | self.translation_class = ActiveRecord.build_translation_class(self, options) | ||
| 49 | self.translated_attribute_names = attr_names.map(&:to_sym) | ||
| 50 | |||
| 51 | include InstanceMethods | ||
| 52 | extend ClassMethods, Migration | ||
| 53 | |||
| 54 | after_save :save_translations! | ||
| 55 | has_many :translations, :class_name => translation_class.name, | ||
| 56 | :foreign_key => class_name.foreign_key, | ||
| 57 | :dependent => :delete_all, | ||
| 58 | :extend => HasManyExtensions | ||
| 59 | |||
| 60 | named_scope :with_translations, lambda { |locale| | ||
| 61 | conditions = required_attributes.map do |attribute| | ||
| 62 | "#{quoted_translation_table_name}.#{attribute} IS NOT NULL" | ||
| 63 | end | ||
| 64 | conditions << "#{quoted_translation_table_name}.locale = ?" | ||
| 65 | { :include => :translations, :conditions => [conditions.join(' AND '), locale] } | ||
| 66 | } | ||
| 67 | |||
| 68 | attr_names.each { |attr_name| translated_attr_accessor(attr_name) } | ||
| 69 | end | ||
| 70 | |||
| 71 | def translates? | ||
| 72 | included_modules.include?(InstanceMethods) | ||
| 73 | end | ||
| 74 | end | ||
| 75 | |||
| 76 | module HasManyExtensions | ||
| 77 | def by_locale(locale) | ||
| 78 | first(:conditions => { :locale => locale.to_s }) | ||
| 79 | end | ||
| 80 | |||
| 81 | def by_locales(locales) | ||
| 82 | all(:conditions => { :locale => locales.map(&:to_s) }) | ||
| 83 | end | ||
| 84 | end | ||
| 85 | |||
| 86 | module ClassMethods | ||
| 87 | delegate :set_translation_table_name, :to => :translation_class | ||
| 88 | |||
| 89 | def with_locale(locale) | ||
| 90 | previous_locale, self.locale = self.locale, locale | ||
| 91 | result = yield | ||
| 92 | self.locale = previous_locale | ||
| 93 | result | ||
| 94 | end | ||
| 95 | |||
| 96 | def translation_table_name | ||
| 97 | translation_class.table_name | ||
| 98 | end | ||
| 99 | |||
| 100 | def quoted_translation_table_name | ||
| 101 | translation_class.quoted_table_name | ||
| 102 | end | ||
| 103 | |||
| 104 | def required_attributes | ||
| 105 | validations = reflect_on_all_validations.select do |validation| | ||
| 106 | validation.macro == :validates_presence_of | ||
| 107 | end.map(&:name) | ||
| 108 | end | ||
| 109 | |||
| 110 | def respond_to?(method, *args, &block) | ||
| 111 | method.to_s =~ /^find_by_(\w+)$/ && translated_attribute_names.include?($1.to_sym) || super | ||
| 112 | end | ||
| 113 | |||
| 114 | def method_missing(method, *args) | ||
| 115 | if method.to_s =~ /^find_by_(\w+)$/ && translated_attribute_names.include?($1.to_sym) | ||
| 116 | find_first_by_translated_attr_and_locales($1, args.first) | ||
| 117 | else | ||
| 118 | super | ||
| 119 | end | ||
| 120 | end | ||
| 121 | |||
| 122 | protected | ||
| 123 | |||
| 124 | def find_first_by_translated_attr_and_locales(name, value) | ||
| 125 | query = "#{translated_attr_name(name)} = ? AND #{translated_attr_name('locale')} IN (?)" | ||
| 126 | locales = Globalize.fallbacks(locale || I18n.locale).map(&:to_s) | ||
| 127 | find(:first, :joins => :translations, :conditions => [query, value, locales]) | ||
| 128 | end | ||
| 129 | |||
| 130 | def translated_attr_accessor(name) | ||
| 131 | define_method "#{name}=", lambda { |value| | ||
| 132 | globalize.write(self.class.locale || I18n.locale, name, value) | ||
| 133 | self[name] = value | ||
| 134 | } | ||
| 135 | define_method name, lambda { |*args| | ||
| 136 | globalize.fetch(args.first || self.class.locale || I18n.locale, name) | ||
| 137 | } | ||
| 138 | alias_method "#{name}_before_type_cast", name | ||
| 139 | end | ||
| 140 | |||
| 141 | def translated_attr_name(name) | ||
| 142 | "#{translation_class.table_name}.#{name}" | ||
| 143 | end | ||
| 144 | end | ||
| 145 | |||
| 146 | module InstanceMethods | ||
| 147 | def globalize | ||
| 148 | @globalize ||= Adapter.new self | ||
| 149 | end | ||
| 150 | |||
| 151 | def attributes=(attributes, *args) | ||
| 152 | if attributes.respond_to?(:delete) && locale = attributes.delete(:locale) | ||
| 153 | self.class.with_locale(locale) { super } | ||
| 154 | else | ||
| 155 | super | ||
| 156 | end | ||
| 157 | end | ||
| 158 | |||
| 159 | def available_locales | ||
| 160 | translations.scoped(:select => 'DISTINCT locale').map(&:locale) | ||
| 161 | end | ||
| 162 | |||
| 163 | def translated_locales | ||
| 164 | translations.map(&:locale) | ||
| 165 | end | ||
| 166 | |||
| 167 | def translated_attributes | ||
| 168 | translated_attribute_names.inject({}) do |attributes, name| | ||
| 169 | attributes.merge(name => send(name)) | ||
| 170 | end | ||
| 171 | end | ||
| 172 | |||
| 173 | def set_translations(options) | ||
| 174 | options.keys.each do |locale| | ||
| 175 | translation = translations.find_by_locale(locale.to_s) || | ||
| 176 | translations.build(:locale => locale.to_s) | ||
| 177 | translation.update_attributes!(options[locale]) | ||
| 178 | end | ||
| 179 | end | ||
| 180 | |||
| 181 | def reload(options = nil) | ||
| 182 | translated_attribute_names.each { |name| @attributes.delete(name.to_s) } | ||
| 183 | globalize.reset | ||
| 184 | super(options) | ||
| 185 | end | ||
| 186 | |||
| 187 | protected | ||
| 188 | |||
| 189 | def save_translations! | ||
| 190 | globalize.save_translations! | ||
| 191 | end | ||
| 192 | end | ||
| 193 | end | ||
| 194 | end | ||
diff --git a/vendor/plugins/globalize2/lib/globalize/active_record/adapter.rb b/vendor/plugins/globalize2/lib/globalize/active_record/adapter.rb deleted file mode 100644 index 12f89ec..0000000 --- a/vendor/plugins/globalize2/lib/globalize/active_record/adapter.rb +++ /dev/null | |||
| @@ -1,80 +0,0 @@ | |||
| 1 | module Globalize | ||
| 2 | module ActiveRecord | ||
| 3 | class Adapter | ||
| 4 | # The cache caches attributes that already were looked up for read access. | ||
| 5 | # The stash keeps track of new or changed values that need to be saved. | ||
| 6 | attr_reader :record, :cache, :stash | ||
| 7 | |||
| 8 | def initialize(record) | ||
| 9 | @record = record | ||
| 10 | @cache = Attributes.new | ||
| 11 | @stash = Attributes.new | ||
| 12 | end | ||
| 13 | |||
| 14 | def fetch(locale, attr_name) | ||
| 15 | cache.contains?(locale, attr_name) ? | ||
| 16 | cache.read(locale, attr_name) : | ||
| 17 | cache.write(locale, attr_name, fetch_attribute(locale, attr_name)) | ||
| 18 | end | ||
| 19 | |||
| 20 | def write(locale, attr_name, value) | ||
| 21 | stash.write(locale, attr_name, value) | ||
| 22 | cache.write(locale, attr_name, value) | ||
| 23 | end | ||
| 24 | |||
| 25 | def save_translations! | ||
| 26 | stash.each do |locale, attrs| | ||
| 27 | translation = record.translations.find_or_initialize_by_locale(locale.to_s) | ||
| 28 | attrs.each { |attr_name, value| translation[attr_name] = value } | ||
| 29 | translation.save! | ||
| 30 | end | ||
| 31 | stash.clear | ||
| 32 | end | ||
| 33 | |||
| 34 | def reset | ||
| 35 | cache.clear | ||
| 36 | # stash.clear | ||
| 37 | end | ||
| 38 | |||
| 39 | protected | ||
| 40 | |||
| 41 | def fetch_translation(locale) | ||
| 42 | locale = locale.to_sym | ||
| 43 | record.translations.loaded? ? record.translations.detect { |t| t.locale == locale } : | ||
| 44 | record.translations.by_locale(locale) | ||
| 45 | end | ||
| 46 | |||
| 47 | def fetch_translations(locale) | ||
| 48 | # only query if not already included with :include => translations | ||
| 49 | record.translations.loaded? ? record.translations : | ||
| 50 | record.translations.by_locales(Globalize.fallbacks(locale)) | ||
| 51 | end | ||
| 52 | |||
| 53 | def fetch_attribute(locale, attr_name) | ||
| 54 | translations = fetch_translations(locale) | ||
| 55 | value, requested_locale = nil, locale | ||
| 56 | |||
| 57 | Globalize.fallbacks(locale).each do |fallback| | ||
| 58 | translation = translations.detect { |t| t.locale == fallback } | ||
| 59 | value = translation && translation.send(attr_name) | ||
| 60 | locale = fallback && break if value | ||
| 61 | end | ||
| 62 | |||
| 63 | set_metadata(value, :locale => locale, :requested_locale => requested_locale) | ||
| 64 | value | ||
| 65 | end | ||
| 66 | |||
| 67 | def set_metadata(object, metadata) | ||
| 68 | if object.respond_to?(:translation_metadata) | ||
| 69 | object.translation_metadata.merge!(meta_data) | ||
| 70 | end | ||
| 71 | end | ||
| 72 | |||
| 73 | def translation_metadata_accessor(object) | ||
| 74 | return if obj.respond_to?(:translation_metadata) | ||
| 75 | class << object; attr_accessor :translation_metadata end | ||
| 76 | object.translation_metadata ||= {} | ||
| 77 | end | ||
| 78 | end | ||
| 79 | end | ||
| 80 | end | ||
diff --git a/vendor/plugins/globalize2/lib/globalize/active_record/attributes.rb b/vendor/plugins/globalize2/lib/globalize/active_record/attributes.rb deleted file mode 100644 index 7bd923c..0000000 --- a/vendor/plugins/globalize2/lib/globalize/active_record/attributes.rb +++ /dev/null | |||
| @@ -1,25 +0,0 @@ | |||
| 1 | # Helper class for storing values per locale. Used by Globalize::Adapter | ||
| 2 | # to stash and cache attribute values. | ||
| 3 | module Globalize | ||
| 4 | module ActiveRecord | ||
| 5 | class Attributes < Hash | ||
| 6 | def [](locale) | ||
| 7 | locale = locale.to_sym | ||
| 8 | self[locale] = {} unless has_key?(locale) | ||
| 9 | self.fetch(locale) | ||
| 10 | end | ||
| 11 | |||
| 12 | def contains?(locale, attr_name) | ||
| 13 | self[locale].has_key?(attr_name) | ||
| 14 | end | ||
| 15 | |||
| 16 | def read(locale, attr_name) | ||
| 17 | self[locale][attr_name] | ||
| 18 | end | ||
| 19 | |||
| 20 | def write(locale, attr_name, value) | ||
| 21 | self[locale][attr_name] = value | ||
| 22 | end | ||
| 23 | end | ||
| 24 | end | ||
| 25 | end | ||
diff --git a/vendor/plugins/globalize2/lib/globalize/active_record/migration.rb b/vendor/plugins/globalize2/lib/globalize/active_record/migration.rb deleted file mode 100644 index ebff3b6..0000000 --- a/vendor/plugins/globalize2/lib/globalize/active_record/migration.rb +++ /dev/null | |||
| @@ -1,40 +0,0 @@ | |||
| 1 | module Globalize | ||
| 2 | module ActiveRecord | ||
| 3 | module Migration | ||
| 4 | def create_translation_table!(fields) | ||
| 5 | translated_attribute_names.each do |f| | ||
| 6 | raise MigrationMissingTranslatedField, "Missing translated field #{f}" unless fields[f] | ||
| 7 | end | ||
| 8 | |||
| 9 | fields.each do |name, type| | ||
| 10 | if translated_attribute_names.include?(name) && ![:string, :text].include?(type) | ||
| 11 | raise BadMigrationFieldType, "Bad field type for #{name}, should be :string or :text" | ||
| 12 | end | ||
| 13 | end | ||
| 14 | |||
| 15 | self.connection.create_table(translation_table_name) do |t| | ||
| 16 | t.references self.table_name.singularize | ||
| 17 | t.string :locale | ||
| 18 | fields.each do |name, type| | ||
| 19 | t.column name, type | ||
| 20 | end | ||
| 21 | t.timestamps | ||
| 22 | end | ||
| 23 | |||
| 24 | self.connection.add_index(translation_table_name, "#{self.table_name.singularize}_id", :name => translation_index_name) | ||
| 25 | end | ||
| 26 | |||
| 27 | def translation_index_name | ||
| 28 | require 'digest/sha1' | ||
| 29 | # FIXME what's the max size of an index name? | ||
| 30 | index_name = "index_#{translation_table_name}_on_#{self.table_name.singularize}_id" | ||
| 31 | index_name.size < 50 ? index_name : "index_#{Digest::SHA1.hexdigest(index_name)}" | ||
| 32 | end | ||
| 33 | |||
| 34 | def drop_translation_table! | ||
| 35 | self.connection.remove_index(translation_table_name, :name => translation_index_name) rescue nil | ||
| 36 | self.connection.drop_table(translation_table_name) | ||
| 37 | end | ||
| 38 | end | ||
| 39 | end | ||
| 40 | end | ||
diff --git a/vendor/plugins/globalize2/lib/i18n/missing_translations_log_handler.rb b/vendor/plugins/globalize2/lib/i18n/missing_translations_log_handler.rb deleted file mode 100644 index 24c1089..0000000 --- a/vendor/plugins/globalize2/lib/i18n/missing_translations_log_handler.rb +++ /dev/null | |||
| @@ -1,41 +0,0 @@ | |||
| 1 | # A simple exception handler that behaves like the default exception handler | ||
| 2 | # but additionally logs missing translations to a given log. | ||
| 3 | # | ||
| 4 | # Useful for identifying missing translations during testing. | ||
| 5 | # | ||
| 6 | # E.g. | ||
| 7 | # | ||
| 8 | # require 'globalize/i18n/missing_translations_log_handler' | ||
| 9 | # I18n.missing_translations_logger = RAILS_DEFAULT_LOGGER | ||
| 10 | # I18n.exception_handler = :missing_translations_log_handler | ||
| 11 | # | ||
| 12 | # To set up a different log file: | ||
| 13 | # | ||
| 14 | # logger = Logger.new("#{RAILS_ROOT}/log/missing_translations.log") | ||
| 15 | # I18n.missing_translations_logger = logger | ||
| 16 | |||
| 17 | module I18n | ||
| 18 | @@missing_translations_logger = nil | ||
| 19 | |||
| 20 | class << self | ||
| 21 | def missing_translations_logger | ||
| 22 | @@missing_translations_logger ||= begin | ||
| 23 | require 'logger' unless defined?(Logger) | ||
| 24 | Logger.new(STDOUT) | ||
| 25 | end | ||
| 26 | end | ||
| 27 | |||
| 28 | def missing_translations_logger=(logger) | ||
| 29 | @@missing_translations_logger = logger | ||
| 30 | end | ||
| 31 | |||
| 32 | def missing_translations_log_handler(exception, locale, key, options) | ||
| 33 | if MissingTranslationData === exception | ||
| 34 | missing_translations_logger.warn(exception.message) | ||
| 35 | return exception.message | ||
| 36 | else | ||
| 37 | raise exception | ||
| 38 | end | ||
| 39 | end | ||
| 40 | end | ||
| 41 | end | ||
diff --git a/vendor/plugins/globalize2/lib/i18n/missing_translations_raise_handler.rb b/vendor/plugins/globalize2/lib/i18n/missing_translations_raise_handler.rb deleted file mode 100644 index 18237b1..0000000 --- a/vendor/plugins/globalize2/lib/i18n/missing_translations_raise_handler.rb +++ /dev/null | |||
| @@ -1,25 +0,0 @@ | |||
| 1 | # A simple exception handler that behaves like the default exception handler | ||
| 2 | # but also raises on missing translations. | ||
| 3 | # | ||
| 4 | # Useful for identifying missing translations during testing. | ||
| 5 | # | ||
| 6 | # E.g. | ||
| 7 | # | ||
| 8 | # require 'globalize/i18n/missing_translations_raise_handler' | ||
| 9 | # I18n.exception_handler = :missing_translations_raise_handler | ||
| 10 | module I18n | ||
| 11 | class << self | ||
| 12 | def missing_translations_raise_handler(exception, locale, key, options) | ||
| 13 | raise exception | ||
| 14 | end | ||
| 15 | end | ||
| 16 | end | ||
| 17 | |||
| 18 | I18n.exception_handler = :missing_translations_raise_handler | ||
| 19 | |||
| 20 | ActionView::Helpers::TranslationHelper.module_eval do | ||
| 21 | def translate(key, options = {}) | ||
| 22 | I18n.translate(key, options) | ||
| 23 | end | ||
| 24 | alias :t :translate | ||
| 25 | end | ||
diff --git a/vendor/plugins/globalize2/test/active_record/fallbacks_test.rb b/vendor/plugins/globalize2/test/active_record/fallbacks_test.rb deleted file mode 100644 index 449ec8b..0000000 --- a/vendor/plugins/globalize2/test/active_record/fallbacks_test.rb +++ /dev/null | |||
| @@ -1,102 +0,0 @@ | |||
| 1 | require File.expand_path(File.dirname(__FILE__) + '/../test_helper') | ||
| 2 | require File.expand_path(File.dirname(__FILE__) + '/../data/models') | ||
| 3 | |||
| 4 | if I18n.respond_to?(:fallbacks) | ||
| 5 | class TranslatedTest < ActiveSupport::TestCase | ||
| 6 | def setup | ||
| 7 | I18n.locale = :'en-US' | ||
| 8 | I18n.fallbacks.clear | ||
| 9 | reset_db! | ||
| 10 | ActiveRecord::Base.locale = nil | ||
| 11 | end | ||
| 12 | |||
| 13 | def teardown | ||
| 14 | I18n.fallbacks.clear | ||
| 15 | end | ||
| 16 | |||
| 17 | test "keeping one field in new locale when other field is changed" do | ||
| 18 | I18n.fallbacks.map 'de-DE' => [ 'en-US' ] | ||
| 19 | post = Post.create :subject => 'foo' | ||
| 20 | I18n.locale = 'de-DE' | ||
| 21 | post.content = 'bar' | ||
| 22 | assert_equal 'foo', post.subject | ||
| 23 | end | ||
| 24 | |||
| 25 | test "modifying non-required field in a new locale" do | ||
| 26 | I18n.fallbacks.map 'de-DE' => [ 'en-US' ] | ||
| 27 | post = Post.create :subject => 'foo' | ||
| 28 | I18n.locale = 'de-DE' | ||
| 29 | post.content = 'bar' | ||
| 30 | assert post.save | ||
| 31 | end | ||
| 32 | |||
| 33 | test "resolves a simple fallback" do | ||
| 34 | I18n.locale = 'de-DE' | ||
| 35 | post = Post.create :subject => 'foo' | ||
| 36 | I18n.locale = 'de' | ||
| 37 | post.subject = 'baz' | ||
| 38 | post.content = 'bar' | ||
| 39 | post.save | ||
| 40 | I18n.locale = 'de-DE' | ||
| 41 | assert_equal 'foo', post.subject | ||
| 42 | assert_equal 'bar', post.content | ||
| 43 | end | ||
| 44 | |||
| 45 | test "resolves a simple fallback without reloading" do | ||
| 46 | I18n.locale = 'de-DE' | ||
| 47 | post = Post.new :subject => 'foo' | ||
| 48 | I18n.locale = 'de' | ||
| 49 | post.subject = 'baz' | ||
| 50 | post.content = 'bar' | ||
| 51 | I18n.locale = 'de-DE' | ||
| 52 | assert_equal 'foo', post.subject | ||
| 53 | assert_equal 'bar', post.content | ||
| 54 | end | ||
| 55 | |||
| 56 | test "resolves a complex fallback without reloading" do | ||
| 57 | I18n.fallbacks.map 'de' => %w(en he) | ||
| 58 | I18n.locale = 'de' | ||
| 59 | post = Post.new | ||
| 60 | I18n.locale = 'en' | ||
| 61 | post.subject = 'foo' | ||
| 62 | I18n.locale = 'he' | ||
| 63 | post.subject = 'baz' | ||
| 64 | post.content = 'bar' | ||
| 65 | I18n.locale = 'de' | ||
| 66 | assert_equal 'foo', post.subject | ||
| 67 | assert_equal 'bar', post.content | ||
| 68 | end | ||
| 69 | |||
| 70 | test 'fallbacks with lots of locale switching' do | ||
| 71 | I18n.fallbacks.map :'de-DE' => [ :'en-US' ] | ||
| 72 | post = Post.create :subject => 'foo' | ||
| 73 | |||
| 74 | I18n.locale = :'de-DE' | ||
| 75 | assert_equal 'foo', post.subject | ||
| 76 | |||
| 77 | I18n.locale = :'en-US' | ||
| 78 | post.update_attribute :subject, 'bar' | ||
| 79 | |||
| 80 | I18n.locale = :'de-DE' | ||
| 81 | assert_equal 'bar', post.subject | ||
| 82 | end | ||
| 83 | |||
| 84 | test 'fallbacks with lots of locale switching' do | ||
| 85 | I18n.fallbacks.map :'de-DE' => [ :'en-US' ] | ||
| 86 | child = Child.create :content => 'foo' | ||
| 87 | |||
| 88 | I18n.locale = :'de-DE' | ||
| 89 | assert_equal 'foo', child.content | ||
| 90 | |||
| 91 | I18n.locale = :'en-US' | ||
| 92 | child.update_attribute :content, 'bar' | ||
| 93 | |||
| 94 | I18n.locale = :'de-DE' | ||
| 95 | assert_equal 'bar', child.content | ||
| 96 | end | ||
| 97 | end | ||
| 98 | end | ||
| 99 | |||
| 100 | # TODO should validate_presence_of take fallbacks into account? maybe we need | ||
| 101 | # an extra validation call, or more options for validate_presence_of. | ||
| 102 | |||
diff --git a/vendor/plugins/globalize2/test/active_record/migration_test.rb b/vendor/plugins/globalize2/test/active_record/migration_test.rb deleted file mode 100644 index 359d811..0000000 --- a/vendor/plugins/globalize2/test/active_record/migration_test.rb +++ /dev/null | |||
| @@ -1,118 +0,0 @@ | |||
| 1 | require File.expand_path(File.dirname(__FILE__) + '/../test_helper') | ||
| 2 | require File.expand_path(File.dirname(__FILE__) + '/../data/models') | ||
| 3 | |||
| 4 | class MigrationTest < ActiveSupport::TestCase | ||
| 5 | def setup | ||
| 6 | reset_db! | ||
| 7 | Post.drop_translation_table! | ||
| 8 | end | ||
| 9 | |||
| 10 | test 'globalize table added' do | ||
| 11 | assert !Post.connection.table_exists?(:post_translations) | ||
| 12 | assert !Post.connection.index_exists?(:post_translations, :post_id) | ||
| 13 | |||
| 14 | Post.create_translation_table!(:subject => :string, :content => :text) | ||
| 15 | assert Post.connection.table_exists?(:post_translations) | ||
| 16 | assert Post.connection.index_exists?(:post_translations, :post_id) | ||
| 17 | |||
| 18 | columns = Post.connection.columns(:post_translations) | ||
| 19 | assert locale = columns.detect { |c| c.name == 'locale' } | ||
| 20 | assert_equal :string, locale.type | ||
| 21 | assert subject = columns.detect { |c| c.name == 'subject' } | ||
| 22 | assert_equal :string, subject.type | ||
| 23 | assert content = columns.detect { |c| c.name == 'content' } | ||
| 24 | assert_equal :text, content.type | ||
| 25 | assert post_id = columns.detect { |c| c.name == 'post_id' } | ||
| 26 | assert_equal :integer, post_id.type | ||
| 27 | assert created_at = columns.detect { |c| c.name == 'created_at' } | ||
| 28 | assert_equal :datetime, created_at.type | ||
| 29 | assert updated_at = columns.detect { |c| c.name == 'updated_at' } | ||
| 30 | assert_equal :datetime, updated_at.type | ||
| 31 | end | ||
| 32 | |||
| 33 | test 'globalize table dropped' do | ||
| 34 | assert !Post.connection.table_exists?( :post_translations ) | ||
| 35 | assert !Post.connection.index_exists?( :post_translations, :post_id ) | ||
| 36 | Post.create_translation_table! :subject => :string, :content => :text | ||
| 37 | assert Post.connection.table_exists?( :post_translations ) | ||
| 38 | assert Post.connection.index_exists?( :post_translations, :post_id ) | ||
| 39 | Post.drop_translation_table! | ||
| 40 | assert !Post.connection.table_exists?( :post_translations ) | ||
| 41 | assert !Post.connection.index_exists?( :post_translations, :post_id ) | ||
| 42 | end | ||
| 43 | |||
| 44 | test 'exception on missing field inputs' do | ||
| 45 | assert_raise Globalize::MigrationMissingTranslatedField do | ||
| 46 | Post.create_translation_table! :content => :text | ||
| 47 | end | ||
| 48 | end | ||
| 49 | |||
| 50 | test 'exception on bad input type' do | ||
| 51 | assert_raise Globalize::BadMigrationFieldType do | ||
| 52 | Post.create_translation_table! :subject => :string, :content => :integer | ||
| 53 | end | ||
| 54 | end | ||
| 55 | |||
| 56 | test "exception on bad input type isn't raised for untranslated fields" do | ||
| 57 | assert_nothing_raised do | ||
| 58 | Post.create_translation_table! :subject => :string, :content => :string, :views_count => :integer | ||
| 59 | end | ||
| 60 | end | ||
| 61 | |||
| 62 | test 'create_translation_table! should not be called on non-translated models' do | ||
| 63 | assert_raise NoMethodError do | ||
| 64 | Blog.create_translation_table! :name => :string | ||
| 65 | end | ||
| 66 | end | ||
| 67 | |||
| 68 | test 'drop_translation_table! should not be called on non-translated models' do | ||
| 69 | assert_raise NoMethodError do | ||
| 70 | Blog.drop_translation_table! | ||
| 71 | end | ||
| 72 | end | ||
| 73 | |||
| 74 | test "translation_index_name returns a readable index name when it's not longer than 50 characters" do | ||
| 75 | assert_equal 'index_post_translations_on_post_id', Post.send(:translation_index_name) | ||
| 76 | end | ||
| 77 | |||
| 78 | test "translation_index_name returns a hashed index name when it's longer than 50 characters" do | ||
| 79 | class UltraLongModelNameWithoutProper < ActiveRecord::Base | ||
| 80 | translates :foo | ||
| 81 | end | ||
| 82 | name = UltraLongModelNameWithoutProper.send(:translation_index_name) | ||
| 83 | assert_match /^index_[a-z0-9]{40}$/, name | ||
| 84 | end | ||
| 85 | |||
| 86 | test 'globalize table added when table has long name' do | ||
| 87 | UltraLongModelNameWithoutProper.create_translation_table!( | ||
| 88 | :subject => :string, :content => :text | ||
| 89 | ) | ||
| 90 | |||
| 91 | assert UltraLongModelNameWithoutProper.connection.table_exists?( | ||
| 92 | :ultra_long_model_name_without_proper_translations | ||
| 93 | ) | ||
| 94 | assert UltraLongModelNameWithoutProper.connection.index_exists?( | ||
| 95 | :ultra_long_model_name_without_proper_translations, | ||
| 96 | :name => UltraLongModelNameWithoutProper.send( | ||
| 97 | :translation_index_name | ||
| 98 | ) | ||
| 99 | ) | ||
| 100 | end | ||
| 101 | |||
| 102 | test 'globalize table dropped when table has long name' do | ||
| 103 | UltraLongModelNameWithoutProper.drop_translation_table! | ||
| 104 | UltraLongModelNameWithoutProper.create_translation_table!( | ||
| 105 | :subject => :string, :content => :text | ||
| 106 | ) | ||
| 107 | UltraLongModelNameWithoutProper.drop_translation_table! | ||
| 108 | |||
| 109 | assert !UltraLongModelNameWithoutProper.connection.table_exists?( | ||
| 110 | :ultra_long_model_name_without_proper_translations | ||
| 111 | ) | ||
| 112 | assert !UltraLongModelNameWithoutProper.connection.index_exists?( | ||
| 113 | :ultra_long_model_name_without_proper_translations, | ||
| 114 | :ultra_long_model_name_without_proper_id | ||
| 115 | ) | ||
| 116 | end | ||
| 117 | |||
| 118 | end | ||
diff --git a/vendor/plugins/globalize2/test/active_record/sti_translated_test.rb b/vendor/plugins/globalize2/test/active_record/sti_translated_test.rb deleted file mode 100644 index f529b8d..0000000 --- a/vendor/plugins/globalize2/test/active_record/sti_translated_test.rb +++ /dev/null | |||
| @@ -1,49 +0,0 @@ | |||
| 1 | require File.expand_path(File.dirname(__FILE__) + '/../test_helper') | ||
| 2 | require File.expand_path(File.dirname(__FILE__) + '/../data/models') | ||
| 3 | |||
| 4 | class StiTranslatedTest < ActiveSupport::TestCase | ||
| 5 | def setup | ||
| 6 | I18n.locale = :'en-US' | ||
| 7 | reset_db! | ||
| 8 | end | ||
| 9 | |||
| 10 | test "works with simple dynamic finders" do | ||
| 11 | foo = Child.create :content => 'foo' | ||
| 12 | Child.create :content => 'bar' | ||
| 13 | child = Child.find_by_content('foo') | ||
| 14 | assert_equal foo, child | ||
| 15 | end | ||
| 16 | |||
| 17 | test 'change attribute on globalized model' do | ||
| 18 | child = Child.create :content => 'foo' | ||
| 19 | assert_equal [], child.changed | ||
| 20 | child.content = 'bar' | ||
| 21 | assert_equal [ 'content' ], child.changed | ||
| 22 | child.content = 'baz' | ||
| 23 | assert_member 'content', child.changed | ||
| 24 | end | ||
| 25 | |||
| 26 | test 'change attribute on globalized model after locale switching' do | ||
| 27 | child = Child.create :content => 'foo' | ||
| 28 | assert_equal [], child.changed | ||
| 29 | child.content = 'bar' | ||
| 30 | I18n.locale = :de | ||
| 31 | assert_equal [ 'content' ], child.changed | ||
| 32 | end | ||
| 33 | |||
| 34 | test "saves all locales, even after locale switching" do | ||
| 35 | child = Child.new :content => 'foo' | ||
| 36 | I18n.locale = 'de-DE' | ||
| 37 | child.content = 'bar' | ||
| 38 | I18n.locale = 'he-IL' | ||
| 39 | child.content = 'baz' | ||
| 40 | child.save | ||
| 41 | I18n.locale = 'en-US' | ||
| 42 | child = Child.first | ||
| 43 | assert_equal 'foo', child.content | ||
| 44 | I18n.locale = 'de-DE' | ||
| 45 | assert_equal 'bar', child.content | ||
| 46 | I18n.locale = 'he-IL' | ||
| 47 | assert_equal 'baz', child.content | ||
| 48 | end | ||
| 49 | end | ||
diff --git a/vendor/plugins/globalize2/test/active_record/translates_test.rb b/vendor/plugins/globalize2/test/active_record/translates_test.rb deleted file mode 100644 index 4207bc4..0000000 --- a/vendor/plugins/globalize2/test/active_record/translates_test.rb +++ /dev/null | |||
| @@ -1,87 +0,0 @@ | |||
| 1 | require File.expand_path(File.dirname(__FILE__) + '/../test_helper') | ||
| 2 | require File.expand_path(File.dirname(__FILE__) + '/../data/models') | ||
| 3 | |||
| 4 | class TranslatesTest < ActiveSupport::TestCase | ||
| 5 | def setup | ||
| 6 | I18n.locale = nil | ||
| 7 | ActiveRecord::Base.locale = nil | ||
| 8 | reset_db! | ||
| 9 | end | ||
| 10 | |||
| 11 | test 'defines a :locale accessors on ActiveRecord::Base' do | ||
| 12 | ActiveRecord::Base.locale = :de | ||
| 13 | assert_equal :de, ActiveRecord::Base.locale | ||
| 14 | end | ||
| 15 | |||
| 16 | test 'the :locale reader on ActiveRecord::Base does not default to I18n.locale (anymore)' do | ||
| 17 | I18n.locale = :en | ||
| 18 | assert_nil ActiveRecord::Base.locale | ||
| 19 | end | ||
| 20 | |||
| 21 | test 'ActiveRecord::Base.with_locale temporarily sets the given locale and yields the block' do | ||
| 22 | I18n.locale = :en | ||
| 23 | post = Post.with_locale(:de) do | ||
| 24 | Post.create!(:subject => 'Titel', :content => 'Inhalt') | ||
| 25 | end | ||
| 26 | assert_nil Post.locale | ||
| 27 | assert_equal :en, I18n.locale | ||
| 28 | |||
| 29 | I18n.locale = :de | ||
| 30 | assert_equal 'Titel', post.subject | ||
| 31 | end | ||
| 32 | |||
| 33 | test 'translation_class returns the Translation class' do | ||
| 34 | assert_equal Post::Translation, Post.translation_class | ||
| 35 | end | ||
| 36 | |||
| 37 | test 'defines a has_many association on the model class' do | ||
| 38 | assert_has_many Post, :translations | ||
| 39 | end | ||
| 40 | |||
| 41 | test 'defines a scope for retrieving locales that have complete translations' do | ||
| 42 | post = Post.create!(:subject => 'subject', :content => 'content') | ||
| 43 | assert_equal [:en], post.translated_locales | ||
| 44 | end | ||
| 45 | |||
| 46 | test 'sets the given attributes to translated_attribute_names' do | ||
| 47 | assert_equal [:subject, :content], Post.translated_attribute_names | ||
| 48 | end | ||
| 49 | |||
| 50 | test 'defines accessors for the translated attributes' do | ||
| 51 | post = Post.new | ||
| 52 | assert post.respond_to?(:subject) | ||
| 53 | assert post.respond_to?(:subject=) | ||
| 54 | end | ||
| 55 | |||
| 56 | test 'attribute reader without arguments will use the current locale on ActiveRecord::Base or I18n' do | ||
| 57 | post = Post.with_locale(:de) do | ||
| 58 | Post.create!(:subject => 'Titel', :content => 'Inhalt') | ||
| 59 | end | ||
| 60 | I18n.locale = :de | ||
| 61 | assert_equal 'Titel', post.subject | ||
| 62 | |||
| 63 | I18n.locale = :en | ||
| 64 | ActiveRecord::Base.locale = :de | ||
| 65 | assert_equal 'Titel', post.subject | ||
| 66 | end | ||
| 67 | |||
| 68 | test 'attribute reader when passed a locale will use the given locale' do | ||
| 69 | post = Post.with_locale(:de) do | ||
| 70 | Post.create!(:subject => 'Titel', :content => 'Inhalt') | ||
| 71 | end | ||
| 72 | assert_equal 'Titel', post.subject(:de) | ||
| 73 | end | ||
| 74 | |||
| 75 | test 'attribute reader will use the current locale on ActiveRecord::Base or I18n' do | ||
| 76 | post = Post.with_locale(:en) do | ||
| 77 | Post.create!(:subject => 'title', :content => 'content') | ||
| 78 | end | ||
| 79 | I18n.locale = :de | ||
| 80 | post.subject = 'Titel' | ||
| 81 | assert_equal 'Titel', post.subject | ||
| 82 | |||
| 83 | ActiveRecord::Base.locale = :en | ||
| 84 | post.subject = 'title' | ||
| 85 | assert_equal 'title', post.subject | ||
| 86 | end | ||
| 87 | end | ||
diff --git a/vendor/plugins/globalize2/test/active_record/translation_class_test.rb b/vendor/plugins/globalize2/test/active_record/translation_class_test.rb deleted file mode 100644 index 1628416..0000000 --- a/vendor/plugins/globalize2/test/active_record/translation_class_test.rb +++ /dev/null | |||
| @@ -1,30 +0,0 @@ | |||
| 1 | require File.expand_path(File.dirname(__FILE__) + '/../test_helper') | ||
| 2 | require File.expand_path(File.dirname(__FILE__) + '/../data/models') | ||
| 3 | |||
| 4 | class TranlationClassTest < ActiveSupport::TestCase | ||
| 5 | def setup | ||
| 6 | reset_db! | ||
| 7 | end | ||
| 8 | |||
| 9 | test 'defines a Translation class nested in the model class' do | ||
| 10 | assert Post.const_defined?(:Translation) | ||
| 11 | end | ||
| 12 | |||
| 13 | test 'defines a belongs_to association' do | ||
| 14 | assert_belongs_to Post::Translation, :post | ||
| 15 | end | ||
| 16 | |||
| 17 | test 'defines a reader for :locale that always returns a symbol' do | ||
| 18 | post = Post::Translation.new | ||
| 19 | post.write_attribute('locale', 'de') | ||
| 20 | assert_equal :de, post.locale | ||
| 21 | end | ||
| 22 | |||
| 23 | test 'defines a write for :locale that always writes a string' do | ||
| 24 | post = Post::Translation.new | ||
| 25 | post.locale = :de | ||
| 26 | assert_equal 'de', post.read_attribute('locale') | ||
| 27 | end | ||
| 28 | end | ||
| 29 | |||
| 30 | |||
diff --git a/vendor/plugins/globalize2/test/active_record/validation_tests.rb b/vendor/plugins/globalize2/test/active_record/validation_tests.rb deleted file mode 100644 index 0148fa3..0000000 --- a/vendor/plugins/globalize2/test/active_record/validation_tests.rb +++ /dev/null | |||
| @@ -1,75 +0,0 @@ | |||
| 1 | require File.expand_path(File.dirname(__FILE__) + '/../test_helper') | ||
| 2 | require File.expand_path(File.dirname(__FILE__) + '/../data/models') | ||
| 3 | |||
| 4 | class ValidationTest < ActiveSupport::TestCase | ||
| 5 | def setup | ||
| 6 | reset_db! | ||
| 7 | end | ||
| 8 | |||
| 9 | def teardown | ||
| 10 | Validatee.instance_variable_set(:@validate_callbacks, CallbackChain.new) | ||
| 11 | end | ||
| 12 | |||
| 13 | test "validates_presence_of" do | ||
| 14 | Validatee.class_eval { validates_presence_of :string } | ||
| 15 | assert !Validatee.new.valid? | ||
| 16 | assert Validatee.new(:string => 'foo').valid? | ||
| 17 | end | ||
| 18 | |||
| 19 | test "validates_confirmation_of" do | ||
| 20 | Validatee.class_eval { validates_confirmation_of :string } | ||
| 21 | assert !Validatee.new(:string => 'foo', :string_confirmation => 'bar').valid? | ||
| 22 | assert Validatee.new(:string => 'foo', :string_confirmation => 'foo').valid? | ||
| 23 | end | ||
| 24 | |||
| 25 | test "validates_acceptance_of" do | ||
| 26 | Validatee.class_eval { validates_acceptance_of :string, :accept => '1' } | ||
| 27 | assert !Validatee.new(:string => '0').valid? | ||
| 28 | assert Validatee.new(:string => '1').valid? | ||
| 29 | end | ||
| 30 | |||
| 31 | test "validates_length_of (:is)" do | ||
| 32 | Validatee.class_eval { validates_length_of :string, :is => 1 } | ||
| 33 | assert !Validatee.new(:string => 'aa').valid? | ||
| 34 | assert Validatee.new(:string => 'a').valid? | ||
| 35 | end | ||
| 36 | |||
| 37 | test "validates_format_of" do | ||
| 38 | Validatee.class_eval { validates_format_of :string, :with => /^\d+$/ } | ||
| 39 | assert !Validatee.new(:string => 'a').valid? | ||
| 40 | assert Validatee.new(:string => '1').valid? | ||
| 41 | end | ||
| 42 | |||
| 43 | test "validates_inclusion_of" do | ||
| 44 | Validatee.class_eval { validates_inclusion_of :string, :in => %(a) } | ||
| 45 | assert !Validatee.new(:string => 'b').valid? | ||
| 46 | assert Validatee.new(:string => 'a').valid? | ||
| 47 | end | ||
| 48 | |||
| 49 | test "validates_exclusion_of" do | ||
| 50 | Validatee.class_eval { validates_exclusion_of :string, :in => %(b) } | ||
| 51 | assert !Validatee.new(:string => 'b').valid? | ||
| 52 | assert Validatee.new(:string => 'a').valid? | ||
| 53 | end | ||
| 54 | |||
| 55 | test "validates_numericality_of" do | ||
| 56 | Validatee.class_eval { validates_numericality_of :string } | ||
| 57 | assert !Validatee.new(:string => 'a').valid? | ||
| 58 | assert Validatee.new(:string => '1').valid? | ||
| 59 | end | ||
| 60 | |||
| 61 | # This doesn't pass and Rails' validates_uniqueness_of implementation doesn't | ||
| 62 | # seem to be extensible easily. One can work around that by either defining | ||
| 63 | # a custom validation on the Validatee model itself, or by using validates_uniqueness_of | ||
| 64 | # on Validatee::Translation. | ||
| 65 | # | ||
| 66 | # test "validates_uniqueness_of" do | ||
| 67 | # Validatee.class_eval { validates_uniqueness_of :string } | ||
| 68 | # Validatee.create!(:string => 'a') | ||
| 69 | # assert !Validatee.new(:string => 'a').valid? | ||
| 70 | # assert Validatee.new(:string => 'b').valid? | ||
| 71 | # end | ||
| 72 | |||
| 73 | # test "validates_associated" do | ||
| 74 | # end | ||
| 75 | end \ No newline at end of file | ||
diff --git a/vendor/plugins/globalize2/test/active_record_test.rb b/vendor/plugins/globalize2/test/active_record_test.rb deleted file mode 100644 index e6b54f0..0000000 --- a/vendor/plugins/globalize2/test/active_record_test.rb +++ /dev/null | |||
| @@ -1,442 +0,0 @@ | |||
| 1 | require File.expand_path(File.dirname(__FILE__) + '/test_helper') | ||
| 2 | require File.expand_path(File.dirname(__FILE__) + '/data/models') | ||
| 3 | |||
| 4 | # Higher level tests. | ||
| 5 | |||
| 6 | class ActiveRecordTest < ActiveSupport::TestCase | ||
| 7 | def setup | ||
| 8 | I18n.locale = :en | ||
| 9 | reset_db! | ||
| 10 | ActiveRecord::Base.locale = nil | ||
| 11 | end | ||
| 12 | |||
| 13 | def assert_translated(locale, record, names, expected) | ||
| 14 | I18n.locale = locale | ||
| 15 | assert_equal Array(expected), Array(names).map { |name| record.send(name) } | ||
| 16 | end | ||
| 17 | |||
| 18 | test "a translated record has translations" do | ||
| 19 | assert_equal [], Post.new.translations | ||
| 20 | end | ||
| 21 | |||
| 22 | test "saves a translated version of the record for each locale" do | ||
| 23 | post = Post.create(:subject => 'title') | ||
| 24 | I18n.locale = :de | ||
| 25 | post.update_attributes(:subject => 'Titel') | ||
| 26 | |||
| 27 | assert_equal 2, post.translations.size | ||
| 28 | assert_equal %w(de en), post.translations.map(&:locale).map(&:to_s).sort | ||
| 29 | assert_equal %w(Titel title), post.translations.map(&:subject).sort | ||
| 30 | end | ||
| 31 | |||
| 32 | test "a translated record has German translations" do | ||
| 33 | I18n.locale = :de | ||
| 34 | post = Post.create(:subject => 'foo') | ||
| 35 | assert_equal 1, post.translations.size | ||
| 36 | assert_equal [:de], post.translations.map { |t| t.locale } | ||
| 37 | end | ||
| 38 | |||
| 39 | test "modifiying translated fields while switching locales" do | ||
| 40 | post = Post.create(:subject => 'title', :content => 'content') | ||
| 41 | assert_equal %w(title content), [post.subject, post.content] | ||
| 42 | |||
| 43 | I18n.locale = :de | ||
| 44 | post.subject, post.content = 'Titel', 'Inhalt' | ||
| 45 | |||
| 46 | assert_translated(:de, post, [:subject, :content], %w(Titel Inhalt)) | ||
| 47 | assert_translated(:en, post, [:subject, :content], %w(title content)) | ||
| 48 | assert_translated(:de, post, [:subject, :content], %w(Titel Inhalt)) | ||
| 49 | |||
| 50 | post.save | ||
| 51 | post.reload | ||
| 52 | |||
| 53 | assert_translated(:en, post, [:subject, :content], %w(title content)) | ||
| 54 | assert_translated(:de, post, [:subject, :content], %w(Titel Inhalt)) | ||
| 55 | end | ||
| 56 | |||
| 57 | test "attribute writers do return their argument" do | ||
| 58 | value = Post.new.subject = 'foo' | ||
| 59 | assert_equal 'foo', value | ||
| 60 | end | ||
| 61 | |||
| 62 | test "update_attribute succeeds with valid values" do | ||
| 63 | post = Post.create(:subject => 'foo', :content => 'bar') | ||
| 64 | post.update_attribute(:subject, 'baz') | ||
| 65 | assert_equal 'baz', Post.first.subject | ||
| 66 | end | ||
| 67 | |||
| 68 | test "update_attributes fails with invalid values" do | ||
| 69 | post = Post.create(:subject => 'foo', :content => 'bar') | ||
| 70 | assert !post.update_attributes(:subject => '') | ||
| 71 | assert_nil post.reload.attributes['subject'] | ||
| 72 | assert_equal 'foo', post.subject | ||
| 73 | end | ||
| 74 | |||
| 75 | test "passing the locale to create uses the given locale" do | ||
| 76 | post = Post.create(:subject => 'Titel', :content => 'Inhalt', :locale => :de) | ||
| 77 | assert_equal :en, I18n.locale | ||
| 78 | assert_nil ActiveRecord::Base.locale | ||
| 79 | |||
| 80 | I18n.locale = :de | ||
| 81 | assert_equal 'Titel', post.subject | ||
| 82 | end | ||
| 83 | |||
| 84 | test "passing the locale to attributes= uses the given locale" do | ||
| 85 | post = Post.create(:subject => 'title', :content => 'content') | ||
| 86 | post.update_attributes(:subject => 'Titel', :content => 'Inhalt', :locale => :de) | ||
| 87 | post.reload | ||
| 88 | |||
| 89 | assert_equal :en, I18n.locale | ||
| 90 | assert_nil ActiveRecord::Base.locale | ||
| 91 | |||
| 92 | assert_equal 'title', post.subject | ||
| 93 | I18n.locale = :de | ||
| 94 | assert_equal 'Titel', post.subject | ||
| 95 | end | ||
| 96 | |||
| 97 | test 'reload works' do | ||
| 98 | post = Post.create(:subject => 'foo', :content => 'bar') | ||
| 99 | post.subject = 'baz' | ||
| 100 | post.reload | ||
| 101 | assert_equal 'foo', post.subject | ||
| 102 | end | ||
| 103 | |||
| 104 | test "returns nil if no translations are found (unsaved record)" do | ||
| 105 | post = Post.new(:subject => 'foo') | ||
| 106 | assert_equal 'foo', post.subject | ||
| 107 | assert_nil post.content | ||
| 108 | end | ||
| 109 | |||
| 110 | test "returns nil if no translations are found (saved record)" do | ||
| 111 | post = Post.create(:subject => 'foo') | ||
| 112 | post.reload | ||
| 113 | assert_equal 'foo', post.subject | ||
| 114 | assert_nil post.content | ||
| 115 | end | ||
| 116 | |||
| 117 | test "finds a German post" do | ||
| 118 | post = Post.create(:subject => 'foo (en)', :content => 'bar') | ||
| 119 | I18n.locale = :de | ||
| 120 | post = Post.first | ||
| 121 | post.subject = 'baz (de)' | ||
| 122 | post.save | ||
| 123 | assert_equal 'baz (de)', Post.first.subject | ||
| 124 | I18n.locale = :en | ||
| 125 | assert_equal 'foo (en)', Post.first.subject | ||
| 126 | end | ||
| 127 | |||
| 128 | test "saves an English post and loads correctly" do | ||
| 129 | post = Post.create(:subject => 'foo', :content => 'bar') | ||
| 130 | assert post.save | ||
| 131 | post = Post.first | ||
| 132 | assert_equal 'foo', post.subject | ||
| 133 | assert_equal 'bar', post.content | ||
| 134 | end | ||
| 135 | |||
| 136 | test "returns the value for the correct locale, after locale switching" do | ||
| 137 | post = Post.create(:subject => 'foo') | ||
| 138 | I18n.locale = :de | ||
| 139 | post.subject = 'bar' | ||
| 140 | post.save | ||
| 141 | I18n.locale = :en | ||
| 142 | post = Post.first | ||
| 143 | assert_equal 'foo', post.subject | ||
| 144 | I18n.locale = :de | ||
| 145 | assert_equal 'bar', post.subject | ||
| 146 | end | ||
| 147 | |||
| 148 | test "returns the value for the correct locale, after locale switching, without saving" do | ||
| 149 | post = Post.create :subject => 'foo' | ||
| 150 | I18n.locale = :de | ||
| 151 | post.subject = 'bar' | ||
| 152 | I18n.locale = :en | ||
| 153 | assert_equal 'foo', post.subject | ||
| 154 | I18n.locale = :de | ||
| 155 | assert_equal 'bar', post.subject | ||
| 156 | end | ||
| 157 | |||
| 158 | test "saves all locales, even after locale switching" do | ||
| 159 | post = Post.new :subject => 'foo' | ||
| 160 | I18n.locale = :de | ||
| 161 | post.subject = 'bar' | ||
| 162 | I18n.locale = :he | ||
| 163 | post.subject = 'baz' | ||
| 164 | post.save | ||
| 165 | I18n.locale = :en | ||
| 166 | post = Post.first | ||
| 167 | assert_equal 'foo', post.subject | ||
| 168 | I18n.locale = :de | ||
| 169 | assert_equal 'bar', post.subject | ||
| 170 | I18n.locale = :he | ||
| 171 | assert_equal 'baz', post.subject | ||
| 172 | end | ||
| 173 | |||
| 174 | test "works with associations" do | ||
| 175 | blog = Blog.create | ||
| 176 | post1 = blog.posts.create(:subject => 'foo') | ||
| 177 | |||
| 178 | I18n.locale = :de | ||
| 179 | post2 = blog.posts.create(:subject => 'bar') | ||
| 180 | assert_equal 2, blog.posts.size | ||
| 181 | |||
| 182 | I18n.locale = :en | ||
| 183 | assert_equal 'foo', blog.posts.first.subject | ||
| 184 | assert_nil blog.posts.last.subject | ||
| 185 | |||
| 186 | I18n.locale = :de | ||
| 187 | assert_equal 'bar', blog.posts.last.subject | ||
| 188 | end | ||
| 189 | |||
| 190 | test "works with simple dynamic finders" do | ||
| 191 | foo = Post.create(:subject => 'foo') | ||
| 192 | Post.create(:subject => 'bar') | ||
| 193 | post = Post.find_by_subject('foo') | ||
| 194 | assert_equal foo, post | ||
| 195 | end | ||
| 196 | |||
| 197 | test 'change attribute on globalized model' do | ||
| 198 | post = Post.create(:subject => 'foo', :content => 'bar') | ||
| 199 | assert_equal [], post.changed | ||
| 200 | post.subject = 'baz' | ||
| 201 | assert_equal ['subject'], post.changed | ||
| 202 | post.content = 'quux' | ||
| 203 | assert_member 'subject', post.changed | ||
| 204 | assert_member 'content', post.changed | ||
| 205 | end | ||
| 206 | |||
| 207 | test 'change attribute on globalized model after locale switching' do | ||
| 208 | post = Post.create(:subject => 'foo', :content => 'bar') | ||
| 209 | assert_equal [], post.changed | ||
| 210 | post.subject = 'baz' | ||
| 211 | I18n.locale = :de | ||
| 212 | assert_equal ['subject'], post.changed | ||
| 213 | end | ||
| 214 | |||
| 215 | test 'complex writing and stashing' do | ||
| 216 | post = Post.create(:subject => 'foo', :content => 'bar') | ||
| 217 | post.subject = nil | ||
| 218 | assert_nil post.subject | ||
| 219 | assert !post.valid? | ||
| 220 | post.subject = 'stashed_foo' | ||
| 221 | assert_equal 'stashed_foo', post.subject | ||
| 222 | end | ||
| 223 | |||
| 224 | test 'translated class locale setting' do | ||
| 225 | assert ActiveRecord::Base.respond_to?(:locale) | ||
| 226 | assert_equal :en, I18n.locale | ||
| 227 | assert_nil ActiveRecord::Base.locale | ||
| 228 | |||
| 229 | I18n.locale = :de | ||
| 230 | assert_equal :de, I18n.locale | ||
| 231 | assert_nil ActiveRecord::Base.locale | ||
| 232 | |||
| 233 | ActiveRecord::Base.locale = :es | ||
| 234 | assert_equal :de, I18n.locale | ||
| 235 | assert_equal :es, ActiveRecord::Base.locale | ||
| 236 | |||
| 237 | I18n.locale = :fr | ||
| 238 | assert_equal :fr, I18n.locale | ||
| 239 | assert_equal :es, ActiveRecord::Base.locale | ||
| 240 | end | ||
| 241 | |||
| 242 | test "untranslated class responds to locale" do | ||
| 243 | assert Blog.respond_to?(:locale) | ||
| 244 | end | ||
| 245 | |||
| 246 | test "to ensure locales in different classes are the same" do | ||
| 247 | ActiveRecord::Base.locale = :de | ||
| 248 | assert_equal :de, ActiveRecord::Base.locale | ||
| 249 | assert_equal :de, Parent.locale | ||
| 250 | |||
| 251 | Parent.locale = :es | ||
| 252 | assert_equal :es, ActiveRecord::Base.locale | ||
| 253 | assert_equal :es, Parent.locale | ||
| 254 | end | ||
| 255 | |||
| 256 | test "attribute saving goes by content locale and not global locale" do | ||
| 257 | ActiveRecord::Base.locale = :de | ||
| 258 | assert_equal :en, I18n.locale | ||
| 259 | Post.create :subject => 'foo' | ||
| 260 | assert_equal :de, Post.first.translations.first.locale | ||
| 261 | end | ||
| 262 | |||
| 263 | test "attribute loading goes by content locale and not global locale" do | ||
| 264 | post = Post.create(:subject => 'foo') | ||
| 265 | assert_nil ActiveRecord::Base.locale | ||
| 266 | |||
| 267 | ActiveRecord::Base.locale = :de | ||
| 268 | assert_equal :en, I18n.locale | ||
| 269 | post.update_attribute(:subject, 'foo [de]') | ||
| 270 | assert_equal 'foo [de]', Post.first.subject | ||
| 271 | |||
| 272 | ActiveRecord::Base.locale = :en | ||
| 273 | assert_equal 'foo', Post.first.subject | ||
| 274 | end | ||
| 275 | |||
| 276 | test "access content locale before setting" do | ||
| 277 | Globalize::ActiveRecord::ActMacro.class_eval "remove_class_variable(:@@locale)" | ||
| 278 | assert_nothing_raised { ActiveRecord::Base.locale } | ||
| 279 | end | ||
| 280 | |||
| 281 | test "available_locales" do | ||
| 282 | Post.locale = :de | ||
| 283 | post = Post.create(:subject => 'foo') | ||
| 284 | Post.locale = :es | ||
| 285 | post.update_attribute(:subject, 'bar') | ||
| 286 | Post.locale = :fr | ||
| 287 | post.update_attribute(:subject, 'baz') | ||
| 288 | assert_equal [:de, :es, :fr], post.available_locales | ||
| 289 | assert_equal [:de, :es, :fr], Post.first.available_locales | ||
| 290 | end | ||
| 291 | |||
| 292 | test "saving record correctly after post-save reload" do | ||
| 293 | reloader = Reloader.create(:content => 'foo') | ||
| 294 | assert_equal 'foo', reloader.content | ||
| 295 | end | ||
| 296 | |||
| 297 | test "including translations" do | ||
| 298 | I18n.locale = :de | ||
| 299 | Post.create(:subject => "Foo1", :content => "Bar1") | ||
| 300 | Post.create(:subject => "Foo2", :content => "Bar2") | ||
| 301 | |||
| 302 | class << Post | ||
| 303 | def translations_included | ||
| 304 | self.all(:include => :translations) | ||
| 305 | end | ||
| 306 | end | ||
| 307 | |||
| 308 | default = Post.all.map { |x| [x.subject, x.content] } | ||
| 309 | with_include = Post.translations_included.map { |x| [x.subject, x.content] } | ||
| 310 | assert_equal default, with_include | ||
| 311 | end | ||
| 312 | |||
| 313 | test "setting multiple translations at once with options hash" do | ||
| 314 | Post.locale = :de | ||
| 315 | post = Post.create(:subject => "foo1", :content => "foo1") | ||
| 316 | Post.locale = :en | ||
| 317 | post.update_attributes(:subject => "bar1", :content => "bar1") | ||
| 318 | |||
| 319 | options = { :de => {:subject => "foo2", :content => "foo2"}, | ||
| 320 | :en => {:subject => "bar2", :content => "bar2"} } | ||
| 321 | post.set_translations options | ||
| 322 | post.reload | ||
| 323 | |||
| 324 | assert ["bar2", "bar2"], [post.subject, post.content] | ||
| 325 | Post.locale = :de | ||
| 326 | assert ["foo2", "foo2"], [post.subject, post.content] | ||
| 327 | end | ||
| 328 | |||
| 329 | test "setting only one translation with set_translations" do | ||
| 330 | Post.locale = :de | ||
| 331 | post = Post.create(:subject => "foo1", :content => "foo1") | ||
| 332 | Post.locale = :en | ||
| 333 | post.update_attributes(:subject => "bar1", :content => "bar1") | ||
| 334 | |||
| 335 | options = { :en => { :subject => "bar2", :content => "bar2" } } | ||
| 336 | post.set_translations options | ||
| 337 | post.reload | ||
| 338 | |||
| 339 | assert ["bar2", "bar2"], [post.subject, post.content] | ||
| 340 | Post.locale = :de | ||
| 341 | assert ["foo1", "foo1"], [post.subject, post.content] | ||
| 342 | end | ||
| 343 | |||
| 344 | test "setting only selected attributes with set_translations" do | ||
| 345 | Post.locale = :de | ||
| 346 | post = Post.create(:subject => "foo1", :content => "foo1") | ||
| 347 | Post.locale = :en | ||
| 348 | post.update_attributes(:subject => "bar1", :content => "bar1") | ||
| 349 | |||
| 350 | options = { :de => { :content => "foo2" }, :en => { :subject => "bar2" } } | ||
| 351 | post.set_translations options | ||
| 352 | post.reload | ||
| 353 | |||
| 354 | assert ["bar2", "bar1"], [post.subject, post.content] | ||
| 355 | Post.locale = :de | ||
| 356 | assert ["foo1", "foo2"], [post.subject, post.content] | ||
| 357 | end | ||
| 358 | |||
| 359 | test "setting invalid attributes raises ArgumentError" do | ||
| 360 | Post.locale = :de | ||
| 361 | post = Post.create(:subject => "foo1", :content => "foo1") | ||
| 362 | Post.locale = :en | ||
| 363 | post.update_attributes(:subject => "bar1", :content => "bar1") | ||
| 364 | |||
| 365 | options = { :de => {:fake => "foo2"} } | ||
| 366 | exception = assert_raise(ActiveRecord::UnknownAttributeError) do | ||
| 367 | post.set_translations options | ||
| 368 | end | ||
| 369 | assert_equal "unknown attribute: fake", exception.message | ||
| 370 | end | ||
| 371 | |||
| 372 | test "reload accepting find options" do | ||
| 373 | p = Post.create(:subject => "Foo", :content => "Bar") | ||
| 374 | assert p.reload(:readonly => true, :lock => true) | ||
| 375 | assert_raise(ArgumentError) { p.reload(:foo => :bar) } | ||
| 376 | end | ||
| 377 | |||
| 378 | test "dependent destroy of translation" do | ||
| 379 | p = Post.create(:subject => "Foo", :content => "Bar") | ||
| 380 | assert_equal 1, PostTranslation.count | ||
| 381 | p.destroy | ||
| 382 | assert_equal 0, PostTranslation.count | ||
| 383 | end | ||
| 384 | |||
| 385 | test "translating subclass of untranslated comment model" do | ||
| 386 | translated_comment = TranslatedComment.create(:post => @post) | ||
| 387 | assert_nothing_raised { translated_comment.translations } | ||
| 388 | end | ||
| 389 | |||
| 390 | test "modifiying translated comments works as expected" do | ||
| 391 | I18n.locale = :en | ||
| 392 | translated_comment = TranslatedComment.create(:post => @post, :content => 'foo') | ||
| 393 | assert_equal 'foo', translated_comment.content | ||
| 394 | |||
| 395 | I18n.locale = :de | ||
| 396 | translated_comment.content = 'bar' | ||
| 397 | assert translated_comment.save | ||
| 398 | assert_equal 'bar', translated_comment.content | ||
| 399 | |||
| 400 | I18n.locale = :en | ||
| 401 | assert_equal 'foo', translated_comment.content | ||
| 402 | |||
| 403 | assert_equal 2, translated_comment.translations.size | ||
| 404 | end | ||
| 405 | |||
| 406 | test "can create a proxy class for a namespaced model" do | ||
| 407 | assert_nothing_raised do | ||
| 408 | module Foo | ||
| 409 | module Bar | ||
| 410 | class Baz < ActiveRecord::Base | ||
| 411 | translates :bumm | ||
| 412 | end | ||
| 413 | end | ||
| 414 | end | ||
| 415 | end | ||
| 416 | end | ||
| 417 | |||
| 418 | test "attribute translated before type cast" do | ||
| 419 | Post.locale = :en | ||
| 420 | post = Post.create(:subject => 'foo', :content => 'bar') | ||
| 421 | Post.locale = :de | ||
| 422 | post.update_attribute(:subject, "German foo") | ||
| 423 | assert_equal 'German foo', post.subject_before_type_cast | ||
| 424 | Post.locale = :en | ||
| 425 | assert_equal 'foo', post.subject_before_type_cast | ||
| 426 | end | ||
| 427 | |||
| 428 | test "don't override existing translation class" do | ||
| 429 | assert PostTranslation.new.respond_to?(:existing_method) | ||
| 430 | end | ||
| 431 | |||
| 432 | test "has_many and named scopes work with globalize" do | ||
| 433 | blog = Blog.create | ||
| 434 | assert_nothing_raised { blog.posts.foobar } | ||
| 435 | end | ||
| 436 | end | ||
| 437 | |||
| 438 | # TODO error checking for fields that exist in main table, don't exist in | ||
| 439 | # proxy table, aren't strings or text | ||
| 440 | # | ||
| 441 | # TODO allow finding by translated attributes in conditions? | ||
| 442 | # TODO generate advanced dynamic finders? | ||
diff --git a/vendor/plugins/globalize2/test/all.rb b/vendor/plugins/globalize2/test/all.rb deleted file mode 100644 index ff467a1..0000000 --- a/vendor/plugins/globalize2/test/all.rb +++ /dev/null | |||
| @@ -1,2 +0,0 @@ | |||
| 1 | files = Dir[File.dirname(__FILE__) + '/**/*_test.rb'] | ||
| 2 | files.each { |file| require file } \ No newline at end of file | ||
diff --git a/vendor/plugins/globalize2/test/data/models.rb b/vendor/plugins/globalize2/test/data/models.rb deleted file mode 100644 index 553fca3..0000000 --- a/vendor/plugins/globalize2/test/data/models.rb +++ /dev/null | |||
| @@ -1,51 +0,0 @@ | |||
| 1 | #require 'ruby2ruby' | ||
| 2 | #require 'parse_tree' | ||
| 3 | #require 'parse_tree_extensions' | ||
| 4 | #require 'pp' | ||
| 5 | |||
| 6 | class PostTranslation < ActiveRecord::Base | ||
| 7 | def existing_method ; end | ||
| 8 | end | ||
| 9 | |||
| 10 | class Post < ActiveRecord::Base | ||
| 11 | translates :subject, :content | ||
| 12 | validates_presence_of :subject | ||
| 13 | named_scope :foobar, :conditions => { :title => "foobar" } | ||
| 14 | end | ||
| 15 | |||
| 16 | class Blog < ActiveRecord::Base | ||
| 17 | has_many :posts, :order => 'id ASC' | ||
| 18 | end | ||
| 19 | |||
| 20 | class Parent < ActiveRecord::Base | ||
| 21 | translates :content | ||
| 22 | end | ||
| 23 | |||
| 24 | class Child < Parent | ||
| 25 | end | ||
| 26 | |||
| 27 | class Comment < ActiveRecord::Base | ||
| 28 | validates_presence_of :content | ||
| 29 | belongs_to :post | ||
| 30 | end | ||
| 31 | |||
| 32 | class TranslatedComment < Comment | ||
| 33 | translates :content | ||
| 34 | end | ||
| 35 | |||
| 36 | class UltraLongModelNameWithoutProper < ActiveRecord::Base | ||
| 37 | translates :subject, :content | ||
| 38 | validates_presence_of :subject | ||
| 39 | end | ||
| 40 | |||
| 41 | class Reloader < Parent | ||
| 42 | after_create :do_reload | ||
| 43 | |||
| 44 | def do_reload | ||
| 45 | reload | ||
| 46 | end | ||
| 47 | end | ||
| 48 | |||
| 49 | class Validatee < ActiveRecord::Base | ||
| 50 | translates :string | ||
| 51 | end | ||
diff --git a/vendor/plugins/globalize2/test/data/no_globalize_schema.rb b/vendor/plugins/globalize2/test/data/no_globalize_schema.rb deleted file mode 100644 index 379455d..0000000 --- a/vendor/plugins/globalize2/test/data/no_globalize_schema.rb +++ /dev/null | |||
| @@ -1,11 +0,0 @@ | |||
| 1 | # This schema creates tables without columns for the translated fields | ||
| 2 | ActiveRecord::Schema.define do | ||
| 3 | create_table :blogs, :force => true do |t| | ||
| 4 | t.string :name | ||
| 5 | end | ||
| 6 | |||
| 7 | create_table :posts, :force => true do |t| | ||
| 8 | t.references :blog | ||
| 9 | end | ||
| 10 | end | ||
| 11 | |||
diff --git a/vendor/plugins/globalize2/test/i18n/missing_translations_test.rb b/vendor/plugins/globalize2/test/i18n/missing_translations_test.rb deleted file mode 100644 index 5d0ecd6..0000000 --- a/vendor/plugins/globalize2/test/i18n/missing_translations_test.rb +++ /dev/null | |||
| @@ -1,36 +0,0 @@ | |||
| 1 | require File.dirname(__FILE__) + '/../test_helper' | ||
| 2 | require 'i18n/missing_translations_log_handler' | ||
| 3 | |||
| 4 | class MissingTranslationsTest < ActiveSupport::TestCase | ||
| 5 | test "defines I18n.missing_translations_logger accessor" do | ||
| 6 | assert I18n.respond_to?(:missing_translations_logger) | ||
| 7 | end | ||
| 8 | |||
| 9 | test "defines I18n.missing_translations_logger= writer" do | ||
| 10 | assert I18n.respond_to?(:missing_translations_logger=) | ||
| 11 | end | ||
| 12 | end | ||
| 13 | |||
| 14 | class TestLogger < String | ||
| 15 | def warn(msg) self.concat msg; end | ||
| 16 | end | ||
| 17 | |||
| 18 | class LogMissingTranslationsTest < ActiveSupport::TestCase | ||
| 19 | def setup | ||
| 20 | @locale, @key, @options = :en, :foo, {} | ||
| 21 | @exception = I18n::MissingTranslationData.new(@locale, @key, @options) | ||
| 22 | |||
| 23 | @logger = TestLogger.new | ||
| 24 | I18n.missing_translations_logger = @logger | ||
| 25 | end | ||
| 26 | |||
| 27 | test "still returns the exception message for MissingTranslationData exceptions" do | ||
| 28 | result = I18n.send(:missing_translations_log_handler, @exception, @locale, @key, @options) | ||
| 29 | assert_equal 'translation missing: en, foo', result | ||
| 30 | end | ||
| 31 | |||
| 32 | test "logs the missing translation to I18n.missing_translations_logger" do | ||
| 33 | I18n.send(:missing_translations_log_handler, @exception, @locale, @key, @options) | ||
| 34 | assert_equal 'translation missing: en, foo', @logger | ||
| 35 | end | ||
| 36 | end | ||
diff --git a/vendor/plugins/globalize2/test/test_helper.rb b/vendor/plugins/globalize2/test/test_helper.rb deleted file mode 100644 index 195907d..0000000 --- a/vendor/plugins/globalize2/test/test_helper.rb +++ /dev/null | |||
| @@ -1,76 +0,0 @@ | |||
| 1 | $LOAD_PATH << File.expand_path( File.dirname(__FILE__) + '/../lib' ) | ||
| 2 | |||
| 3 | require 'rubygems' | ||
| 4 | require 'test/unit' | ||
| 5 | require 'active_record' | ||
| 6 | require 'active_support' | ||
| 7 | require 'active_support/test_case' | ||
| 8 | require 'mocha' | ||
| 9 | require 'globalize' | ||
| 10 | require 'validation_reflection' | ||
| 11 | |||
| 12 | config = { :adapter => 'sqlite3', :database => ':memory:' } | ||
| 13 | ActiveRecord::Base.establish_connection(config) | ||
| 14 | |||
| 15 | class ActiveSupport::TestCase | ||
| 16 | def reset_db!(schema_path = nil) | ||
| 17 | schema_path ||= File.expand_path(File.dirname(__FILE__) + '/data/schema.rb') | ||
| 18 | ActiveRecord::Migration.verbose = false | ||
| 19 | ActiveRecord::Base.silence { load(schema_path) } | ||
| 20 | end | ||
| 21 | |||
| 22 | def assert_member(item, array) | ||
| 23 | assert_block "Item #{item} is not in array #{array}" do | ||
| 24 | array.member?(item) | ||
| 25 | end | ||
| 26 | end | ||
| 27 | |||
| 28 | def assert_belongs_to(model, associated) | ||
| 29 | assert model.reflect_on_all_associations(:belongs_to).detect { |association| | ||
| 30 | association.name.to_s == associated.to_s | ||
| 31 | } | ||
| 32 | end | ||
| 33 | |||
| 34 | def assert_has_many(model, associated) | ||
| 35 | assert model.reflect_on_all_associations(:has_many).detect { |association| | ||
| 36 | association.name.to_s == associated.to_s | ||
| 37 | } | ||
| 38 | end | ||
| 39 | end | ||
| 40 | |||
| 41 | module ActiveRecord | ||
| 42 | module ConnectionAdapters | ||
| 43 | class AbstractAdapter | ||
| 44 | def index_exists?(table_name, column_name) | ||
| 45 | indexes(table_name).any? { |index| index.name == index_name(table_name, column_name) } | ||
| 46 | end | ||
| 47 | end | ||
| 48 | end | ||
| 49 | end | ||
| 50 | |||
| 51 | # module ActiveRecord | ||
| 52 | # class BaseWithoutTable < Base | ||
| 53 | # self.abstract_class = true | ||
| 54 | # | ||
| 55 | # def create_or_update | ||
| 56 | # errors.empty? | ||
| 57 | # end | ||
| 58 | # | ||
| 59 | # class << self | ||
| 60 | # def columns() | ||
| 61 | # @columns ||= [] | ||
| 62 | # end | ||
| 63 | # | ||
| 64 | # def column(name, sql_type = nil, default = nil, null = true) | ||
| 65 | # columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, sql_type.to_s, null) | ||
| 66 | # reset_column_information | ||
| 67 | # end | ||
| 68 | # | ||
| 69 | # # Do not reset @columns | ||
| 70 | # def reset_column_information | ||
| 71 | # read_methods.each { |name| undef_method(name) } | ||
| 72 | # @column_names = @columns_hash = @content_columns = @dynamic_methods_hash = @read_methods = nil | ||
| 73 | # end | ||
| 74 | # end | ||
| 75 | # end | ||
| 76 | # end \ No newline at end of file | ||
diff --git a/vendor/plugins/paperclip/LICENSE b/vendor/plugins/paperclip/LICENSE deleted file mode 100644 index 299b9ed..0000000 --- a/vendor/plugins/paperclip/LICENSE +++ /dev/null | |||
| @@ -1,26 +0,0 @@ | |||
| 1 | |||
| 2 | LICENSE | ||
| 3 | |||
| 4 | The MIT License | ||
| 5 | |||
| 6 | Copyright (c) 2008 Jon Yurek and thoughtbot, inc. | ||
| 7 | |||
| 8 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 9 | of this software and associated documentation files (the "Software"), to deal | ||
| 10 | in the Software without restriction, including without limitation the rights | ||
| 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 12 | copies of the Software, and to permit persons to whom the Software is | ||
| 13 | furnished to do so, subject to the following conditions: | ||
| 14 | |||
| 15 | The above copyright notice and this permission notice shall be included in | ||
| 16 | all copies or substantial portions of the Software. | ||
| 17 | |||
| 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 24 | THE SOFTWARE. | ||
| 25 | |||
| 26 | |||
diff --git a/vendor/plugins/paperclip/README.rdoc b/vendor/plugins/paperclip/README.rdoc deleted file mode 100644 index 85fcf4b..0000000 --- a/vendor/plugins/paperclip/README.rdoc +++ /dev/null | |||
| @@ -1,172 +0,0 @@ | |||
| 1 | =Paperclip | ||
| 2 | |||
| 3 | Paperclip is intended as an easy file attachment library for ActiveRecord. The | ||
| 4 | intent behind it was to keep setup as easy as possible and to treat files as | ||
| 5 | much like other attributes as possible. This means they aren't saved to their | ||
| 6 | final locations on disk, nor are they deleted if set to nil, until | ||
| 7 | ActiveRecord::Base#save is called. It manages validations based on size and | ||
| 8 | presence, if required. It can transform its assigned image into thumbnails if | ||
| 9 | needed, and the prerequisites are as simple as installing ImageMagick (which, | ||
| 10 | for most modern Unix-based systems, is as easy as installing the right | ||
| 11 | packages). Attached files are saved to the filesystem and referenced in the | ||
| 12 | browser by an easily understandable specification, which has sensible and | ||
| 13 | useful defaults. | ||
| 14 | |||
| 15 | See the documentation for +has_attached_file+ in Paperclip::ClassMethods for | ||
| 16 | more detailed options. | ||
| 17 | |||
| 18 | ==Quick Start | ||
| 19 | |||
| 20 | In your model: | ||
| 21 | |||
| 22 | class User < ActiveRecord::Base | ||
| 23 | has_attached_file :avatar, :styles => { :medium => "300x300>", :thumb => "100x100>" } | ||
| 24 | end | ||
| 25 | |||
| 26 | In your migrations: | ||
| 27 | |||
| 28 | class AddAvatarColumnsToUser < ActiveRecord::Migration | ||
| 29 | def self.up | ||
| 30 | add_column :users, :avatar_file_name, :string | ||
| 31 | add_column :users, :avatar_content_type, :string | ||
| 32 | add_column :users, :avatar_file_size, :integer | ||
| 33 | add_column :users, :avatar_updated_at, :datetime | ||
| 34 | end | ||
| 35 | |||
| 36 | def self.down | ||
| 37 | remove_column :users, :avatar_file_name | ||
| 38 | remove_column :users, :avatar_content_type | ||
| 39 | remove_column :users, :avatar_file_size | ||
| 40 | remove_column :users, :avatar_updated_at | ||
| 41 | end | ||
| 42 | end | ||
| 43 | |||
| 44 | In your edit and new views: | ||
| 45 | |||
| 46 | <% form_for :user, @user, :url => user_path, :html => { :multipart => true } do |form| %> | ||
| 47 | <%= form.file_field :avatar %> | ||
| 48 | <% end %> | ||
| 49 | |||
| 50 | In your controller: | ||
| 51 | |||
| 52 | def create | ||
| 53 | @user = User.create( params[:user] ) | ||
| 54 | end | ||
| 55 | |||
| 56 | In your show view: | ||
| 57 | |||
| 58 | <%= image_tag @user.avatar.url %> | ||
| 59 | <%= image_tag @user.avatar.url(:medium) %> | ||
| 60 | <%= image_tag @user.avatar.url(:thumb) %> | ||
| 61 | |||
| 62 | ==Usage | ||
| 63 | |||
| 64 | The basics of paperclip are quite simple: Declare that your model has an | ||
| 65 | attachment with the has_attached_file method, and give it a name. Paperclip | ||
| 66 | will wrap up up to four attributes (all prefixed with that attachment's name, | ||
| 67 | so you can have multiple attachments per model if you wish) and give the a | ||
| 68 | friendly front end. The attributes are <attachment>_file_name, | ||
| 69 | <attachment>_file_size, <attachment>_content_type, and <attachment>_updated_at. | ||
| 70 | Only <attachment>_file_name is required for paperclip to operate. More | ||
| 71 | information about the options to has_attached_file is available in the | ||
| 72 | documentation of Paperclip::ClassMethods. | ||
| 73 | |||
| 74 | Attachments can be validated with Paperclip's validation methods, | ||
| 75 | validates_attachment_presence, validates_attachment_content_type, and | ||
| 76 | validates_attachment_size. | ||
| 77 | |||
| 78 | ==Storage | ||
| 79 | |||
| 80 | The files that are assigned as attachments are, by default, placed in the | ||
| 81 | directory specified by the :path option to has_attached_file. By default, this | ||
| 82 | location is | ||
| 83 | ":rails_root/public/system/:attachment/:id/:style/:basename.:extension". This | ||
| 84 | location was chosen because on standard Capistrano deployments, the | ||
| 85 | public/system directory is symlinked to the app's shared directory, meaning it | ||
| 86 | will survive between deployments. For example, using that :path, you may have a | ||
| 87 | file at | ||
| 88 | |||
| 89 | /data/myapp/releases/20081229172410/public/system/avatars/13/small/my_pic.png | ||
| 90 | |||
| 91 | NOTE: This is a change from previous versions of Paperclip, but is overall a | ||
| 92 | safer choice for the defaul file store. | ||
| 93 | |||
| 94 | You may also choose to store your files using Amazon's S3 service. You can find | ||
| 95 | more information about S3 storage at the description for | ||
| 96 | Paperclip::Storage::S3. | ||
| 97 | |||
| 98 | Files on the local filesystem (and in the Rails app's public directory) will be | ||
| 99 | available to the internet at large. If you require access control, it's | ||
| 100 | possible to place your files in a different location. You will need to change | ||
| 101 | both the :path and :url options in order to make sure the files are unavailable | ||
| 102 | to the public. Both :path and :url allow the same set of interpolated | ||
| 103 | variables. | ||
| 104 | |||
| 105 | ==Post Processing | ||
| 106 | |||
| 107 | Paperclip supports an extendible selection of post-processors. When you define | ||
| 108 | a set of styles for an attachment, by default it is expected that those | ||
| 109 | "styles" are actually "thumbnails". However, you can do more than just | ||
| 110 | thumbnail images. By defining a subclass of Paperclip::Processor, you can | ||
| 111 | perform any processing you want on the files that are attached. Any file in | ||
| 112 | your Rails app's lib/paperclip_processors directory is automatically loaded by | ||
| 113 | paperclip, allowing you to easily define custom processors. You can specify a | ||
| 114 | processor with the :processors option to has_attached_file: | ||
| 115 | |||
| 116 | has_attached_file :scan, :styles => { :text => { :quality => :better } }, | ||
| 117 | :processors => [:ocr] | ||
| 118 | |||
| 119 | This would load the hypothetical class Paperclip::Ocr, which would have the | ||
| 120 | hash "{ :quality => :better }" passed to it along with the uploaded file. For | ||
| 121 | more information about defining processors, see Paperclip::Processor. | ||
| 122 | |||
| 123 | The default processor is Paperclip::Thumbnail. For backwards compatability | ||
| 124 | reasons, you can pass a single geometry string or an array containing a | ||
| 125 | geometry and a format, which the file will be converted to, like so: | ||
| 126 | |||
| 127 | has_attached_file :avatar, :styles => { :thumb => ["32x32#", :png] } | ||
| 128 | |||
| 129 | This will convert the "thumb" style to a 32x32 square in png format, regardless | ||
| 130 | of what was uploaded. If the format is not specified, it is kept the same (i.e. | ||
| 131 | jpgs will remain jpgs). | ||
| 132 | |||
| 133 | Multiple processors can be specified, and they will be invoked in the order | ||
| 134 | they are defined in the :processors array. Each successive processor will | ||
| 135 | be given the result of the previous processor's execution. All processors will | ||
| 136 | receive the same parameters, which are what you define in the :styles hash. | ||
| 137 | For example, assuming we had this definition: | ||
| 138 | |||
| 139 | has_attached_file :scan, :styles => { :text => { :quality => :better } }, | ||
| 140 | :processors => [:rotator, :ocr] | ||
| 141 | |||
| 142 | then both the :rotator processor and the :ocr processor would receive the | ||
| 143 | options "{ :quality => :better }". This parameter may not mean anything to one | ||
| 144 | or more or the processors, and they are free to ignore it. | ||
| 145 | |||
| 146 | ==Events | ||
| 147 | |||
| 148 | Before and after the Post Processing step, Paperclip calls back to the model | ||
| 149 | with a few callbacks, allowing the model to change or cancel the processing | ||
| 150 | step. The callbacks are "before_post_process" and "after_post_process" (which | ||
| 151 | are called before and after the processing of each attachment), and the | ||
| 152 | attachment-specific "before_<attachment>_post_process" and | ||
| 153 | "after_<attachment>_post_process". The callbacks are intended to be as close to | ||
| 154 | normal ActiveRecord callbacks as possible, so if you return false (specifically | ||
| 155 | - returning nil is not the same) in a before_ filter, the post processing step | ||
| 156 | will halt. Returning false in an after_ filter will not halt anything, but you | ||
| 157 | can access the model and the attachment if necessary. | ||
| 158 | |||
| 159 | NOTE: Post processing will not even *start* if the attachment is not valid | ||
| 160 | according to the validations. Your callbacks (and processors) will only be | ||
| 161 | called with valid attachments. | ||
| 162 | |||
| 163 | ==Contributing | ||
| 164 | |||
| 165 | If you'd like to contribute a feature or bugfix: Thanks! To make sure your | ||
| 166 | fix/feature has a high chance of being included, please read the following | ||
| 167 | guidelines: | ||
| 168 | |||
| 169 | 1. Ask on the mailing list, or post a ticket in Lighthouse. | ||
| 170 | 2. Make sure there are tests! We will not accept any patch that is not tested. | ||
| 171 | It's a rare time when explicit tests aren't needed. If you have questions | ||
| 172 | about writing tests for paperclip, please ask the mailing list. | ||
diff --git a/vendor/plugins/paperclip/Rakefile b/vendor/plugins/paperclip/Rakefile deleted file mode 100644 index 91f1687..0000000 --- a/vendor/plugins/paperclip/Rakefile +++ /dev/null | |||
| @@ -1,77 +0,0 @@ | |||
| 1 | require 'rake' | ||
| 2 | require 'rake/testtask' | ||
| 3 | require 'rake/rdoctask' | ||
| 4 | |||
| 5 | $LOAD_PATH << File.join(File.dirname(__FILE__), 'lib') | ||
| 6 | require 'paperclip' | ||
| 7 | |||
| 8 | desc 'Default: run unit tests.' | ||
| 9 | task :default => [:clean, :test] | ||
| 10 | |||
| 11 | desc 'Test the paperclip plugin.' | ||
| 12 | Rake::TestTask.new(:test) do |t| | ||
| 13 | t.libs << 'lib' << 'profile' | ||
| 14 | t.pattern = 'test/**/*_test.rb' | ||
| 15 | t.verbose = true | ||
| 16 | end | ||
| 17 | |||
| 18 | desc 'Start an IRB session with all necessary files required.' | ||
| 19 | task :shell do |t| | ||
| 20 | chdir File.dirname(__FILE__) | ||
| 21 | exec 'irb -I lib/ -I lib/paperclip -r rubygems -r active_record -r tempfile -r init' | ||
| 22 | end | ||
| 23 | |||
| 24 | desc 'Generate documentation for the paperclip plugin.' | ||
| 25 | Rake::RDocTask.new(:rdoc) do |rdoc| | ||
| 26 | rdoc.rdoc_dir = 'doc' | ||
| 27 | rdoc.title = 'Paperclip' | ||
| 28 | rdoc.options << '--line-numbers' << '--inline-source' | ||
| 29 | rdoc.rdoc_files.include('README*') | ||
| 30 | rdoc.rdoc_files.include('lib/**/*.rb') | ||
| 31 | end | ||
| 32 | |||
| 33 | desc 'Update documentation on website' | ||
| 34 | task :sync_docs => 'rdoc' do | ||
| 35 | `rsync -ave ssh doc/ dev@dev.thoughtbot.com:/home/dev/www/dev.thoughtbot.com/paperclip` | ||
| 36 | end | ||
| 37 | |||
| 38 | desc 'Clean up files.' | ||
| 39 | task :clean do |t| | ||
| 40 | FileUtils.rm_rf "doc" | ||
| 41 | FileUtils.rm_rf "tmp" | ||
| 42 | FileUtils.rm_rf "pkg" | ||
| 43 | FileUtils.rm "test/debug.log" rescue nil | ||
| 44 | FileUtils.rm "test/paperclip.db" rescue nil | ||
| 45 | end | ||
| 46 | |||
| 47 | spec = Gem::Specification.new do |s| | ||
| 48 | s.name = "paperclip" | ||
| 49 | s.version = Paperclip::VERSION | ||
| 50 | s.author = "Jon Yurek" | ||
| 51 | s.email = "jyurek@thoughtbot.com" | ||
| 52 | s.homepage = "http://www.thoughtbot.com/projects/paperclip" | ||
| 53 | s.platform = Gem::Platform::RUBY | ||
| 54 | s.summary = "File attachments as attributes for ActiveRecord" | ||
| 55 | s.files = FileList["README*", | ||
| 56 | "LICENSE", | ||
| 57 | "Rakefile", | ||
| 58 | "init.rb", | ||
| 59 | "{generators,lib,tasks,test,shoulda_macros}/**/*"].to_a | ||
| 60 | s.require_path = "lib" | ||
| 61 | s.test_files = FileList["test/**/test_*.rb"].to_a | ||
| 62 | s.rubyforge_project = "paperclip" | ||
| 63 | s.has_rdoc = true | ||
| 64 | s.extra_rdoc_files = FileList["README*"].to_a | ||
| 65 | s.rdoc_options << '--line-numbers' << '--inline-source' | ||
| 66 | s.requirements << "ImageMagick" | ||
| 67 | s.add_runtime_dependency 'right_aws' | ||
| 68 | s.add_development_dependency 'thoughtbot-shoulda' | ||
| 69 | s.add_development_dependency 'mocha' | ||
| 70 | end | ||
| 71 | |||
| 72 | desc "Generate a gemspec file for GitHub" | ||
| 73 | task :gemspec do | ||
| 74 | File.open("#{spec.name}.gemspec", 'w') do |f| | ||
| 75 | f.write spec.to_ruby | ||
| 76 | end | ||
| 77 | end | ||
diff --git a/vendor/plugins/paperclip/generators/paperclip/USAGE b/vendor/plugins/paperclip/generators/paperclip/USAGE deleted file mode 100644 index 2d611d7..0000000 --- a/vendor/plugins/paperclip/generators/paperclip/USAGE +++ /dev/null | |||
| @@ -1,5 +0,0 @@ | |||
| 1 | Usage: | ||
| 2 | |||
| 3 | script/generate paperclip Class attachment1 (attachment2 ...) | ||
| 4 | |||
| 5 | This will create a migration that will add the proper columns to your class's table. \ No newline at end of file | ||
diff --git a/vendor/plugins/paperclip/generators/paperclip/paperclip_generator.rb b/vendor/plugins/paperclip/generators/paperclip/paperclip_generator.rb deleted file mode 100644 index 77ee5a2..0000000 --- a/vendor/plugins/paperclip/generators/paperclip/paperclip_generator.rb +++ /dev/null | |||
| @@ -1,27 +0,0 @@ | |||
| 1 | class PaperclipGenerator < Rails::Generator::NamedBase | ||
| 2 | attr_accessor :attachments, :migration_name | ||
| 3 | |||
| 4 | def initialize(args, options = {}) | ||
| 5 | super | ||
| 6 | @class_name, @attachments = args[0], args[1..-1] | ||
| 7 | end | ||
| 8 | |||
| 9 | def manifest | ||
| 10 | file_name = generate_file_name | ||
| 11 | @migration_name = file_name.camelize | ||
| 12 | record do |m| | ||
| 13 | m.migration_template "paperclip_migration.rb.erb", | ||
| 14 | File.join('db', 'migrate'), | ||
| 15 | :migration_file_name => file_name | ||
| 16 | end | ||
| 17 | end | ||
| 18 | |||
| 19 | private | ||
| 20 | |||
| 21 | def generate_file_name | ||
| 22 | names = attachments.map{|a| a.underscore } | ||
| 23 | names = names[0..-2] + ["and", names[-1]] if names.length > 1 | ||
| 24 | "add_attachments_#{names.join("_")}_to_#{@class_name.underscore}" | ||
| 25 | end | ||
| 26 | |||
| 27 | end | ||
diff --git a/vendor/plugins/paperclip/generators/paperclip/templates/paperclip_migration.rb.erb b/vendor/plugins/paperclip/generators/paperclip/templates/paperclip_migration.rb.erb deleted file mode 100644 index eebb0e5..0000000 --- a/vendor/plugins/paperclip/generators/paperclip/templates/paperclip_migration.rb.erb +++ /dev/null | |||
| @@ -1,19 +0,0 @@ | |||
| 1 | class <%= migration_name %> < ActiveRecord::Migration | ||
| 2 | def self.up | ||
| 3 | <% attachments.each do |attachment| -%> | ||
| 4 | add_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_file_name, :string | ||
| 5 | add_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_content_type, :string | ||
| 6 | add_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_file_size, :integer | ||
| 7 | add_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_updated_at, :datetime | ||
| 8 | <% end -%> | ||
| 9 | end | ||
| 10 | |||
| 11 | def self.down | ||
| 12 | <% attachments.each do |attachment| -%> | ||
| 13 | remove_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_file_name | ||
| 14 | remove_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_content_type | ||
| 15 | remove_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_file_size | ||
| 16 | remove_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_updated_at | ||
| 17 | <% end -%> | ||
| 18 | end | ||
| 19 | end | ||
diff --git a/vendor/plugins/paperclip/init.rb b/vendor/plugins/paperclip/init.rb deleted file mode 100644 index 5a07dda..0000000 --- a/vendor/plugins/paperclip/init.rb +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | require File.join(File.dirname(__FILE__), "lib", "paperclip") | ||
diff --git a/vendor/plugins/paperclip/lib/paperclip.rb b/vendor/plugins/paperclip/lib/paperclip.rb deleted file mode 100644 index 74c3d79..0000000 --- a/vendor/plugins/paperclip/lib/paperclip.rb +++ /dev/null | |||
| @@ -1,318 +0,0 @@ | |||
| 1 | # Paperclip allows file attachments that are stored in the filesystem. All graphical | ||
| 2 | # transformations are done using the Graphics/ImageMagick command line utilities and | ||
| 3 | # are stored in Tempfiles until the record is saved. Paperclip does not require a | ||
| 4 | # separate model for storing the attachment's information, instead adding a few simple | ||
| 5 | # columns to your table. | ||
| 6 | # | ||
| 7 | # Author:: Jon Yurek | ||
| 8 | # Copyright:: Copyright (c) 2008 thoughtbot, inc. | ||
| 9 | # License:: MIT License (http://www.opensource.org/licenses/mit-license.php) | ||
| 10 | # | ||
| 11 | # Paperclip defines an attachment as any file, though it makes special considerations | ||
| 12 | # for image files. You can declare that a model has an attached file with the | ||
| 13 | # +has_attached_file+ method: | ||
| 14 | # | ||
| 15 | # class User < ActiveRecord::Base | ||
| 16 | # has_attached_file :avatar, :styles => { :thumb => "100x100" } | ||
| 17 | # end | ||
| 18 | # | ||
| 19 | # user = User.new | ||
| 20 | # user.avatar = params[:user][:avatar] | ||
| 21 | # user.avatar.url | ||
| 22 | # # => "/users/avatars/4/original_me.jpg" | ||
| 23 | # user.avatar.url(:thumb) | ||
| 24 | # # => "/users/avatars/4/thumb_me.jpg" | ||
| 25 | # | ||
| 26 | # See the +has_attached_file+ documentation for more details. | ||
| 27 | |||
| 28 | require 'tempfile' | ||
| 29 | require 'paperclip/upfile' | ||
| 30 | require 'paperclip/iostream' | ||
| 31 | require 'paperclip/geometry' | ||
| 32 | require 'paperclip/processor' | ||
| 33 | require 'paperclip/thumbnail' | ||
| 34 | require 'paperclip/storage' | ||
| 35 | require 'paperclip/attachment' | ||
| 36 | if defined? RAILS_ROOT | ||
| 37 | Dir.glob(File.join(File.expand_path(RAILS_ROOT), "lib", "paperclip_processors", "*.rb")).each do |processor| | ||
| 38 | require processor | ||
| 39 | end | ||
| 40 | end | ||
| 41 | |||
| 42 | # The base module that gets included in ActiveRecord::Base. See the | ||
| 43 | # documentation for Paperclip::ClassMethods for more useful information. | ||
| 44 | module Paperclip | ||
| 45 | |||
| 46 | VERSION = "2.2.8" | ||
| 47 | |||
| 48 | class << self | ||
| 49 | # Provides configurability to Paperclip. There are a number of options available, such as: | ||
| 50 | # * whiny_thumbnails: Will raise an error if Paperclip cannot process thumbnails of | ||
| 51 | # an uploaded image. Defaults to true. | ||
| 52 | # * log: Logs progress to the Rails log. Uses ActiveRecord's logger, so honors | ||
| 53 | # log levels, etc. Defaults to true. | ||
| 54 | # * command_path: Defines the path at which to find the command line | ||
| 55 | # programs if they are not visible to Rails the system's search path. Defaults to | ||
| 56 | # nil, which uses the first executable found in the user's search path. | ||
| 57 | # * image_magick_path: Deprecated alias of command_path. | ||
| 58 | def options | ||
| 59 | @options ||= { | ||
| 60 | :whiny_thumbnails => true, | ||
| 61 | :image_magick_path => nil, | ||
| 62 | :command_path => nil, | ||
| 63 | :log => true, | ||
| 64 | :swallow_stderr => true | ||
| 65 | } | ||
| 66 | end | ||
| 67 | |||
| 68 | def path_for_command command #:nodoc: | ||
| 69 | if options[:image_magick_path] | ||
| 70 | warn("[DEPRECATION] :image_magick_path is deprecated and will be removed. Use :command_path instead") | ||
| 71 | end | ||
| 72 | path = [options[:command_path] || options[:image_magick_path], command].compact | ||
| 73 | File.join(*path) | ||
| 74 | end | ||
| 75 | |||
| 76 | def interpolates key, &block | ||
| 77 | Paperclip::Attachment.interpolations[key] = block | ||
| 78 | end | ||
| 79 | |||
| 80 | # The run method takes a command to execute and a string of parameters | ||
| 81 | # that get passed to it. The command is prefixed with the :command_path | ||
| 82 | # option from Paperclip.options. If you have many commands to run and | ||
| 83 | # they are in different paths, the suggested course of action is to | ||
| 84 | # symlink them so they are all in the same directory. | ||
| 85 | # | ||
| 86 | # If the command returns with a result code that is not one of the | ||
| 87 | # expected_outcodes, a PaperclipCommandLineError will be raised. Generally | ||
| 88 | # a code of 0 is expected, but a list of codes may be passed if necessary. | ||
| 89 | def run cmd, params = "", expected_outcodes = 0 | ||
| 90 | command = %Q<#{%Q[#{path_for_command(cmd)} #{params}].gsub(/\s+/, " ")}> | ||
| 91 | command = "#{command} 2>#{bit_bucket}" if Paperclip.options[:swallow_stderr] | ||
| 92 | output = `#{command}` | ||
| 93 | unless [expected_outcodes].flatten.include?($?.exitstatus) | ||
| 94 | raise PaperclipCommandLineError, "Error while running #{cmd}" | ||
| 95 | end | ||
| 96 | output | ||
| 97 | end | ||
| 98 | |||
| 99 | def bit_bucket #:nodoc: | ||
| 100 | File.exists?("/dev/null") ? "/dev/null" : "NUL" | ||
| 101 | end | ||
| 102 | |||
| 103 | def included base #:nodoc: | ||
| 104 | base.extend ClassMethods | ||
| 105 | unless base.respond_to?(:define_callbacks) | ||
| 106 | base.send(:include, Paperclip::CallbackCompatability) | ||
| 107 | end | ||
| 108 | end | ||
| 109 | |||
| 110 | def processor name #:nodoc: | ||
| 111 | name = name.to_s.camelize | ||
| 112 | processor = Paperclip.const_get(name) | ||
| 113 | unless processor.ancestors.include?(Paperclip::Processor) | ||
| 114 | raise PaperclipError.new("Processor #{name} was not found") | ||
| 115 | end | ||
| 116 | processor | ||
| 117 | end | ||
| 118 | end | ||
| 119 | |||
| 120 | class PaperclipError < StandardError #:nodoc: | ||
| 121 | end | ||
| 122 | |||
| 123 | class PaperclipCommandLineError < StandardError #:nodoc: | ||
| 124 | end | ||
| 125 | |||
| 126 | class NotIdentifiedByImageMagickError < PaperclipError #:nodoc: | ||
| 127 | end | ||
| 128 | |||
| 129 | module ClassMethods | ||
| 130 | # +has_attached_file+ gives the class it is called on an attribute that maps to a file. This | ||
| 131 | # is typically a file stored somewhere on the filesystem and has been uploaded by a user. | ||
| 132 | # The attribute returns a Paperclip::Attachment object which handles the management of | ||
| 133 | # that file. The intent is to make the attachment as much like a normal attribute. The | ||
| 134 | # thumbnails will be created when the new file is assigned, but they will *not* be saved | ||
| 135 | # until +save+ is called on the record. Likewise, if the attribute is set to +nil+ is | ||
| 136 | # called on it, the attachment will *not* be deleted until +save+ is called. See the | ||
| 137 | # Paperclip::Attachment documentation for more specifics. There are a number of options | ||
| 138 | # you can set to change the behavior of a Paperclip attachment: | ||
| 139 | # * +url+: The full URL of where the attachment is publically accessible. This can just | ||
| 140 | # as easily point to a directory served directly through Apache as it can to an action | ||
| 141 | # that can control permissions. You can specify the full domain and path, but usually | ||
| 142 | # just an absolute path is sufficient. The leading slash *must* be included manually for | ||
| 143 | # absolute paths. The default value is | ||
| 144 | # "/system/:attachment/:id/:style/:basename.:extension". See | ||
| 145 | # Paperclip::Attachment#interpolate for more information on variable interpolaton. | ||
| 146 | # :url => "/:class/:attachment/:id/:style_:basename.:extension" | ||
| 147 | # :url => "http://some.other.host/stuff/:class/:id_:extension" | ||
| 148 | # * +default_url+: The URL that will be returned if there is no attachment assigned. | ||
| 149 | # This field is interpolated just as the url is. The default value is | ||
| 150 | # "/:attachment/:style/missing.png" | ||
| 151 | # has_attached_file :avatar, :default_url => "/images/default_:style_avatar.png" | ||
| 152 | # User.new.avatar_url(:small) # => "/images/default_small_avatar.png" | ||
| 153 | # * +styles+: A hash of thumbnail styles and their geometries. You can find more about | ||
| 154 | # geometry strings at the ImageMagick website | ||
| 155 | # (http://www.imagemagick.org/script/command-line-options.php#resize). Paperclip | ||
| 156 | # also adds the "#" option (e.g. "50x50#"), which will resize the image to fit maximally | ||
| 157 | # inside the dimensions and then crop the rest off (weighted at the center). The | ||
| 158 | # default value is to generate no thumbnails. | ||
| 159 | # * +default_style+: The thumbnail style that will be used by default URLs. | ||
| 160 | # Defaults to +original+. | ||
| 161 | # has_attached_file :avatar, :styles => { :normal => "100x100#" }, | ||
| 162 | # :default_style => :normal | ||
| 163 | # user.avatar.url # => "/avatars/23/normal_me.png" | ||
| 164 | # * +whiny_thumbnails+: Will raise an error if Paperclip cannot post_process an uploaded file due | ||
| 165 | # to a command line error. This will override the global setting for this attachment. | ||
| 166 | # Defaults to true. | ||
| 167 | # * +convert_options+: When creating thumbnails, use this free-form options | ||
| 168 | # field to pass in various convert command options. Typical options are "-strip" to | ||
| 169 | # remove all Exif data from the image (save space for thumbnails and avatars) or | ||
| 170 | # "-depth 8" to specify the bit depth of the resulting conversion. See ImageMagick | ||
| 171 | # convert documentation for more options: (http://www.imagemagick.org/script/convert.php) | ||
| 172 | # Note that this option takes a hash of options, each of which correspond to the style | ||
| 173 | # of thumbnail being generated. You can also specify :all as a key, which will apply | ||
| 174 | # to all of the thumbnails being generated. If you specify options for the :original, | ||
| 175 | # it would be best if you did not specify destructive options, as the intent of keeping | ||
| 176 | # the original around is to regenerate all the thumbnails when requirements change. | ||
| 177 | # has_attached_file :avatar, :styles => { :large => "300x300", :negative => "100x100" } | ||
| 178 | # :convert_options => { | ||
| 179 | # :all => "-strip", | ||
| 180 | # :negative => "-negate" | ||
| 181 | # } | ||
| 182 | # * +storage+: Chooses the storage backend where the files will be stored. The current | ||
| 183 | # choices are :filesystem and :s3. The default is :filesystem. Make sure you read the | ||
| 184 | # documentation for Paperclip::Storage::Filesystem and Paperclip::Storage::S3 | ||
| 185 | # for backend-specific options. | ||
| 186 | def has_attached_file name, options = {} | ||
| 187 | include InstanceMethods | ||
| 188 | |||
| 189 | write_inheritable_attribute(:attachment_definitions, {}) if attachment_definitions.nil? | ||
| 190 | attachment_definitions[name] = {:validations => {}}.merge(options) | ||
| 191 | |||
| 192 | after_save :save_attached_files | ||
| 193 | before_destroy :destroy_attached_files | ||
| 194 | |||
| 195 | define_callbacks :before_post_process, :after_post_process | ||
| 196 | define_callbacks :"before_#{name}_post_process", :"after_#{name}_post_process" | ||
| 197 | |||
| 198 | define_method name do |*args| | ||
| 199 | a = attachment_for(name) | ||
| 200 | (args.length > 0) ? a.to_s(args.first) : a | ||
| 201 | end | ||
| 202 | |||
| 203 | define_method "#{name}=" do |file| | ||
| 204 | attachment_for(name).assign(file) | ||
| 205 | end | ||
| 206 | |||
| 207 | define_method "#{name}?" do | ||
| 208 | attachment_for(name).file? | ||
| 209 | end | ||
| 210 | |||
| 211 | validates_each(name) do |record, attr, value| | ||
| 212 | attachment = record.attachment_for(name) | ||
| 213 | attachment.send(:flush_errors) unless attachment.valid? | ||
| 214 | end | ||
| 215 | end | ||
| 216 | |||
| 217 | # Places ActiveRecord-style validations on the size of the file assigned. The | ||
| 218 | # possible options are: | ||
| 219 | # * +in+: a Range of bytes (i.e. +1..1.megabyte+), | ||
| 220 | # * +less_than+: equivalent to :in => 0..options[:less_than] | ||
| 221 | # * +greater_than+: equivalent to :in => options[:greater_than]..Infinity | ||
| 222 | # * +message+: error message to display, use :min and :max as replacements | ||
| 223 | def validates_attachment_size name, options = {} | ||
| 224 | min = options[:greater_than] || (options[:in] && options[:in].first) || 0 | ||
| 225 | max = options[:less_than] || (options[:in] && options[:in].last) || (1.0/0) | ||
| 226 | range = (min..max) | ||
| 227 | message = options[:message] || "file size must be between :min and :max bytes." | ||
| 228 | |||
| 229 | attachment_definitions[name][:validations][:size] = lambda do |attachment, instance| | ||
| 230 | if attachment.file? && !range.include?(attachment.size.to_i) | ||
| 231 | message.gsub(/:min/, min.to_s).gsub(/:max/, max.to_s) | ||
| 232 | end | ||
| 233 | end | ||
| 234 | end | ||
| 235 | |||
| 236 | # Adds errors if thumbnail creation fails. The same as specifying :whiny_thumbnails => true. | ||
| 237 | def validates_attachment_thumbnails name, options = {} | ||
| 238 | attachment_definitions[name][:whiny_thumbnails] = true | ||
| 239 | end | ||
| 240 | |||
| 241 | # Places ActiveRecord-style validations on the presence of a file. | ||
| 242 | def validates_attachment_presence name, options = {} | ||
| 243 | message = options[:message] || "must be set." | ||
| 244 | attachment_definitions[name][:validations][:presence] = lambda do |attachment, instance| | ||
| 245 | message unless attachment.file? | ||
| 246 | end | ||
| 247 | end | ||
| 248 | |||
| 249 | # Places ActiveRecord-style validations on the content type of the file | ||
| 250 | # assigned. The possible options are: | ||
| 251 | # * +content_type+: Allowed content types. Can be a single content type | ||
| 252 | # or an array. Each type can be a String or a Regexp. It should be | ||
| 253 | # noted that Internet Explorer upload files with content_types that you | ||
| 254 | # may not expect. For example, JPEG images are given image/pjpeg and | ||
| 255 | # PNGs are image/x-png, so keep that in mind when determining how you | ||
| 256 | # match. Allows all by default. | ||
| 257 | # * +message+: The message to display when the uploaded file has an invalid | ||
| 258 | # content type. | ||
| 259 | # NOTE: If you do not specify an [attachment]_content_type field on your | ||
| 260 | # model, content_type validation will work _ONLY upon assignment_ and | ||
| 261 | # re-validation after the instance has been reloaded will always succeed. | ||
| 262 | def validates_attachment_content_type name, options = {} | ||
| 263 | attachment_definitions[name][:validations][:content_type] = lambda do |attachment, instance| | ||
| 264 | valid_types = [options[:content_type]].flatten | ||
| 265 | |||
| 266 | unless attachment.original_filename.blank? | ||
| 267 | unless valid_types.blank? | ||
| 268 | content_type = attachment.instance_read(:content_type) | ||
| 269 | unless valid_types.any?{|t| content_type.nil? || t === content_type } | ||
| 270 | options[:message] || "is not one of the allowed file types." | ||
| 271 | end | ||
| 272 | end | ||
| 273 | end | ||
| 274 | end | ||
| 275 | end | ||
| 276 | |||
| 277 | # Returns the attachment definitions defined by each call to | ||
| 278 | # has_attached_file. | ||
| 279 | def attachment_definitions | ||
| 280 | read_inheritable_attribute(:attachment_definitions) | ||
| 281 | end | ||
| 282 | end | ||
| 283 | |||
| 284 | module InstanceMethods #:nodoc: | ||
| 285 | def attachment_for name | ||
| 286 | @_paperclip_attachments ||= {} | ||
| 287 | @_paperclip_attachments[name] ||= Attachment.new(name, self, self.class.attachment_definitions[name]) | ||
| 288 | end | ||
| 289 | |||
| 290 | def each_attachment | ||
| 291 | self.class.attachment_definitions.each do |name, definition| | ||
| 292 | yield(name, attachment_for(name)) | ||
| 293 | end | ||
| 294 | end | ||
| 295 | |||
| 296 | def save_attached_files | ||
| 297 | logger.info("[paperclip] Saving attachments.") | ||
| 298 | each_attachment do |name, attachment| | ||
| 299 | attachment.send(:save) | ||
| 300 | end | ||
| 301 | end | ||
| 302 | |||
| 303 | def destroy_attached_files | ||
| 304 | logger.info("[paperclip] Deleting attachments.") | ||
| 305 | each_attachment do |name, attachment| | ||
| 306 | attachment.send(:queue_existing_for_delete) | ||
| 307 | attachment.send(:flush_deletes) | ||
| 308 | end | ||
| 309 | end | ||
| 310 | end | ||
| 311 | |||
| 312 | end | ||
| 313 | |||
| 314 | # Set it all up. | ||
| 315 | if Object.const_defined?("ActiveRecord") | ||
| 316 | ActiveRecord::Base.send(:include, Paperclip) | ||
| 317 | File.send(:include, Paperclip::Upfile) | ||
| 318 | end | ||
diff --git a/vendor/plugins/paperclip/lib/paperclip/attachment.rb b/vendor/plugins/paperclip/lib/paperclip/attachment.rb deleted file mode 100644 index 897c67e..0000000 --- a/vendor/plugins/paperclip/lib/paperclip/attachment.rb +++ /dev/null | |||
| @@ -1,403 +0,0 @@ | |||
| 1 | module Paperclip | ||
| 2 | # The Attachment class manages the files for a given attachment. It saves | ||
| 3 | # when the model saves, deletes when the model is destroyed, and processes | ||
| 4 | # the file upon assignment. | ||
| 5 | class Attachment | ||
| 6 | |||
| 7 | def self.default_options | ||
| 8 | @default_options ||= { | ||
| 9 | :url => "/system/:attachment/:id/:style/:basename.:extension", | ||
| 10 | :path => ":rails_root/public/system/:attachment/:id/:style/:basename.:extension", | ||
| 11 | :styles => {}, | ||
| 12 | :default_url => "/:attachment/:style/missing.png", | ||
| 13 | :default_style => :original, | ||
| 14 | :validations => {}, | ||
| 15 | :storage => :filesystem | ||
| 16 | } | ||
| 17 | end | ||
| 18 | |||
| 19 | attr_reader :name, :instance, :styles, :default_style, :convert_options, :queued_for_write | ||
| 20 | |||
| 21 | # Creates an Attachment object. +name+ is the name of the attachment, | ||
| 22 | # +instance+ is the ActiveRecord object instance it's attached to, and | ||
| 23 | # +options+ is the same as the hash passed to +has_attached_file+. | ||
| 24 | def initialize name, instance, options = {} | ||
| 25 | @name = name | ||
| 26 | @instance = instance | ||
| 27 | |||
| 28 | options = self.class.default_options.merge(options) | ||
| 29 | |||
| 30 | @url = options[:url] | ||
| 31 | @url = @url.call(self) if @url.is_a?(Proc) | ||
| 32 | @path = options[:path] | ||
| 33 | @path = @path.call(self) if @path.is_a?(Proc) | ||
| 34 | @styles = options[:styles] | ||
| 35 | @styles = @styles.call(self) if @styles.is_a?(Proc) | ||
| 36 | @default_url = options[:default_url] | ||
| 37 | @validations = options[:validations] | ||
| 38 | @default_style = options[:default_style] | ||
| 39 | @storage = options[:storage] | ||
| 40 | @whiny = options[:whiny_thumbnails] | ||
| 41 | @convert_options = options[:convert_options] || {} | ||
| 42 | @processors = options[:processors] || [:thumbnail] | ||
| 43 | @options = options | ||
| 44 | @queued_for_delete = [] | ||
| 45 | @queued_for_write = {} | ||
| 46 | @errors = {} | ||
| 47 | @validation_errors = nil | ||
| 48 | @dirty = false | ||
| 49 | |||
| 50 | normalize_style_definition | ||
| 51 | initialize_storage | ||
| 52 | end | ||
| 53 | |||
| 54 | # What gets called when you call instance.attachment = File. It clears | ||
| 55 | # errors, assigns attributes, processes the file, and runs validations. It | ||
| 56 | # also queues up the previous file for deletion, to be flushed away on | ||
| 57 | # #save of its host. In addition to form uploads, you can also assign | ||
| 58 | # another Paperclip attachment: | ||
| 59 | # new_user.avatar = old_user.avatar | ||
| 60 | # If the file that is assigned is not valid, the processing (i.e. | ||
| 61 | # thumbnailing, etc) will NOT be run. | ||
| 62 | def assign uploaded_file | ||
| 63 | %w(file_name).each do |field| | ||
| 64 | unless @instance.class.column_names.include?("#{name}_#{field}") | ||
| 65 | raise PaperclipError.new("#{@instance.class} model does not have required column '#{name}_#{field}'") | ||
| 66 | end | ||
| 67 | end | ||
| 68 | |||
| 69 | if uploaded_file.is_a?(Paperclip::Attachment) | ||
| 70 | uploaded_file = uploaded_file.to_file(:original) | ||
| 71 | close_uploaded_file = uploaded_file.respond_to?(:close) | ||
| 72 | end | ||
| 73 | |||
| 74 | return nil unless valid_assignment?(uploaded_file) | ||
| 75 | |||
| 76 | uploaded_file.binmode if uploaded_file.respond_to? :binmode | ||
| 77 | self.clear | ||
| 78 | |||
| 79 | return nil if uploaded_file.nil? | ||
| 80 | |||
| 81 | @queued_for_write[:original] = uploaded_file.to_tempfile | ||
| 82 | instance_write(:file_name, uploaded_file.original_filename.strip.gsub(/[^\w\d\.\-]+/, '_')) | ||
| 83 | instance_write(:content_type, uploaded_file.content_type.to_s.strip) | ||
| 84 | instance_write(:file_size, uploaded_file.size.to_i) | ||
| 85 | instance_write(:updated_at, Time.now) | ||
| 86 | |||
| 87 | @dirty = true | ||
| 88 | |||
| 89 | post_process if valid? | ||
| 90 | |||
| 91 | # Reset the file size if the original file was reprocessed. | ||
| 92 | instance_write(:file_size, @queued_for_write[:original].size.to_i) | ||
| 93 | ensure | ||
| 94 | uploaded_file.close if close_uploaded_file | ||
| 95 | validate | ||
| 96 | end | ||
| 97 | |||
| 98 | # Returns the public URL of the attachment, with a given style. Note that | ||
| 99 | # this does not necessarily need to point to a file that your web server | ||
| 100 | # can access and can point to an action in your app, if you need fine | ||
| 101 | # grained security. This is not recommended if you don't need the | ||
| 102 | # security, however, for performance reasons. set | ||
| 103 | # include_updated_timestamp to false if you want to stop the attachment | ||
| 104 | # update time appended to the url | ||
| 105 | def url style = default_style, include_updated_timestamp = true | ||
| 106 | url = original_filename.nil? ? interpolate(@default_url, style) : interpolate(@url, style) | ||
| 107 | include_updated_timestamp && updated_at ? [url, updated_at].compact.join(url.include?("?") ? "&" : "?") : url | ||
| 108 | end | ||
| 109 | |||
| 110 | # Returns the path of the attachment as defined by the :path option. If the | ||
| 111 | # file is stored in the filesystem the path refers to the path of the file | ||
| 112 | # on disk. If the file is stored in S3, the path is the "key" part of the | ||
| 113 | # URL, and the :bucket option refers to the S3 bucket. | ||
| 114 | def path style = nil #:nodoc: | ||
| 115 | original_filename.nil? ? nil : interpolate(@path, style) | ||
| 116 | end | ||
| 117 | |||
| 118 | # Alias to +url+ | ||
| 119 | def to_s style = nil | ||
| 120 | url(style) | ||
| 121 | end | ||
| 122 | |||
| 123 | # Returns true if there are no errors on this attachment. | ||
| 124 | def valid? | ||
| 125 | validate | ||
| 126 | errors.empty? | ||
| 127 | end | ||
| 128 | |||
| 129 | # Returns an array containing the errors on this attachment. | ||
| 130 | def errors | ||
| 131 | @errors | ||
| 132 | end | ||
| 133 | |||
| 134 | # Returns true if there are changes that need to be saved. | ||
| 135 | def dirty? | ||
| 136 | @dirty | ||
| 137 | end | ||
| 138 | |||
| 139 | # Saves the file, if there are no errors. If there are, it flushes them to | ||
| 140 | # the instance's errors and returns false, cancelling the save. | ||
| 141 | def save | ||
| 142 | if valid? | ||
| 143 | flush_deletes | ||
| 144 | flush_writes | ||
| 145 | @dirty = false | ||
| 146 | true | ||
| 147 | else | ||
| 148 | flush_errors | ||
| 149 | false | ||
| 150 | end | ||
| 151 | end | ||
| 152 | |||
| 153 | # Clears out the attachment. Has the same effect as previously assigning | ||
| 154 | # nil to the attachment. Does NOT save. If you wish to clear AND save, | ||
| 155 | # use #destroy. | ||
| 156 | def clear | ||
| 157 | queue_existing_for_delete | ||
| 158 | @errors = {} | ||
| 159 | @validation_errors = nil | ||
| 160 | end | ||
| 161 | |||
| 162 | # Destroys the attachment. Has the same effect as previously assigning | ||
| 163 | # nil to the attachment *and saving*. This is permanent. If you wish to | ||
| 164 | # wipe out the existing attachment but not save, use #clear. | ||
| 165 | def destroy | ||
| 166 | clear | ||
| 167 | save | ||
| 168 | end | ||
| 169 | |||
| 170 | # Returns the name of the file as originally assigned, and lives in the | ||
| 171 | # <attachment>_file_name attribute of the model. | ||
| 172 | def original_filename | ||
| 173 | instance_read(:file_name) | ||
| 174 | end | ||
| 175 | |||
| 176 | # Returns the size of the file as originally assigned, and lives in the | ||
| 177 | # <attachment>_file_size attribute of the model. | ||
| 178 | def size | ||
| 179 | instance_read(:file_size) || (@queued_for_write[:original] && @queued_for_write[:original].size) | ||
| 180 | end | ||
| 181 | |||
| 182 | # Returns the content_type of the file as originally assigned, and lives | ||
| 183 | # in the <attachment>_content_type attribute of the model. | ||
| 184 | def content_type | ||
| 185 | instance_read(:content_type) | ||
| 186 | end | ||
| 187 | |||
| 188 | # Returns the last modified time of the file as originally assigned, and | ||
| 189 | # lives in the <attachment>_updated_at attribute of the model. | ||
| 190 | def updated_at | ||
| 191 | time = instance_read(:updated_at) | ||
| 192 | time && time.to_i | ||
| 193 | end | ||
| 194 | |||
| 195 | # A hash of procs that are run during the interpolation of a path or url. | ||
| 196 | # A variable of the format :name will be replaced with the return value of | ||
| 197 | # the proc named ":name". Each lambda takes the attachment and the current | ||
| 198 | # style as arguments. This hash can be added to with your own proc if | ||
| 199 | # necessary. | ||
| 200 | def self.interpolations | ||
| 201 | @interpolations ||= { | ||
| 202 | :rails_root => lambda{|attachment,style| RAILS_ROOT }, | ||
| 203 | :rails_env => lambda{|attachment,style| RAILS_ENV }, | ||
| 204 | :class => lambda do |attachment,style| | ||
| 205 | attachment.instance.class.name.underscore.pluralize | ||
| 206 | end, | ||
| 207 | :basename => lambda do |attachment,style| | ||
| 208 | attachment.original_filename.gsub(/#{File.extname(attachment.original_filename)}$/, "") | ||
| 209 | end, | ||
| 210 | :extension => lambda do |attachment,style| | ||
| 211 | ((style = attachment.styles[style]) && style[:format]) || | ||
| 212 | File.extname(attachment.original_filename).gsub(/^\.+/, "") | ||
| 213 | end, | ||
| 214 | :id => lambda{|attachment,style| attachment.instance.id }, | ||
| 215 | :id_partition => lambda do |attachment, style| | ||
| 216 | ("%09d" % attachment.instance.id).scan(/\d{3}/).join("/") | ||
| 217 | end, | ||
| 218 | :attachment => lambda{|attachment,style| attachment.name.to_s.downcase.pluralize }, | ||
| 219 | :style => lambda{|attachment,style| style || attachment.default_style }, | ||
| 220 | } | ||
| 221 | end | ||
| 222 | |||
| 223 | # This method really shouldn't be called that often. It's expected use is | ||
| 224 | # in the paperclip:refresh rake task and that's it. It will regenerate all | ||
| 225 | # thumbnails forcefully, by reobtaining the original file and going through | ||
| 226 | # the post-process again. | ||
| 227 | def reprocess! | ||
| 228 | new_original = Tempfile.new("paperclip-reprocess") | ||
| 229 | new_original.binmode | ||
| 230 | if old_original = to_file(:original) | ||
| 231 | new_original.write( old_original.read ) | ||
| 232 | new_original.rewind | ||
| 233 | |||
| 234 | @queued_for_write = { :original => new_original } | ||
| 235 | post_process | ||
| 236 | |||
| 237 | old_original.close if old_original.respond_to?(:close) | ||
| 238 | |||
| 239 | save | ||
| 240 | else | ||
| 241 | true | ||
| 242 | end | ||
| 243 | end | ||
| 244 | |||
| 245 | # Returns true if a file has been assigned. | ||
| 246 | def file? | ||
| 247 | !original_filename.blank? | ||
| 248 | end | ||
| 249 | |||
| 250 | # Writes the attachment-specific attribute on the instance. For example, | ||
| 251 | # instance_write(:file_name, "me.jpg") will write "me.jpg" to the instance's | ||
| 252 | # "avatar_file_name" field (assuming the attachment is called avatar). | ||
| 253 | def instance_write(attr, value) | ||
| 254 | setter = :"#{name}_#{attr}=" | ||
| 255 | responds = instance.respond_to?(setter) | ||
| 256 | self.instance_variable_set("@_#{setter.to_s.chop}", value) | ||
| 257 | instance.send(setter, value) if responds || attr.to_s == "file_name" | ||
| 258 | end | ||
| 259 | |||
| 260 | # Reads the attachment-specific attribute on the instance. See instance_write | ||
| 261 | # for more details. | ||
| 262 | def instance_read(attr) | ||
| 263 | getter = :"#{name}_#{attr}" | ||
| 264 | responds = instance.respond_to?(getter) | ||
| 265 | cached = self.instance_variable_get("@_#{getter}") | ||
| 266 | return cached if cached | ||
| 267 | instance.send(getter) if responds || attr.to_s == "file_name" | ||
| 268 | end | ||
| 269 | |||
| 270 | private | ||
| 271 | |||
| 272 | def logger #:nodoc: | ||
| 273 | instance.logger | ||
| 274 | end | ||
| 275 | |||
| 276 | def log message #:nodoc: | ||
| 277 | logger.info("[paperclip] #{message}") if logging? | ||
| 278 | end | ||
| 279 | |||
| 280 | def logging? #:nodoc: | ||
| 281 | Paperclip.options[:log] | ||
| 282 | end | ||
| 283 | |||
| 284 | def valid_assignment? file #:nodoc: | ||
| 285 | file.nil? || (file.respond_to?(:original_filename) && file.respond_to?(:content_type)) | ||
| 286 | end | ||
| 287 | |||
| 288 | def validate #:nodoc: | ||
| 289 | unless @validation_errors | ||
| 290 | @validation_errors = @validations.inject({}) do |errors, validation| | ||
| 291 | name, block = validation | ||
| 292 | errors[name] = block.call(self, instance) if block | ||
| 293 | errors | ||
| 294 | end | ||
| 295 | @validation_errors.reject!{|k,v| v == nil } | ||
| 296 | @errors.merge!(@validation_errors) | ||
| 297 | end | ||
| 298 | @validation_errors | ||
| 299 | end | ||
| 300 | |||
| 301 | def normalize_style_definition #:nodoc: | ||
| 302 | @styles.each do |name, args| | ||
| 303 | unless args.is_a? Hash | ||
| 304 | dimensions, format = *args | ||
| 305 | @styles[name] = { | ||
| 306 | :processors => @processors, | ||
| 307 | :geometry => dimensions, | ||
| 308 | :format => format, | ||
| 309 | :whiny => @whiny, | ||
| 310 | :convert_options => extra_options_for(name) | ||
| 311 | } | ||
| 312 | else | ||
| 313 | @styles[name] = { | ||
| 314 | :processors => @processors, | ||
| 315 | :whiny => @whiny, | ||
| 316 | :convert_options => extra_options_for(name) | ||
| 317 | }.merge(@styles[name]) | ||
| 318 | end | ||
| 319 | end | ||
| 320 | end | ||
| 321 | |||
| 322 | def solidify_style_definitions #:nodoc: | ||
| 323 | @styles.each do |name, args| | ||
| 324 | @styles[name][:geometry] = @styles[name][:geometry].call(instance) if @styles[name][:geometry].respond_to?(:call) | ||
| 325 | @styles[name][:processors] = @styles[name][:processors].call(instance) if @styles[name][:processors].respond_to?(:call) | ||
| 326 | end | ||
| 327 | end | ||
| 328 | |||
| 329 | def initialize_storage #:nodoc: | ||
| 330 | @storage_module = Paperclip::Storage.const_get(@storage.to_s.capitalize) | ||
| 331 | self.extend(@storage_module) | ||
| 332 | end | ||
| 333 | |||
| 334 | def extra_options_for(style) #:nodoc: | ||
| 335 | all_options = convert_options[:all] | ||
| 336 | all_options = all_options.call(instance) if all_options.respond_to?(:call) | ||
| 337 | style_options = convert_options[style] | ||
| 338 | style_options = style_options.call(instance) if style_options.respond_to?(:call) | ||
| 339 | |||
| 340 | [ style_options, all_options ].compact.join(" ") | ||
| 341 | end | ||
| 342 | |||
| 343 | def post_process #:nodoc: | ||
| 344 | return if @queued_for_write[:original].nil? | ||
| 345 | solidify_style_definitions | ||
| 346 | return if fire_events(:before) | ||
| 347 | post_process_styles | ||
| 348 | return if fire_events(:after) | ||
| 349 | end | ||
| 350 | |||
| 351 | def fire_events(which) | ||
| 352 | return true if callback(:"#{which}_post_process") == false | ||
| 353 | return true if callback(:"#{which}_#{name}_post_process") == false | ||
| 354 | end | ||
| 355 | |||
| 356 | def callback which #:nodoc: | ||
| 357 | instance.run_callbacks(which, @queued_for_write){|result, obj| result == false } | ||
| 358 | end | ||
| 359 | |||
| 360 | def post_process_styles | ||
| 361 | @styles.each do |name, args| | ||
| 362 | begin | ||
| 363 | raise RuntimeError.new("Style #{name} has no processors defined.") if args[:processors].blank? | ||
| 364 | @queued_for_write[name] = args[:processors].inject(@queued_for_write[:original]) do |file, processor| | ||
| 365 | Paperclip.processor(processor).make(file, args, self) | ||
| 366 | end | ||
| 367 | rescue PaperclipError => e | ||
| 368 | log("An error was received while processing: #{e.inspect}") | ||
| 369 | (@errors[:processing] ||= []) << e.message if @whiny | ||
| 370 | end | ||
| 371 | end | ||
| 372 | end | ||
| 373 | |||
| 374 | def interpolate pattern, style = default_style #:nodoc: | ||
| 375 | interpolations = self.class.interpolations.sort{|a,b| a.first.to_s <=> b.first.to_s } | ||
| 376 | interpolations.reverse.inject( pattern.dup ) do |result, interpolation| | ||
| 377 | tag, blk = interpolation | ||
| 378 | result.gsub(/:#{tag}/) do |match| | ||
| 379 | blk.call( self, style ) | ||
| 380 | end | ||
| 381 | end | ||
| 382 | end | ||
| 383 | |||
| 384 | def queue_existing_for_delete #:nodoc: | ||
| 385 | return unless file? | ||
| 386 | @queued_for_delete += [:original, *@styles.keys].uniq.map do |style| | ||
| 387 | path(style) if exists?(style) | ||
| 388 | end.compact | ||
| 389 | instance_write(:file_name, nil) | ||
| 390 | instance_write(:content_type, nil) | ||
| 391 | instance_write(:file_size, nil) | ||
| 392 | instance_write(:updated_at, nil) | ||
| 393 | end | ||
| 394 | |||
| 395 | def flush_errors #:nodoc: | ||
| 396 | @errors.each do |error, message| | ||
| 397 | [message].flatten.each {|m| instance.errors.add(name, m) } | ||
| 398 | end | ||
| 399 | end | ||
| 400 | |||
| 401 | end | ||
| 402 | end | ||
| 403 | |||
diff --git a/vendor/plugins/paperclip/lib/paperclip/callback_compatability.rb b/vendor/plugins/paperclip/lib/paperclip/callback_compatability.rb deleted file mode 100644 index 10b08fc..0000000 --- a/vendor/plugins/paperclip/lib/paperclip/callback_compatability.rb +++ /dev/null | |||
| @@ -1,33 +0,0 @@ | |||
| 1 | module Paperclip | ||
| 2 | # This module is intended as a compatability shim for the differences in | ||
| 3 | # callbacks between Rails 2.0 and Rails 2.1. | ||
| 4 | module CallbackCompatability | ||
| 5 | def self.included(base) | ||
| 6 | base.extend(ClassMethods) | ||
| 7 | base.send(:include, InstanceMethods) | ||
| 8 | end | ||
| 9 | |||
| 10 | module ClassMethods | ||
| 11 | # The implementation of this method is taken from the Rails 1.2.6 source, | ||
| 12 | # from rails/activerecord/lib/active_record/callbacks.rb, line 192. | ||
| 13 | def define_callbacks(*args) | ||
| 14 | args.each do |method| | ||
| 15 | self.class_eval <<-"end_eval" | ||
| 16 | def self.#{method}(*callbacks, &block) | ||
| 17 | callbacks << block if block_given? | ||
| 18 | write_inheritable_array(#{method.to_sym.inspect}, callbacks) | ||
| 19 | end | ||
| 20 | end_eval | ||
| 21 | end | ||
| 22 | end | ||
| 23 | end | ||
| 24 | |||
| 25 | module InstanceMethods | ||
| 26 | # The callbacks in < 2.1 don't worry about the extra options or the | ||
| 27 | # block, so just run what we have available. | ||
| 28 | def run_callbacks(meth, opts = nil, &blk) | ||
| 29 | callback(meth) | ||
| 30 | end | ||
| 31 | end | ||
| 32 | end | ||
| 33 | end | ||
diff --git a/vendor/plugins/paperclip/lib/paperclip/geometry.rb b/vendor/plugins/paperclip/lib/paperclip/geometry.rb deleted file mode 100644 index 7fbe038..0000000 --- a/vendor/plugins/paperclip/lib/paperclip/geometry.rb +++ /dev/null | |||
| @@ -1,115 +0,0 @@ | |||
| 1 | module Paperclip | ||
| 2 | |||
| 3 | # Defines the geometry of an image. | ||
| 4 | class Geometry | ||
| 5 | attr_accessor :height, :width, :modifier | ||
| 6 | |||
| 7 | # Gives a Geometry representing the given height and width | ||
| 8 | def initialize width = nil, height = nil, modifier = nil | ||
| 9 | @height = height.to_f | ||
| 10 | @width = width.to_f | ||
| 11 | @modifier = modifier | ||
| 12 | end | ||
| 13 | |||
| 14 | # Uses ImageMagick to determing the dimensions of a file, passed in as either a | ||
| 15 | # File or path. | ||
| 16 | def self.from_file file | ||
| 17 | file = file.path if file.respond_to? "path" | ||
| 18 | geometry = begin | ||
| 19 | Paperclip.run("identify", %Q[-format "%wx%h" "#{file}"[0]]) | ||
| 20 | rescue PaperclipCommandLineError | ||
| 21 | "" | ||
| 22 | end | ||
| 23 | parse(geometry) || | ||
| 24 | raise(NotIdentifiedByImageMagickError.new("#{file} is not recognized by the 'identify' command.")) | ||
| 25 | end | ||
| 26 | |||
| 27 | # Parses a "WxH" formatted string, where W is the width and H is the height. | ||
| 28 | def self.parse string | ||
| 29 | if match = (string && string.match(/\b(\d*)x?(\d*)\b([\>\<\#\@\%^!])?/)) | ||
| 30 | Geometry.new(*match[1,3]) | ||
| 31 | end | ||
| 32 | end | ||
| 33 | |||
| 34 | # True if the dimensions represent a square | ||
| 35 | def square? | ||
| 36 | height == width | ||
| 37 | end | ||
| 38 | |||
| 39 | # True if the dimensions represent a horizontal rectangle | ||
| 40 | def horizontal? | ||
| 41 | height < width | ||
| 42 | end | ||
| 43 | |||
| 44 | # True if the dimensions represent a vertical rectangle | ||
| 45 | def vertical? | ||
| 46 | height > width | ||
| 47 | end | ||
| 48 | |||
| 49 | # The aspect ratio of the dimensions. | ||
| 50 | def aspect | ||
| 51 | width / height | ||
| 52 | end | ||
| 53 | |||
| 54 | # Returns the larger of the two dimensions | ||
| 55 | def larger | ||
| 56 | [height, width].max | ||
| 57 | end | ||
| 58 | |||
| 59 | # Returns the smaller of the two dimensions | ||
| 60 | def smaller | ||
| 61 | [height, width].min | ||
| 62 | end | ||
| 63 | |||
| 64 | # Returns the width and height in a format suitable to be passed to Geometry.parse | ||
| 65 | def to_s | ||
| 66 | s = "" | ||
| 67 | s << width.to_i.to_s if width > 0 | ||
| 68 | s << "x#{height.to_i}" if height > 0 | ||
| 69 | s << modifier.to_s | ||
| 70 | s | ||
| 71 | end | ||
| 72 | |||
| 73 | # Same as to_s | ||
| 74 | def inspect | ||
| 75 | to_s | ||
| 76 | end | ||
| 77 | |||
| 78 | # Returns the scaling and cropping geometries (in string-based ImageMagick format) | ||
| 79 | # neccessary to transform this Geometry into the Geometry given. If crop is true, | ||
| 80 | # then it is assumed the destination Geometry will be the exact final resolution. | ||
| 81 | # In this case, the source Geometry is scaled so that an image containing the | ||
| 82 | # destination Geometry would be completely filled by the source image, and any | ||
| 83 | # overhanging image would be cropped. Useful for square thumbnail images. The cropping | ||
| 84 | # is weighted at the center of the Geometry. | ||
| 85 | def transformation_to dst, crop = false | ||
| 86 | if crop | ||
| 87 | ratio = Geometry.new( dst.width / self.width, dst.height / self.height ) | ||
| 88 | scale_geometry, scale = scaling(dst, ratio) | ||
| 89 | crop_geometry = cropping(dst, ratio, scale) | ||
| 90 | else | ||
| 91 | scale_geometry = dst.to_s | ||
| 92 | end | ||
| 93 | |||
| 94 | [ scale_geometry, crop_geometry ] | ||
| 95 | end | ||
| 96 | |||
| 97 | private | ||
| 98 | |||
| 99 | def scaling dst, ratio | ||
| 100 | if ratio.horizontal? || ratio.square? | ||
| 101 | [ "%dx" % dst.width, ratio.width ] | ||
| 102 | else | ||
| 103 | [ "x%d" % dst.height, ratio.height ] | ||
| 104 | end | ||
| 105 | end | ||
| 106 | |||
| 107 | def cropping dst, ratio, scale | ||
| 108 | if ratio.horizontal? || ratio.square? | ||
| 109 | "%dx%d+%d+%d" % [ dst.width, dst.height, 0, (self.height * scale - dst.height) / 2 ] | ||
| 110 | else | ||
| 111 | "%dx%d+%d+%d" % [ dst.width, dst.height, (self.width * scale - dst.width) / 2, 0 ] | ||
| 112 | end | ||
| 113 | end | ||
| 114 | end | ||
| 115 | end | ||
diff --git a/vendor/plugins/paperclip/lib/paperclip/iostream.rb b/vendor/plugins/paperclip/lib/paperclip/iostream.rb deleted file mode 100644 index 74e2014..0000000 --- a/vendor/plugins/paperclip/lib/paperclip/iostream.rb +++ /dev/null | |||
| @@ -1,58 +0,0 @@ | |||
| 1 | # Provides method that can be included on File-type objects (IO, StringIO, Tempfile, etc) to allow stream copying | ||
| 2 | # and Tempfile conversion. | ||
| 3 | module IOStream | ||
| 4 | |||
| 5 | # Returns a Tempfile containing the contents of the readable object. | ||
| 6 | def to_tempfile | ||
| 7 | tempfile = Tempfile.new("stream") | ||
| 8 | tempfile.binmode | ||
| 9 | self.stream_to(tempfile) | ||
| 10 | end | ||
| 11 | |||
| 12 | # Copies one read-able object from one place to another in blocks, obviating the need to load | ||
| 13 | # the whole thing into memory. Defaults to 8k blocks. If this module is included in both | ||
| 14 | # StringIO and Tempfile, then either can have its data copied anywhere else without typing | ||
| 15 | # worries or memory overhead worries. Returns a File if a String is passed in as the destination | ||
| 16 | # and returns the IO or Tempfile as passed in if one is sent as the destination. | ||
| 17 | def stream_to path_or_file, in_blocks_of = 8192 | ||
| 18 | dstio = case path_or_file | ||
| 19 | when String then File.new(path_or_file, "wb+") | ||
| 20 | when IO then path_or_file | ||
| 21 | when Tempfile then path_or_file | ||
| 22 | end | ||
| 23 | buffer = "" | ||
| 24 | self.rewind | ||
| 25 | while self.read(in_blocks_of, buffer) do | ||
| 26 | dstio.write(buffer) | ||
| 27 | end | ||
| 28 | dstio.rewind | ||
| 29 | dstio | ||
| 30 | end | ||
| 31 | end | ||
| 32 | |||
| 33 | class IO #:nodoc: | ||
| 34 | include IOStream | ||
| 35 | end | ||
| 36 | |||
| 37 | %w( Tempfile StringIO ).each do |klass| | ||
| 38 | if Object.const_defined? klass | ||
| 39 | Object.const_get(klass).class_eval do | ||
| 40 | include IOStream | ||
| 41 | end | ||
| 42 | end | ||
| 43 | end | ||
| 44 | |||
| 45 | # Corrects a bug in Windows when asking for Tempfile size. | ||
| 46 | if defined? Tempfile | ||
| 47 | class Tempfile | ||
| 48 | def size | ||
| 49 | if @tmpfile | ||
| 50 | @tmpfile.fsync | ||
| 51 | @tmpfile.flush | ||
| 52 | @tmpfile.stat.size | ||
| 53 | else | ||
| 54 | 0 | ||
| 55 | end | ||
| 56 | end | ||
| 57 | end | ||
| 58 | end | ||
diff --git a/vendor/plugins/paperclip/lib/paperclip/matchers.rb b/vendor/plugins/paperclip/lib/paperclip/matchers.rb deleted file mode 100644 index ca24b5e..0000000 --- a/vendor/plugins/paperclip/lib/paperclip/matchers.rb +++ /dev/null | |||
| @@ -1,4 +0,0 @@ | |||
| 1 | require 'paperclip/matchers/have_attached_file_matcher' | ||
| 2 | require 'paperclip/matchers/validate_attachment_presence_matcher' | ||
| 3 | require 'paperclip/matchers/validate_attachment_content_type_matcher' | ||
| 4 | require 'paperclip/matchers/validate_attachment_size_matcher' | ||
diff --git a/vendor/plugins/paperclip/lib/paperclip/matchers/have_attached_file_matcher.rb b/vendor/plugins/paperclip/lib/paperclip/matchers/have_attached_file_matcher.rb deleted file mode 100644 index da0dd8b..0000000 --- a/vendor/plugins/paperclip/lib/paperclip/matchers/have_attached_file_matcher.rb +++ /dev/null | |||
| @@ -1,49 +0,0 @@ | |||
| 1 | module Paperclip | ||
| 2 | module Shoulda | ||
| 3 | module Matchers | ||
| 4 | def have_attached_file name | ||
| 5 | HaveAttachedFileMatcher.new(name) | ||
| 6 | end | ||
| 7 | |||
| 8 | class HaveAttachedFileMatcher | ||
| 9 | def initialize attachment_name | ||
| 10 | @attachment_name = attachment_name | ||
| 11 | end | ||
| 12 | |||
| 13 | def matches? subject | ||
| 14 | @subject = subject | ||
| 15 | responds? && has_column? && included? | ||
| 16 | end | ||
| 17 | |||
| 18 | def failure_message | ||
| 19 | "Should have an attachment named #{@attachment_name}" | ||
| 20 | end | ||
| 21 | |||
| 22 | def negative_failure_message | ||
| 23 | "Should not have an attachment named #{@attachment_name}" | ||
| 24 | end | ||
| 25 | |||
| 26 | def description | ||
| 27 | "have an attachment named #{@attachment_name}" | ||
| 28 | end | ||
| 29 | |||
| 30 | protected | ||
| 31 | |||
| 32 | def responds? | ||
| 33 | methods = @subject.instance_methods | ||
| 34 | methods.include?("#{@attachment_name}") && | ||
| 35 | methods.include?("#{@attachment_name}=") && | ||
| 36 | methods.include?("#{@attachment_name}?") | ||
| 37 | end | ||
| 38 | |||
| 39 | def has_column? | ||
| 40 | @subject.column_names.include?("#{@attachment_name}_file_name") | ||
| 41 | end | ||
| 42 | |||
| 43 | def included? | ||
| 44 | @subject.ancestors.include?(Paperclip::InstanceMethods) | ||
| 45 | end | ||
| 46 | end | ||
| 47 | end | ||
| 48 | end | ||
| 49 | end | ||
diff --git a/vendor/plugins/paperclip/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb b/vendor/plugins/paperclip/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb deleted file mode 100644 index b4e97fd..0000000 --- a/vendor/plugins/paperclip/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +++ /dev/null | |||
| @@ -1,66 +0,0 @@ | |||
| 1 | module Paperclip | ||
| 2 | module Shoulda | ||
| 3 | module Matchers | ||
| 4 | def validate_attachment_content_type name | ||
| 5 | ValidateAttachmentContentTypeMatcher.new(name) | ||
| 6 | end | ||
| 7 | |||
| 8 | class ValidateAttachmentContentTypeMatcher | ||
| 9 | def initialize attachment_name | ||
| 10 | @attachment_name = attachment_name | ||
| 11 | end | ||
| 12 | |||
| 13 | def allowing *types | ||
| 14 | @allowed_types = types.flatten | ||
| 15 | self | ||
| 16 | end | ||
| 17 | |||
| 18 | def rejecting *types | ||
| 19 | @rejected_types = types.flatten | ||
| 20 | self | ||
| 21 | end | ||
| 22 | |||
| 23 | def matches? subject | ||
| 24 | @subject = subject | ||
| 25 | @allowed_types && @rejected_types && | ||
| 26 | allowed_types_allowed? && rejected_types_rejected? | ||
| 27 | end | ||
| 28 | |||
| 29 | def failure_message | ||
| 30 | "Content types #{@allowed_types.join(", ")} should be accepted" + | ||
| 31 | " and #{@rejected_types.join(", ")} rejected by #{@attachment_name}" | ||
| 32 | end | ||
| 33 | |||
| 34 | def negative_failure_message | ||
| 35 | "Content types #{@allowed_types.join(", ")} should be rejected" + | ||
| 36 | " and #{@rejected_types.join(", ")} accepted by #{@attachment_name}" | ||
| 37 | end | ||
| 38 | |||
| 39 | def description | ||
| 40 | "validate the content types allowed on attachment #{@attachment_name}" | ||
| 41 | end | ||
| 42 | |||
| 43 | protected | ||
| 44 | |||
| 45 | def allow_types?(types) | ||
| 46 | types.all? do |type| | ||
| 47 | file = StringIO.new(".") | ||
| 48 | file.content_type = type | ||
| 49 | attachment = @subject.new.attachment_for(@attachment_name) | ||
| 50 | attachment.assign(file) | ||
| 51 | attachment.errors[:content_type].nil? | ||
| 52 | end | ||
| 53 | end | ||
| 54 | |||
| 55 | def allowed_types_allowed? | ||
| 56 | allow_types?(@allowed_types) | ||
| 57 | end | ||
| 58 | |||
| 59 | def rejected_types_rejected? | ||
| 60 | not allow_types?(@rejected_types) | ||
| 61 | end | ||
| 62 | end | ||
| 63 | end | ||
| 64 | end | ||
| 65 | end | ||
| 66 | |||
diff --git a/vendor/plugins/paperclip/lib/paperclip/matchers/validate_attachment_presence_matcher.rb b/vendor/plugins/paperclip/lib/paperclip/matchers/validate_attachment_presence_matcher.rb deleted file mode 100644 index 61dc0ea..0000000 --- a/vendor/plugins/paperclip/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +++ /dev/null | |||
| @@ -1,48 +0,0 @@ | |||
| 1 | module Paperclip | ||
| 2 | module Shoulda | ||
| 3 | module Matchers | ||
| 4 | def validate_attachment_presence name | ||
| 5 | ValidateAttachmentPresenceMatcher.new(name) | ||
| 6 | end | ||
| 7 | |||
| 8 | class ValidateAttachmentPresenceMatcher | ||
| 9 | def initialize attachment_name | ||
| 10 | @attachment_name = attachment_name | ||
| 11 | end | ||
| 12 | |||
| 13 | def matches? subject | ||
| 14 | @subject = subject | ||
| 15 | error_when_not_valid? && no_error_when_valid? | ||
| 16 | end | ||
| 17 | |||
| 18 | def failure_message | ||
| 19 | "Attachment #{@attachment_name} should be required" | ||
| 20 | end | ||
| 21 | |||
| 22 | def negative_failure_message | ||
| 23 | "Attachment #{@attachment_name} should not be required" | ||
| 24 | end | ||
| 25 | |||
| 26 | def description | ||
| 27 | "require presence of attachment #{@attachment_name}" | ||
| 28 | end | ||
| 29 | |||
| 30 | protected | ||
| 31 | |||
| 32 | def error_when_not_valid? | ||
| 33 | @attachment = @subject.new.send(@attachment_name) | ||
| 34 | @attachment.assign(nil) | ||
| 35 | not @attachment.errors[:presence].nil? | ||
| 36 | end | ||
| 37 | |||
| 38 | def no_error_when_valid? | ||
| 39 | @file = StringIO.new(".") | ||
| 40 | @attachment = @subject.new.send(@attachment_name) | ||
| 41 | @attachment.assign(@file) | ||
| 42 | @attachment.errors[:presence].nil? | ||
| 43 | end | ||
| 44 | end | ||
| 45 | end | ||
| 46 | end | ||
| 47 | end | ||
| 48 | |||
diff --git a/vendor/plugins/paperclip/lib/paperclip/matchers/validate_attachment_size_matcher.rb b/vendor/plugins/paperclip/lib/paperclip/matchers/validate_attachment_size_matcher.rb deleted file mode 100644 index f84c479..0000000 --- a/vendor/plugins/paperclip/lib/paperclip/matchers/validate_attachment_size_matcher.rb +++ /dev/null | |||
| @@ -1,83 +0,0 @@ | |||
| 1 | module Paperclip | ||
| 2 | module Shoulda | ||
| 3 | module Matchers | ||
| 4 | def validate_attachment_size name | ||
| 5 | ValidateAttachmentSizeMatcher.new(name) | ||
| 6 | end | ||
| 7 | |||
| 8 | class ValidateAttachmentSizeMatcher | ||
| 9 | def initialize attachment_name | ||
| 10 | @attachment_name = attachment_name | ||
| 11 | @low, @high = 0, (1.0/0) | ||
| 12 | end | ||
| 13 | |||
| 14 | def less_than size | ||
| 15 | @high = size | ||
| 16 | self | ||
| 17 | end | ||
| 18 | |||
| 19 | def greater_than size | ||
| 20 | @low = size | ||
| 21 | self | ||
| 22 | end | ||
| 23 | |||
| 24 | def in range | ||
| 25 | @low, @high = range.first, range.last | ||
| 26 | self | ||
| 27 | end | ||
| 28 | |||
| 29 | def matches? subject | ||
| 30 | @subject = subject | ||
| 31 | lower_than_low? && higher_than_low? && lower_than_high? && higher_than_high? | ||
| 32 | end | ||
| 33 | |||
| 34 | def failure_message | ||
| 35 | "Attachment #{@attachment_name} must be between #{@low} and #{@high} bytes" | ||
| 36 | end | ||
| 37 | |||
| 38 | def negative_failure_message | ||
| 39 | "Attachment #{@attachment_name} cannot be between #{@low} and #{@high} bytes" | ||
| 40 | end | ||
| 41 | |||
| 42 | def description | ||
| 43 | "validate the size of attachment #{@attachment_name}" | ||
| 44 | end | ||
| 45 | |||
| 46 | protected | ||
| 47 | |||
| 48 | def override_method object, method, &replacement | ||
| 49 | (class << object; self; end).class_eval do | ||
| 50 | define_method(method, &replacement) | ||
| 51 | end | ||
| 52 | end | ||
| 53 | |||
| 54 | def passes_validation_with_size(new_size) | ||
| 55 | file = StringIO.new(".") | ||
| 56 | override_method(file, :size){ new_size } | ||
| 57 | attachment = @subject.new.attachment_for(@attachment_name) | ||
| 58 | attachment.assign(file) | ||
| 59 | attachment.errors[:size].nil? | ||
| 60 | end | ||
| 61 | |||
| 62 | def lower_than_low? | ||
| 63 | not passes_validation_with_size(@low - 1) | ||
| 64 | end | ||
| 65 | |||
| 66 | def higher_than_low? | ||
| 67 | passes_validation_with_size(@low + 1) | ||
| 68 | end | ||
| 69 | |||
| 70 | def lower_than_high? | ||
| 71 | return true if @high == (1.0/0) | ||
| 72 | passes_validation_with_size(@high - 1) | ||
| 73 | end | ||
| 74 | |||
| 75 | def higher_than_high? | ||
| 76 | return true if @high == (1.0/0) | ||
| 77 | not passes_validation_with_size(@high + 1) | ||
| 78 | end | ||
| 79 | end | ||
| 80 | end | ||
| 81 | end | ||
| 82 | end | ||
| 83 | |||
diff --git a/vendor/plugins/paperclip/lib/paperclip/processor.rb b/vendor/plugins/paperclip/lib/paperclip/processor.rb deleted file mode 100644 index 9082bfd..0000000 --- a/vendor/plugins/paperclip/lib/paperclip/processor.rb +++ /dev/null | |||
| @@ -1,48 +0,0 @@ | |||
| 1 | module Paperclip | ||
| 2 | # Paperclip processors allow you to modify attached files when they are | ||
| 3 | # attached in any way you are able. Paperclip itself uses command-line | ||
| 4 | # programs for its included Thumbnail processor, but custom processors | ||
| 5 | # are not required to follow suit. | ||
| 6 | # | ||
| 7 | # Processors are required to be defined inside the Paperclip module and | ||
| 8 | # are also required to be a subclass of Paperclip::Processor. There are | ||
| 9 | # only two methods you must implement to properly be a subclass: | ||
| 10 | # #initialize and #make. Initialize's arguments are the file that will | ||
| 11 | # be operated on (which is an instance of File), and a hash of options | ||
| 12 | # that were defined in has_attached_file's style hash. | ||
| 13 | # | ||
| 14 | # All #make needs to do is return an instance of File (Tempfile is | ||
| 15 | # acceptable) which contains the results of the processing. | ||
| 16 | # | ||
| 17 | # See Paperclip.run for more information about using command-line | ||
| 18 | # utilities from within Processors. | ||
| 19 | class Processor | ||
| 20 | attr_accessor :file, :options, :attachment | ||
| 21 | |||
| 22 | def initialize file, options = {}, attachment = nil | ||
| 23 | @file = file | ||
| 24 | @options = options | ||
| 25 | @attachment = attachment | ||
| 26 | end | ||
| 27 | |||
| 28 | def make | ||
| 29 | end | ||
| 30 | |||
| 31 | def self.make file, options = {}, attachment = nil | ||
| 32 | new(file, options, attachment).make | ||
| 33 | end | ||
| 34 | end | ||
| 35 | |||
| 36 | # Due to how ImageMagick handles its image format conversion and how Tempfile | ||
| 37 | # handles its naming scheme, it is necessary to override how Tempfile makes | ||
| 38 | # its names so as to allow for file extensions. Idea taken from the comments | ||
| 39 | # on this blog post: | ||
| 40 | # http://marsorange.com/archives/of-mogrify-ruby-tempfile-dynamic-class-definitions | ||
| 41 | class Tempfile < ::Tempfile | ||
| 42 | # Replaces Tempfile's +make_tmpname+ with one that honors file extensions. | ||
| 43 | def make_tmpname(basename, n) | ||
| 44 | extension = File.extname(basename) | ||
| 45 | sprintf("%s,%d,%d%s", File.basename(basename, extension), $$, n, extension) | ||
| 46 | end | ||
| 47 | end | ||
| 48 | end | ||
diff --git a/vendor/plugins/paperclip/lib/paperclip/storage.rb b/vendor/plugins/paperclip/lib/paperclip/storage.rb deleted file mode 100644 index 58913ad..0000000 --- a/vendor/plugins/paperclip/lib/paperclip/storage.rb +++ /dev/null | |||
| @@ -1,236 +0,0 @@ | |||
| 1 | module Paperclip | ||
| 2 | module Storage | ||
| 3 | |||
| 4 | # The default place to store attachments is in the filesystem. Files on the local | ||
| 5 | # filesystem can be very easily served by Apache without requiring a hit to your app. | ||
| 6 | # They also can be processed more easily after they've been saved, as they're just | ||
| 7 | # normal files. There is one Filesystem-specific option for has_attached_file. | ||
| 8 | # * +path+: The location of the repository of attachments on disk. This can (and, in | ||
| 9 | # almost all cases, should) be coordinated with the value of the +url+ option to | ||
| 10 | # allow files to be saved into a place where Apache can serve them without | ||
| 11 | # hitting your app. Defaults to | ||
| 12 | # ":rails_root/public/:attachment/:id/:style/:basename.:extension" | ||
| 13 | # By default this places the files in the app's public directory which can be served | ||
| 14 | # directly. If you are using capistrano for deployment, a good idea would be to | ||
| 15 | # make a symlink to the capistrano-created system directory from inside your app's | ||
| 16 | # public directory. | ||
| 17 | # See Paperclip::Attachment#interpolate for more information on variable interpolaton. | ||
| 18 | # :path => "/var/app/attachments/:class/:id/:style/:basename.:extension" | ||
| 19 | module Filesystem | ||
| 20 | def self.extended base | ||
| 21 | end | ||
| 22 | |||
| 23 | def exists?(style = default_style) | ||
| 24 | if original_filename | ||
| 25 | File.exist?(path(style)) | ||
| 26 | else | ||
| 27 | false | ||
| 28 | end | ||
| 29 | end | ||
| 30 | |||
| 31 | # Returns representation of the data of the file assigned to the given | ||
| 32 | # style, in the format most representative of the current storage. | ||
| 33 | def to_file style = default_style | ||
| 34 | @queued_for_write[style] || (File.new(path(style), 'rb') if exists?(style)) | ||
| 35 | end | ||
| 36 | alias_method :to_io, :to_file | ||
| 37 | |||
| 38 | def flush_writes #:nodoc: | ||
| 39 | @queued_for_write.each do |style, file| | ||
| 40 | file.close | ||
| 41 | FileUtils.mkdir_p(File.dirname(path(style))) | ||
| 42 | logger.info("[paperclip] saving #{path(style)}") | ||
| 43 | FileUtils.mv(file.path, path(style)) | ||
| 44 | FileUtils.chmod(0644, path(style)) | ||
| 45 | end | ||
| 46 | @queued_for_write = {} | ||
| 47 | end | ||
| 48 | |||
| 49 | def flush_deletes #:nodoc: | ||
| 50 | @queued_for_delete.each do |path| | ||
| 51 | begin | ||
| 52 | logger.info("[paperclip] deleting #{path}") | ||
| 53 | FileUtils.rm(path) if File.exist?(path) | ||
| 54 | rescue Errno::ENOENT => e | ||
| 55 | # ignore file-not-found, let everything else pass | ||
| 56 | end | ||
| 57 | begin | ||
| 58 | while(true) | ||
| 59 | path = File.dirname(path) | ||
| 60 | FileUtils.rmdir(path) | ||
| 61 | end | ||
| 62 | rescue Errno::EEXIST, Errno::ENOTEMPTY, Errno::ENOENT, Errno::EINVAL, Errno::ENOTDIR | ||
| 63 | # Stop trying to remove parent directories | ||
| 64 | rescue SystemCallError => e | ||
| 65 | logger.info("[paperclip] There was an unexpected error while deleting directories: #{e.class}") | ||
| 66 | # Ignore it | ||
| 67 | end | ||
| 68 | end | ||
| 69 | @queued_for_delete = [] | ||
| 70 | end | ||
| 71 | end | ||
| 72 | |||
| 73 | # Amazon's S3 file hosting service is a scalable, easy place to store files for | ||
| 74 | # distribution. You can find out more about it at http://aws.amazon.com/s3 | ||
| 75 | # There are a few S3-specific options for has_attached_file: | ||
| 76 | # * +s3_credentials+: Takes a path, a File, or a Hash. The path (or File) must point | ||
| 77 | # to a YAML file containing the +access_key_id+ and +secret_access_key+ that Amazon | ||
| 78 | # gives you. You can 'environment-space' this just like you do to your | ||
| 79 | # database.yml file, so different environments can use different accounts: | ||
| 80 | # development: | ||
| 81 | # access_key_id: 123... | ||
| 82 | # secret_access_key: 123... | ||
| 83 | # test: | ||
| 84 | # access_key_id: abc... | ||
| 85 | # secret_access_key: abc... | ||
| 86 | # production: | ||
| 87 | # access_key_id: 456... | ||
| 88 | # secret_access_key: 456... | ||
| 89 | # This is not required, however, and the file may simply look like this: | ||
| 90 | # access_key_id: 456... | ||
| 91 | # secret_access_key: 456... | ||
| 92 | # In which case, those access keys will be used in all environments. You can also | ||
| 93 | # put your bucket name in this file, instead of adding it to the code directly. | ||
| 94 | # This is useful when you want the same account but a different bucket for | ||
| 95 | # development versus production. | ||
| 96 | # * +s3_permissions+: This is a String that should be one of the "canned" access | ||
| 97 | # policies that S3 provides (more information can be found here: | ||
| 98 | # http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAccessPolicy.html#RESTCannedAccessPolicies) | ||
| 99 | # The default for Paperclip is "public-read". | ||
| 100 | # * +s3_protocol+: The protocol for the URLs generated to your S3 assets. Can be either | ||
| 101 | # 'http' or 'https'. Defaults to 'http' when your :s3_permissions are 'public-read' (the | ||
| 102 | # default), and 'https' when your :s3_permissions are anything else. | ||
| 103 | # * +s3_headers+: A hash of headers such as {'Expires' => 1.year.from_now.httpdate} | ||
| 104 | # * +bucket+: This is the name of the S3 bucket that will store your files. Remember | ||
| 105 | # that the bucket must be unique across all of Amazon S3. If the bucket does not exist | ||
| 106 | # Paperclip will attempt to create it. The bucket name will not be interpolated. | ||
| 107 | # You can define the bucket as a Proc if you want to determine it's name at runtime. | ||
| 108 | # Paperclip will call that Proc with attachment as the only argument. | ||
| 109 | # * +s3_host_alias+: The fully-qualified domain name (FQDN) that is the alias to the | ||
| 110 | # S3 domain of your bucket. Used with the :s3_alias_url url interpolation. See the | ||
| 111 | # link in the +url+ entry for more information about S3 domains and buckets. | ||
| 112 | # * +url+: There are three options for the S3 url. You can choose to have the bucket's name | ||
| 113 | # placed domain-style (bucket.s3.amazonaws.com) or path-style (s3.amazonaws.com/bucket). | ||
| 114 | # Lastly, you can specify a CNAME (which requires the CNAME to be specified as | ||
| 115 | # :s3_alias_url. You can read more about CNAMEs and S3 at | ||
| 116 | # http://docs.amazonwebservices.com/AmazonS3/latest/index.html?VirtualHosting.html | ||
| 117 | # Normally, this won't matter in the slightest and you can leave the default (which is | ||
| 118 | # path-style, or :s3_path_url). But in some cases paths don't work and you need to use | ||
| 119 | # the domain-style (:s3_domain_url). Anything else here will be treated like path-style. | ||
| 120 | # NOTE: If you use a CNAME for use with CloudFront, you can NOT specify https as your | ||
| 121 | # :s3_protocol; This is *not supported* by S3/CloudFront. Finally, when using the host | ||
| 122 | # alias, the :bucket parameter is ignored, as the hostname is used as the bucket name | ||
| 123 | # by S3. | ||
| 124 | # * +path+: This is the key under the bucket in which the file will be stored. The | ||
| 125 | # URL will be constructed from the bucket and the path. This is what you will want | ||
| 126 | # to interpolate. Keys should be unique, like filenames, and despite the fact that | ||
| 127 | # S3 (strictly speaking) does not support directories, you can still use a / to | ||
| 128 | # separate parts of your file name. | ||
| 129 | module S3 | ||
| 130 | def self.extended base | ||
| 131 | require 'right_aws' | ||
| 132 | base.instance_eval do | ||
| 133 | @s3_credentials = parse_credentials(@options[:s3_credentials]) | ||
| 134 | @bucket = @options[:bucket] || @s3_credentials[:bucket] | ||
| 135 | @bucket = @bucket.call(self) if @bucket.is_a?(Proc) | ||
| 136 | @s3_options = @options[:s3_options] || {} | ||
| 137 | @s3_permissions = @options[:s3_permissions] || 'public-read' | ||
| 138 | @s3_protocol = @options[:s3_protocol] || (@s3_permissions == 'public-read' ? 'http' : 'https') | ||
| 139 | @s3_headers = @options[:s3_headers] || {} | ||
| 140 | @s3_host_alias = @options[:s3_host_alias] | ||
| 141 | @url = ":s3_path_url" unless @url.to_s.match(/^:s3.*url$/) | ||
| 142 | end | ||
| 143 | base.class.interpolations[:s3_alias_url] = lambda do |attachment, style| | ||
| 144 | "#{attachment.s3_protocol}://#{attachment.s3_host_alias}/#{attachment.path(style).gsub(%r{^/}, "")}" | ||
| 145 | end | ||
| 146 | base.class.interpolations[:s3_path_url] = lambda do |attachment, style| | ||
| 147 | "#{attachment.s3_protocol}://s3.amazonaws.com/#{attachment.bucket_name}/#{attachment.path(style).gsub(%r{^/}, "")}" | ||
| 148 | end | ||
| 149 | base.class.interpolations[:s3_domain_url] = lambda do |attachment, style| | ||
| 150 | "#{attachment.s3_protocol}://#{attachment.bucket_name}.s3.amazonaws.com/#{attachment.path(style).gsub(%r{^/}, "")}" | ||
| 151 | end | ||
| 152 | end | ||
| 153 | |||
| 154 | def s3 | ||
| 155 | @s3 ||= RightAws::S3.new(@s3_credentials[:access_key_id], | ||
| 156 | @s3_credentials[:secret_access_key], | ||
| 157 | @s3_options) | ||
| 158 | end | ||
| 159 | |||
| 160 | def s3_bucket | ||
| 161 | @s3_bucket ||= s3.bucket(@bucket, true, @s3_permissions) | ||
| 162 | end | ||
| 163 | |||
| 164 | def bucket_name | ||
| 165 | @bucket | ||
| 166 | end | ||
| 167 | |||
| 168 | def s3_host_alias | ||
| 169 | @s3_host_alias | ||
| 170 | end | ||
| 171 | |||
| 172 | def parse_credentials creds | ||
| 173 | creds = find_credentials(creds).stringify_keys | ||
| 174 | (creds[ENV['RAILS_ENV']] || creds).symbolize_keys | ||
| 175 | end | ||
| 176 | |||
| 177 | def exists?(style = default_style) | ||
| 178 | s3_bucket.key(path(style)) ? true : false | ||
| 179 | end | ||
| 180 | |||
| 181 | def s3_protocol | ||
| 182 | @s3_protocol | ||
| 183 | end | ||
| 184 | |||
| 185 | # Returns representation of the data of the file assigned to the given | ||
| 186 | # style, in the format most representative of the current storage. | ||
| 187 | def to_file style = default_style | ||
| 188 | @queued_for_write[style] || s3_bucket.key(path(style)) | ||
| 189 | end | ||
| 190 | alias_method :to_io, :to_file | ||
| 191 | |||
| 192 | def flush_writes #:nodoc: | ||
| 193 | @queued_for_write.each do |style, file| | ||
| 194 | begin | ||
| 195 | logger.info("[paperclip] saving #{path(style)}") | ||
| 196 | key = s3_bucket.key(path(style)) | ||
| 197 | key.data = file | ||
| 198 | key.put(nil, @s3_permissions, {'Content-type' => instance_read(:content_type)}.merge(@s3_headers)) | ||
| 199 | rescue RightAws::AwsError => e | ||
| 200 | raise | ||
| 201 | end | ||
| 202 | end | ||
| 203 | @queued_for_write = {} | ||
| 204 | end | ||
| 205 | |||
| 206 | def flush_deletes #:nodoc: | ||
| 207 | @queued_for_delete.each do |path| | ||
| 208 | begin | ||
| 209 | logger.info("[paperclip] deleting #{path}") | ||
| 210 | if file = s3_bucket.key(path) | ||
| 211 | file.delete | ||
| 212 | end | ||
| 213 | rescue RightAws::AwsError | ||
| 214 | # Ignore this. | ||
| 215 | end | ||
| 216 | end | ||
| 217 | @queued_for_delete = [] | ||
| 218 | end | ||
| 219 | |||
| 220 | def find_credentials creds | ||
| 221 | case creds | ||
| 222 | when File | ||
| 223 | YAML.load_file(creds.path) | ||
| 224 | when String | ||
| 225 | YAML.load_file(creds) | ||
| 226 | when Hash | ||
| 227 | creds | ||
| 228 | else | ||
| 229 | raise ArgumentError, "Credentials are not a path, file, or hash." | ||
| 230 | end | ||
| 231 | end | ||
| 232 | private :find_credentials | ||
| 233 | |||
| 234 | end | ||
| 235 | end | ||
| 236 | end | ||
diff --git a/vendor/plugins/paperclip/lib/paperclip/thumbnail.rb b/vendor/plugins/paperclip/lib/paperclip/thumbnail.rb deleted file mode 100644 index 2178a9c..0000000 --- a/vendor/plugins/paperclip/lib/paperclip/thumbnail.rb +++ /dev/null | |||
| @@ -1,70 +0,0 @@ | |||
| 1 | module Paperclip | ||
| 2 | # Handles thumbnailing images that are uploaded. | ||
| 3 | class Thumbnail < Processor | ||
| 4 | |||
| 5 | attr_accessor :current_geometry, :target_geometry, :format, :whiny, :convert_options | ||
| 6 | |||
| 7 | # Creates a Thumbnail object set to work on the +file+ given. It | ||
| 8 | # will attempt to transform the image into one defined by +target_geometry+ | ||
| 9 | # which is a "WxH"-style string. +format+ will be inferred from the +file+ | ||
| 10 | # unless specified. Thumbnail creation will raise no errors unless | ||
| 11 | # +whiny+ is true (which it is, by default. If +convert_options+ is | ||
| 12 | # set, the options will be appended to the convert command upon image conversion | ||
| 13 | def initialize file, options = {}, attachment = nil | ||
| 14 | super | ||
| 15 | geometry = options[:geometry] | ||
| 16 | @file = file | ||
| 17 | @crop = geometry[-1,1] == '#' | ||
| 18 | @target_geometry = Geometry.parse geometry | ||
| 19 | @current_geometry = Geometry.from_file @file | ||
| 20 | @convert_options = options[:convert_options] | ||
| 21 | @whiny = options[:whiny].nil? ? true : options[:whiny] | ||
| 22 | @format = options[:format] | ||
| 23 | |||
| 24 | @current_format = File.extname(@file.path) | ||
| 25 | @basename = File.basename(@file.path, @current_format) | ||
| 26 | end | ||
| 27 | |||
| 28 | # Returns true if the +target_geometry+ is meant to crop. | ||
| 29 | def crop? | ||
| 30 | @crop | ||
| 31 | end | ||
| 32 | |||
| 33 | # Returns true if the image is meant to make use of additional convert options. | ||
| 34 | def convert_options? | ||
| 35 | not @convert_options.blank? | ||
| 36 | end | ||
| 37 | |||
| 38 | # Performs the conversion of the +file+ into a thumbnail. Returns the Tempfile | ||
| 39 | # that contains the new image. | ||
| 40 | def make | ||
| 41 | src = @file | ||
| 42 | dst = Tempfile.new([@basename, @format].compact.join(".")) | ||
| 43 | dst.binmode | ||
| 44 | |||
| 45 | command = <<-end_command | ||
| 46 | "#{ File.expand_path(src.path) }[0]" | ||
| 47 | #{ transformation_command } | ||
| 48 | "#{ File.expand_path(dst.path) }" | ||
| 49 | end_command | ||
| 50 | |||
| 51 | begin | ||
| 52 | success = Paperclip.run("convert", command.gsub(/\s+/, " ")) | ||
| 53 | rescue PaperclipCommandLineError | ||
| 54 | raise PaperclipError, "There was an error processing the thumbnail for #{@basename}" if @whiny | ||
| 55 | end | ||
| 56 | |||
| 57 | dst | ||
| 58 | end | ||
| 59 | |||
| 60 | # Returns the command ImageMagick's +convert+ needs to transform the image | ||
| 61 | # into the thumbnail. | ||
| 62 | def transformation_command | ||
| 63 | scale, crop = @current_geometry.transformation_to(@target_geometry, crop?) | ||
| 64 | trans = "-resize \"#{scale}\"" | ||
| 65 | trans << " -crop \"#{crop}\" +repage" if crop | ||
| 66 | trans << " #{convert_options}" if convert_options? | ||
| 67 | trans | ||
| 68 | end | ||
| 69 | end | ||
| 70 | end | ||
diff --git a/vendor/plugins/paperclip/lib/paperclip/upfile.rb b/vendor/plugins/paperclip/lib/paperclip/upfile.rb deleted file mode 100644 index f0c8a44..0000000 --- a/vendor/plugins/paperclip/lib/paperclip/upfile.rb +++ /dev/null | |||
| @@ -1,48 +0,0 @@ | |||
| 1 | module Paperclip | ||
| 2 | # The Upfile module is a convenience module for adding uploaded-file-type methods | ||
| 3 | # to the +File+ class. Useful for testing. | ||
| 4 | # user.avatar = File.new("test/test_avatar.jpg") | ||
| 5 | module Upfile | ||
| 6 | |||
| 7 | # Infer the MIME-type of the file from the extension. | ||
| 8 | def content_type | ||
| 9 | type = (self.path.match(/\.(\w+)$/)[1] rescue "octet-stream").downcase | ||
| 10 | case type | ||
| 11 | when %r"jpe?g" then "image/jpeg" | ||
| 12 | when %r"tiff?" then "image/tiff" | ||
| 13 | when %r"png", "gif", "bmp" then "image/#{type}" | ||
| 14 | when "txt" then "text/plain" | ||
| 15 | when %r"html?" then "text/html" | ||
| 16 | when "csv", "xml", "css", "js" then "text/#{type}" | ||
| 17 | else "application/x-#{type}" | ||
| 18 | end | ||
| 19 | end | ||
| 20 | |||
| 21 | # Returns the file's normal name. | ||
| 22 | def original_filename | ||
| 23 | File.basename(self.path) | ||
| 24 | end | ||
| 25 | |||
| 26 | # Returns the size of the file. | ||
| 27 | def size | ||
| 28 | File.size(self) | ||
| 29 | end | ||
| 30 | end | ||
| 31 | end | ||
| 32 | |||
| 33 | if defined? StringIO | ||
| 34 | class StringIO | ||
| 35 | attr_accessor :original_filename, :content_type | ||
| 36 | def original_filename | ||
| 37 | @original_filename ||= "stringio.txt" | ||
| 38 | end | ||
| 39 | def content_type | ||
| 40 | @content_type ||= "text/plain" | ||
| 41 | end | ||
| 42 | end | ||
| 43 | end | ||
| 44 | |||
| 45 | class File #:nodoc: | ||
| 46 | include Paperclip::Upfile | ||
| 47 | end | ||
| 48 | |||
diff --git a/vendor/plugins/paperclip/paperclip.gemspec b/vendor/plugins/paperclip/paperclip.gemspec deleted file mode 100644 index 12ce4c2..0000000 --- a/vendor/plugins/paperclip/paperclip.gemspec +++ /dev/null | |||
| @@ -1,40 +0,0 @@ | |||
| 1 | # -*- encoding: utf-8 -*- | ||
| 2 | |||
| 3 | Gem::Specification.new do |s| | ||
| 4 | s.name = %q{paperclip} | ||
| 5 | s.version = "2.2.8" | ||
| 6 | |||
| 7 | s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= | ||
| 8 | s.authors = ["Jon Yurek"] | ||
| 9 | s.date = %q{2009-04-02} | ||
| 10 | s.email = %q{jyurek@thoughtbot.com} | ||
| 11 | s.extra_rdoc_files = ["README.rdoc"] | ||
| 12 | s.files = ["README.rdoc", "LICENSE", "Rakefile", "init.rb", "generators/paperclip", "generators/paperclip/paperclip_generator.rb", "generators/paperclip/templates", "generators/paperclip/templates/paperclip_migration.rb.erb", "generators/paperclip/USAGE", "lib/paperclip", "lib/paperclip/attachment.rb", "lib/paperclip/callback_compatability.rb", "lib/paperclip/geometry.rb", "lib/paperclip/iostream.rb", "lib/paperclip/matchers", "lib/paperclip/matchers/have_attached_file_matcher.rb", "lib/paperclip/matchers/validate_attachment_content_type_matcher.rb", "lib/paperclip/matchers/validate_attachment_presence_matcher.rb", "lib/paperclip/matchers/validate_attachment_size_matcher.rb", "lib/paperclip/matchers.rb", "lib/paperclip/processor.rb", "lib/paperclip/storage.rb", "lib/paperclip/thumbnail.rb", "lib/paperclip/upfile.rb", "lib/paperclip.rb", "tasks/paperclip_tasks.rake", "test/attachment_test.rb", "test/database.yml", "test/debug.log", "test/fixtures", "test/fixtures/12k.png", "test/fixtures/50x50.png", "test/fixtures/5k.png", "test/fixtures/bad.png", "test/fixtures/s3.yml", "test/fixtures/text.txt", "test/fixtures/twopage.pdf", "test/geometry_test.rb", "test/helper.rb", "test/integration_test.rb", "test/iostream_test.rb", "test/matchers", "test/matchers/have_attached_file_matcher_test.rb", "test/matchers/validate_attachment_content_type_matcher_test.rb", "test/matchers/validate_attachment_presence_matcher_test.rb", "test/matchers/validate_attachment_size_matcher_test.rb", "test/paperclip_test.rb", "test/processor_test.rb", "test/s3.yml", "test/storage_test.rb", "test/thumbnail_test.rb", "test/tmp", "test/tmp/storage.txt", "shoulda_macros/paperclip.rb"] | ||
| 13 | s.has_rdoc = true | ||
| 14 | s.homepage = %q{http://www.thoughtbot.com/projects/paperclip} | ||
| 15 | s.rdoc_options = ["--line-numbers", "--inline-source"] | ||
| 16 | s.require_paths = ["lib"] | ||
| 17 | s.requirements = ["ImageMagick"] | ||
| 18 | s.rubyforge_project = %q{paperclip} | ||
| 19 | s.rubygems_version = %q{1.3.1} | ||
| 20 | s.summary = %q{File attachments as attributes for ActiveRecord} | ||
| 21 | |||
| 22 | if s.respond_to? :specification_version then | ||
| 23 | current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION | ||
| 24 | s.specification_version = 2 | ||
| 25 | |||
| 26 | if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then | ||
| 27 | s.add_runtime_dependency(%q<right_aws>, [">= 0"]) | ||
| 28 | s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"]) | ||
| 29 | s.add_development_dependency(%q<mocha>, [">= 0"]) | ||
| 30 | else | ||
| 31 | s.add_dependency(%q<right_aws>, [">= 0"]) | ||
| 32 | s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"]) | ||
| 33 | s.add_dependency(%q<mocha>, [">= 0"]) | ||
| 34 | end | ||
| 35 | else | ||
| 36 | s.add_dependency(%q<right_aws>, [">= 0"]) | ||
| 37 | s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"]) | ||
| 38 | s.add_dependency(%q<mocha>, [">= 0"]) | ||
| 39 | end | ||
| 40 | end | ||
diff --git a/vendor/plugins/paperclip/shoulda_macros/paperclip.rb b/vendor/plugins/paperclip/shoulda_macros/paperclip.rb deleted file mode 100644 index d690357..0000000 --- a/vendor/plugins/paperclip/shoulda_macros/paperclip.rb +++ /dev/null | |||
| @@ -1,68 +0,0 @@ | |||
| 1 | require 'paperclip/matchers' | ||
| 2 | |||
| 3 | module Paperclip | ||
| 4 | # =Paperclip Shoulda Macros | ||
| 5 | # | ||
| 6 | # These macros are intended for use with shoulda, and will be included into | ||
| 7 | # your tests automatically. All of the macros use the standard shoulda | ||
| 8 | # assumption that the name of the test is based on the name of the model | ||
| 9 | # you're testing (that is, UserTest is the test for the User model), and | ||
| 10 | # will load that class for testing purposes. | ||
| 11 | module Shoulda | ||
| 12 | include Matchers | ||
| 13 | # This will test whether you have defined your attachment correctly by | ||
| 14 | # checking for all the required fields exist after the definition of the | ||
| 15 | # attachment. | ||
| 16 | def should_have_attached_file name | ||
| 17 | klass = self.name.gsub(/Test$/, '').constantize | ||
| 18 | matcher = have_attached_file name | ||
| 19 | should matcher.description do | ||
| 20 | assert_accepts(matcher, klass) | ||
| 21 | end | ||
| 22 | end | ||
| 23 | |||
| 24 | # Tests for validations on the presence of the attachment. | ||
| 25 | def should_validate_attachment_presence name | ||
| 26 | klass = self.name.gsub(/Test$/, '').constantize | ||
| 27 | matcher = validate_attachment_presence name | ||
| 28 | should matcher.description do | ||
| 29 | assert_accepts(matcher, klass) | ||
| 30 | end | ||
| 31 | end | ||
| 32 | |||
| 33 | # Tests that you have content_type validations specified. There are two | ||
| 34 | # options, :valid and :invalid. Both accept an array of strings. The | ||
| 35 | # strings should be a list of content types which will pass and fail | ||
| 36 | # validation, respectively. | ||
| 37 | def should_validate_attachment_content_type name, options = {} | ||
| 38 | klass = self.name.gsub(/Test$/, '').constantize | ||
| 39 | valid = [options[:valid]].flatten | ||
| 40 | invalid = [options[:invalid]].flatten | ||
| 41 | matcher = validate_attachment_content_type(name).allowing(valid).rejecting(invalid) | ||
| 42 | should matcher.description do | ||
| 43 | assert_accepts(matcher, klass) | ||
| 44 | end | ||
| 45 | end | ||
| 46 | |||
| 47 | # Tests to ensure that you have file size validations turned on. You | ||
| 48 | # can pass the same options to this that you can to | ||
| 49 | # validate_attachment_file_size - :less_than, :greater_than, and :in. | ||
| 50 | # :less_than checks that a file is less than a certain size, :greater_than | ||
| 51 | # checks that a file is more than a certain size, and :in takes a Range or | ||
| 52 | # Array which specifies the lower and upper limits of the file size. | ||
| 53 | def should_validate_attachment_size name, options = {} | ||
| 54 | klass = self.name.gsub(/Test$/, '').constantize | ||
| 55 | min = options[:greater_than] || (options[:in] && options[:in].first) || 0 | ||
| 56 | max = options[:less_than] || (options[:in] && options[:in].last) || (1.0/0) | ||
| 57 | range = (min..max) | ||
| 58 | matcher = validate_attachment_size(name).in(range) | ||
| 59 | should matcher.description do | ||
| 60 | assert_accepts(matcher, klass) | ||
| 61 | end | ||
| 62 | end | ||
| 63 | end | ||
| 64 | end | ||
| 65 | |||
| 66 | class Test::Unit::TestCase #:nodoc: | ||
| 67 | extend Paperclip::Shoulda | ||
| 68 | end | ||
diff --git a/vendor/plugins/paperclip/tasks/paperclip_tasks.rake b/vendor/plugins/paperclip/tasks/paperclip_tasks.rake deleted file mode 100644 index 23e4c11..0000000 --- a/vendor/plugins/paperclip/tasks/paperclip_tasks.rake +++ /dev/null | |||
| @@ -1,79 +0,0 @@ | |||
| 1 | def obtain_class | ||
| 2 | class_name = ENV['CLASS'] || ENV['class'] | ||
| 3 | raise "Must specify CLASS" unless class_name | ||
| 4 | @klass = Object.const_get(class_name) | ||
| 5 | end | ||
| 6 | |||
| 7 | def obtain_attachments | ||
| 8 | name = ENV['ATTACHMENT'] || ENV['attachment'] | ||
| 9 | raise "Class #{@klass.name} has no attachments specified" unless @klass.respond_to?(:attachment_definitions) | ||
| 10 | if !name.blank? && @klass.attachment_definitions.keys.include?(name) | ||
| 11 | [ name ] | ||
| 12 | else | ||
| 13 | @klass.attachment_definitions.keys | ||
| 14 | end | ||
| 15 | end | ||
| 16 | |||
| 17 | def for_all_attachments | ||
| 18 | klass = obtain_class | ||
| 19 | names = obtain_attachments | ||
| 20 | ids = klass.connection.select_values(klass.send(:construct_finder_sql, :select => 'id')) | ||
| 21 | |||
| 22 | ids.each do |id| | ||
| 23 | instance = klass.find(id) | ||
| 24 | names.each do |name| | ||
| 25 | result = if instance.send("#{ name }?") | ||
| 26 | yield(instance, name) | ||
| 27 | else | ||
| 28 | true | ||
| 29 | end | ||
| 30 | print result ? "." : "x"; $stdout.flush | ||
| 31 | end | ||
| 32 | end | ||
| 33 | puts " Done." | ||
| 34 | end | ||
| 35 | |||
| 36 | namespace :paperclip do | ||
| 37 | desc "Refreshes both metadata and thumbnails." | ||
| 38 | task :refresh => ["paperclip:refresh:metadata", "paperclip:refresh:thumbnails"] | ||
| 39 | |||
| 40 | namespace :refresh do | ||
| 41 | desc "Regenerates thumbnails for a given CLASS (and optional ATTACHMENT)." | ||
| 42 | task :thumbnails => :environment do | ||
| 43 | errors = [] | ||
| 44 | for_all_attachments do |instance, name| | ||
| 45 | result = instance.send(name).reprocess! | ||
| 46 | errors << [instance.id, instance.errors] unless instance.errors.blank? | ||
| 47 | result | ||
| 48 | end | ||
| 49 | errors.each{|e| puts "#{e.first}: #{e.last.full_messages.inspect}" } | ||
| 50 | end | ||
| 51 | |||
| 52 | desc "Regenerates content_type/size metadata for a given CLASS (and optional ATTACHMENT)." | ||
| 53 | task :metadata => :environment do | ||
| 54 | for_all_attachments do |instance, name| | ||
| 55 | if file = instance.send(name).to_file | ||
| 56 | instance.send("#{name}_file_name=", instance.send("#{name}_file_name").strip) | ||
| 57 | instance.send("#{name}_content_type=", file.content_type.strip) | ||
| 58 | instance.send("#{name}_file_size=", file.size) if instance.respond_to?("#{name}_file_size") | ||
| 59 | instance.save(false) | ||
| 60 | else | ||
| 61 | true | ||
| 62 | end | ||
| 63 | end | ||
| 64 | end | ||
| 65 | end | ||
| 66 | |||
| 67 | desc "Cleans out invalid attachments. Useful after you've added new validations." | ||
| 68 | task :clean => :environment do | ||
| 69 | for_all_attachments do |instance, name| | ||
| 70 | instance.send(name).send(:validate) | ||
| 71 | if instance.send(name).valid? | ||
| 72 | true | ||
| 73 | else | ||
| 74 | instance.send("#{name}=", nil) | ||
| 75 | instance.save | ||
| 76 | end | ||
| 77 | end | ||
| 78 | end | ||
| 79 | end | ||
diff --git a/vendor/plugins/paperclip/test/.gitignore b/vendor/plugins/paperclip/test/.gitignore deleted file mode 100644 index b14c548..0000000 --- a/vendor/plugins/paperclip/test/.gitignore +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | debug.log | ||
diff --git a/vendor/plugins/paperclip/test/attachment_test.rb b/vendor/plugins/paperclip/test/attachment_test.rb deleted file mode 100644 index 61ab2a2..0000000 --- a/vendor/plugins/paperclip/test/attachment_test.rb +++ /dev/null | |||
| @@ -1,742 +0,0 @@ | |||
| 1 | require 'test/helper' | ||
| 2 | |||
| 3 | class Dummy | ||
| 4 | # This is a dummy class | ||
| 5 | end | ||
| 6 | |||
| 7 | class AttachmentTest < Test::Unit::TestCase | ||
| 8 | context "Attachment default_options" do | ||
| 9 | setup do | ||
| 10 | rebuild_model | ||
| 11 | @old_default_options = Paperclip::Attachment.default_options.dup | ||
| 12 | @new_default_options = @old_default_options.merge({ | ||
| 13 | :path => "argle/bargle", | ||
| 14 | :url => "fooferon", | ||
| 15 | :default_url => "not here.png" | ||
| 16 | }) | ||
| 17 | end | ||
| 18 | |||
| 19 | teardown do | ||
| 20 | Paperclip::Attachment.default_options.merge! @old_default_options | ||
| 21 | end | ||
| 22 | |||
| 23 | should "be overrideable" do | ||
| 24 | Paperclip::Attachment.default_options.merge!(@new_default_options) | ||
| 25 | @new_default_options.keys.each do |key| | ||
| 26 | assert_equal @new_default_options[key], | ||
| 27 | Paperclip::Attachment.default_options[key] | ||
| 28 | end | ||
| 29 | end | ||
| 30 | |||
| 31 | context "without an Attachment" do | ||
| 32 | setup do | ||
| 33 | @dummy = Dummy.new | ||
| 34 | end | ||
| 35 | |||
| 36 | should "return false when asked exists?" do | ||
| 37 | assert !@dummy.avatar.exists? | ||
| 38 | end | ||
| 39 | end | ||
| 40 | |||
| 41 | context "on an Attachment" do | ||
| 42 | setup do | ||
| 43 | @dummy = Dummy.new | ||
| 44 | @attachment = @dummy.avatar | ||
| 45 | end | ||
| 46 | |||
| 47 | Paperclip::Attachment.default_options.keys.each do |key| | ||
| 48 | should "be the default_options for #{key}" do | ||
| 49 | assert_equal @old_default_options[key], | ||
| 50 | @attachment.instance_variable_get("@#{key}"), | ||
| 51 | key | ||
| 52 | end | ||
| 53 | end | ||
| 54 | |||
| 55 | context "when redefined" do | ||
| 56 | setup do | ||
| 57 | Paperclip::Attachment.default_options.merge!(@new_default_options) | ||
| 58 | @dummy = Dummy.new | ||
| 59 | @attachment = @dummy.avatar | ||
| 60 | end | ||
| 61 | |||
| 62 | Paperclip::Attachment.default_options.keys.each do |key| | ||
| 63 | should "be the new default_options for #{key}" do | ||
| 64 | assert_equal @new_default_options[key], | ||
| 65 | @attachment.instance_variable_get("@#{key}"), | ||
| 66 | key | ||
| 67 | end | ||
| 68 | end | ||
| 69 | end | ||
| 70 | end | ||
| 71 | end | ||
| 72 | |||
| 73 | context "An attachment with similarly named interpolations" do | ||
| 74 | setup do | ||
| 75 | rebuild_model :path => ":id.omg/:id-bbq/:idwhat/:id_partition.wtf" | ||
| 76 | @dummy = Dummy.new | ||
| 77 | @dummy.stubs(:id).returns(1024) | ||
| 78 | @file = File.new(File.join(File.dirname(__FILE__), | ||
| 79 | "fixtures", | ||
| 80 | "5k.png"), 'rb') | ||
| 81 | @dummy.avatar = @file | ||
| 82 | end | ||
| 83 | |||
| 84 | teardown { @file.close } | ||
| 85 | |||
| 86 | should "make sure that they are interpolated correctly" do | ||
| 87 | assert_equal "1024.omg/1024-bbq/1024what/000/001/024.wtf", @dummy.avatar.path | ||
| 88 | end | ||
| 89 | end | ||
| 90 | |||
| 91 | context "An attachment with a :rails_env interpolation" do | ||
| 92 | setup do | ||
| 93 | @rails_env = "blah" | ||
| 94 | @id = 1024 | ||
| 95 | rebuild_model :path => ":rails_env/:id.png" | ||
| 96 | @dummy = Dummy.new | ||
| 97 | @dummy.stubs(:id).returns(@id) | ||
| 98 | @file = StringIO.new(".") | ||
| 99 | @dummy.avatar = @file | ||
| 100 | end | ||
| 101 | |||
| 102 | should "return the proper path" do | ||
| 103 | temporary_rails_env(@rails_env) { | ||
| 104 | assert_equal "#{@rails_env}/#{@id}.png", @dummy.avatar.path | ||
| 105 | } | ||
| 106 | end | ||
| 107 | end | ||
| 108 | |||
| 109 | context "An attachment with :convert_options" do | ||
| 110 | setup do | ||
| 111 | rebuild_model :styles => { | ||
| 112 | :thumb => "100x100", | ||
| 113 | :large => "400x400" | ||
| 114 | }, | ||
| 115 | :convert_options => { | ||
| 116 | :all => "-do_stuff", | ||
| 117 | :thumb => "-thumbnailize" | ||
| 118 | } | ||
| 119 | @dummy = Dummy.new | ||
| 120 | @dummy.avatar | ||
| 121 | end | ||
| 122 | |||
| 123 | should "report the correct options when sent #extra_options_for(:thumb)" do | ||
| 124 | assert_equal "-thumbnailize -do_stuff", @dummy.avatar.send(:extra_options_for, :thumb), @dummy.avatar.convert_options.inspect | ||
| 125 | end | ||
| 126 | |||
| 127 | should "report the correct options when sent #extra_options_for(:large)" do | ||
| 128 | assert_equal "-do_stuff", @dummy.avatar.send(:extra_options_for, :large) | ||
| 129 | end | ||
| 130 | |||
| 131 | before_should "call extra_options_for(:thumb/:large)" do | ||
| 132 | Paperclip::Attachment.any_instance.expects(:extra_options_for).with(:thumb) | ||
| 133 | Paperclip::Attachment.any_instance.expects(:extra_options_for).with(:large) | ||
| 134 | end | ||
| 135 | end | ||
| 136 | |||
| 137 | context "An attachment with :convert_options that is a proc" do | ||
| 138 | setup do | ||
| 139 | rebuild_model :styles => { | ||
| 140 | :thumb => "100x100", | ||
| 141 | :large => "400x400" | ||
| 142 | }, | ||
| 143 | :convert_options => { | ||
| 144 | :all => lambda{|i| i.all }, | ||
| 145 | :thumb => lambda{|i| i.thumb } | ||
| 146 | } | ||
| 147 | Dummy.class_eval do | ||
| 148 | def all; "-all"; end | ||
| 149 | def thumb; "-thumb"; end | ||
| 150 | end | ||
| 151 | @dummy = Dummy.new | ||
| 152 | @dummy.avatar | ||
| 153 | end | ||
| 154 | |||
| 155 | should "report the correct options when sent #extra_options_for(:thumb)" do | ||
| 156 | assert_equal "-thumb -all", @dummy.avatar.send(:extra_options_for, :thumb), @dummy.avatar.convert_options.inspect | ||
| 157 | end | ||
| 158 | |||
| 159 | should "report the correct options when sent #extra_options_for(:large)" do | ||
| 160 | assert_equal "-all", @dummy.avatar.send(:extra_options_for, :large) | ||
| 161 | end | ||
| 162 | |||
| 163 | before_should "call extra_options_for(:thumb/:large)" do | ||
| 164 | Paperclip::Attachment.any_instance.expects(:extra_options_for).with(:thumb) | ||
| 165 | Paperclip::Attachment.any_instance.expects(:extra_options_for).with(:large) | ||
| 166 | end | ||
| 167 | end | ||
| 168 | |||
| 169 | context "An attachment with :path that is a proc" do | ||
| 170 | setup do | ||
| 171 | rebuild_model :path => lambda{ |attachment| "path/#{attachment.instance.other}.:extension" } | ||
| 172 | |||
| 173 | @file = File.new(File.join(File.dirname(__FILE__), | ||
| 174 | "fixtures", | ||
| 175 | "5k.png"), 'rb') | ||
| 176 | @dummyA = Dummy.new(:other => 'a') | ||
| 177 | @dummyA.avatar = @file | ||
| 178 | @dummyB = Dummy.new(:other => 'b') | ||
| 179 | @dummyB.avatar = @file | ||
| 180 | end | ||
| 181 | |||
| 182 | teardown { @file.close } | ||
| 183 | |||
| 184 | should "return correct path" do | ||
| 185 | assert_equal "path/a.png", @dummyA.avatar.path | ||
| 186 | assert_equal "path/b.png", @dummyB.avatar.path | ||
| 187 | end | ||
| 188 | end | ||
| 189 | |||
| 190 | context "An attachment with :styles that is a proc" do | ||
| 191 | setup do | ||
| 192 | rebuild_model :styles => lambda{ |attachment| {:thumb => "50x50#", :large => "400x400"} } | ||
| 193 | |||
| 194 | @attachment = Dummy.new.avatar | ||
| 195 | end | ||
| 196 | |||
| 197 | should "have the correct geometry" do | ||
| 198 | assert_equal "50x50#", @attachment.styles[:thumb][:geometry] | ||
| 199 | end | ||
| 200 | end | ||
| 201 | |||
| 202 | context "An attachment with :url that is a proc" do | ||
| 203 | setup do | ||
| 204 | rebuild_model :url => lambda{ |attachment| "path/#{attachment.instance.other}.:extension" } | ||
| 205 | |||
| 206 | @file = File.new(File.join(File.dirname(__FILE__), | ||
| 207 | "fixtures", | ||
| 208 | "5k.png"), 'rb') | ||
| 209 | @dummyA = Dummy.new(:other => 'a') | ||
| 210 | @dummyA.avatar = @file | ||
| 211 | @dummyB = Dummy.new(:other => 'b') | ||
| 212 | @dummyB.avatar = @file | ||
| 213 | end | ||
| 214 | |||
| 215 | teardown { @file.close } | ||
| 216 | |||
| 217 | should "return correct url" do | ||
| 218 | assert_equal "path/a.png", @dummyA.avatar.url(:original, false) | ||
| 219 | assert_equal "path/b.png", @dummyB.avatar.url(:original, false) | ||
| 220 | end | ||
| 221 | end | ||
| 222 | |||
| 223 | geometry_specs = [ | ||
| 224 | [ lambda{|z| "50x50#" }, :png ], | ||
| 225 | lambda{|z| "50x50#" }, | ||
| 226 | { :geometry => lambda{|z| "50x50#" } } | ||
| 227 | ] | ||
| 228 | geometry_specs.each do |geometry_spec| | ||
| 229 | context "An attachment geometry like #{geometry_spec}" do | ||
| 230 | setup do | ||
| 231 | rebuild_model :styles => { :normal => geometry_spec } | ||
| 232 | @attachment = Dummy.new.avatar | ||
| 233 | end | ||
| 234 | |||
| 235 | should "not run the procs immediately" do | ||
| 236 | assert_kind_of Proc, @attachment.styles[:normal][:geometry] | ||
| 237 | end | ||
| 238 | |||
| 239 | context "when assigned" do | ||
| 240 | setup do | ||
| 241 | @file = StringIO.new(".") | ||
| 242 | @attachment.assign(@file) | ||
| 243 | end | ||
| 244 | |||
| 245 | should "have the correct geometry" do | ||
| 246 | assert_equal "50x50#", @attachment.styles[:normal][:geometry] | ||
| 247 | end | ||
| 248 | end | ||
| 249 | end | ||
| 250 | end | ||
| 251 | |||
| 252 | context "An attachment with both 'normal' and hash-style styles" do | ||
| 253 | setup do | ||
| 254 | rebuild_model :styles => { | ||
| 255 | :normal => ["50x50#", :png], | ||
| 256 | :hash => { :geometry => "50x50#", :format => :png } | ||
| 257 | } | ||
| 258 | @dummy = Dummy.new | ||
| 259 | @attachment = @dummy.avatar | ||
| 260 | end | ||
| 261 | |||
| 262 | [:processors, :whiny, :convert_options, :geometry, :format].each do |field| | ||
| 263 | should "have the same #{field} field" do | ||
| 264 | assert_equal @attachment.styles[:normal][field], @attachment.styles[:hash][field] | ||
| 265 | end | ||
| 266 | end | ||
| 267 | end | ||
| 268 | |||
| 269 | context "An attachment with :processors that is a proc" do | ||
| 270 | setup do | ||
| 271 | rebuild_model :styles => { :normal => '' }, :processors => lambda { |a| [ :test ] } | ||
| 272 | @attachment = Dummy.new.avatar | ||
| 273 | end | ||
| 274 | |||
| 275 | should "not run the proc immediately" do | ||
| 276 | assert_kind_of Proc, @attachment.styles[:normal][:processors] | ||
| 277 | end | ||
| 278 | |||
| 279 | context "when assigned" do | ||
| 280 | setup do | ||
| 281 | @attachment.assign(StringIO.new(".")) | ||
| 282 | end | ||
| 283 | |||
| 284 | should "have the correct processors" do | ||
| 285 | assert_equal [ :test ], @attachment.styles[:normal][:processors] | ||
| 286 | end | ||
| 287 | end | ||
| 288 | end | ||
| 289 | |||
| 290 | context "An attachment with erroring processor" do | ||
| 291 | setup do | ||
| 292 | rebuild_model :processor => [:thumbnail], :styles => { :small => '' }, :whiny_thumbnails => true | ||
| 293 | @dummy = Dummy.new | ||
| 294 | Paperclip::Thumbnail.expects(:make).raises(Paperclip::PaperclipError, "cannot be processed.") | ||
| 295 | @file = StringIO.new("...") | ||
| 296 | @file.stubs(:to_tempfile).returns(@file) | ||
| 297 | @dummy.avatar = @file | ||
| 298 | end | ||
| 299 | |||
| 300 | should "correctly forward processing error message to the instance" do | ||
| 301 | @dummy.valid? | ||
| 302 | assert_contains @dummy.errors.full_messages, "Avatar cannot be processed." | ||
| 303 | end | ||
| 304 | end | ||
| 305 | |||
| 306 | context "An attachment with multiple processors" do | ||
| 307 | setup do | ||
| 308 | class Paperclip::Test < Paperclip::Processor; end | ||
| 309 | @style_params = { :once => {:one => 1, :two => 2} } | ||
| 310 | rebuild_model :processors => [:thumbnail, :test], :styles => @style_params | ||
| 311 | @dummy = Dummy.new | ||
| 312 | @file = StringIO.new("...") | ||
| 313 | @file.stubs(:to_tempfile).returns(@file) | ||
| 314 | Paperclip::Test.stubs(:make).returns(@file) | ||
| 315 | Paperclip::Thumbnail.stubs(:make).returns(@file) | ||
| 316 | end | ||
| 317 | |||
| 318 | context "when assigned" do | ||
| 319 | setup { @dummy.avatar = @file } | ||
| 320 | |||
| 321 | before_should "call #make on all specified processors" do | ||
| 322 | expected_params = @style_params[:once].merge({:processors => [:thumbnail, :test], :whiny => nil, :convert_options => ""}) | ||
| 323 | Paperclip::Thumbnail.expects(:make).with(@file, expected_params, @dummy.avatar).returns(@file) | ||
| 324 | Paperclip::Test.expects(:make).with(@file, expected_params, @dummy.avatar).returns(@file) | ||
| 325 | end | ||
| 326 | |||
| 327 | before_should "call #make with attachment passed as third argument" do | ||
| 328 | expected_params = @style_params[:once].merge({:processors => [:thumbnail, :test], :whiny => nil, :convert_options => ""}) | ||
| 329 | Paperclip::Test.expects(:make).with(@file, expected_params, @dummy.avatar).returns(@file) | ||
| 330 | end | ||
| 331 | end | ||
| 332 | end | ||
| 333 | |||
| 334 | context "An attachment with no processors defined" do | ||
| 335 | setup do | ||
| 336 | rebuild_model :processors => [], :styles => {:something => 1} | ||
| 337 | @dummy = Dummy.new | ||
| 338 | @file = StringIO.new("...") | ||
| 339 | end | ||
| 340 | should "raise when assigned to" do | ||
| 341 | assert_raises(RuntimeError){ @dummy.avatar = @file } | ||
| 342 | end | ||
| 343 | end | ||
| 344 | |||
| 345 | context "Assigning an attachment with post_process hooks" do | ||
| 346 | setup do | ||
| 347 | rebuild_model :styles => { :something => "100x100#" } | ||
| 348 | Dummy.class_eval do | ||
| 349 | before_avatar_post_process :do_before_avatar | ||
| 350 | after_avatar_post_process :do_after_avatar | ||
| 351 | before_post_process :do_before_all | ||
| 352 | after_post_process :do_after_all | ||
| 353 | def do_before_avatar; end | ||
| 354 | def do_after_avatar; end | ||
| 355 | def do_before_all; end | ||
| 356 | def do_after_all; end | ||
| 357 | end | ||
| 358 | @file = StringIO.new(".") | ||
| 359 | @file.stubs(:to_tempfile).returns(@file) | ||
| 360 | @dummy = Dummy.new | ||
| 361 | Paperclip::Thumbnail.stubs(:make).returns(@file) | ||
| 362 | @attachment = @dummy.avatar | ||
| 363 | end | ||
| 364 | |||
| 365 | should "call the defined callbacks when assigned" do | ||
| 366 | @dummy.expects(:do_before_avatar).with() | ||
| 367 | @dummy.expects(:do_after_avatar).with() | ||
| 368 | @dummy.expects(:do_before_all).with() | ||
| 369 | @dummy.expects(:do_after_all).with() | ||
| 370 | Paperclip::Thumbnail.expects(:make).returns(@file) | ||
| 371 | @dummy.avatar = @file | ||
| 372 | end | ||
| 373 | |||
| 374 | should "not cancel the processing if a before_post_process returns nil" do | ||
| 375 | @dummy.expects(:do_before_avatar).with().returns(nil) | ||
| 376 | @dummy.expects(:do_after_avatar).with() | ||
| 377 | @dummy.expects(:do_before_all).with().returns(nil) | ||
| 378 | @dummy.expects(:do_after_all).with() | ||
| 379 | Paperclip::Thumbnail.expects(:make).returns(@file) | ||
| 380 | @dummy.avatar = @file | ||
| 381 | end | ||
| 382 | |||
| 383 | should "cancel the processing if a before_post_process returns false" do | ||
| 384 | @dummy.expects(:do_before_avatar).never | ||
| 385 | @dummy.expects(:do_after_avatar).never | ||
| 386 | @dummy.expects(:do_before_all).with().returns(false) | ||
| 387 | @dummy.expects(:do_after_all).never | ||
| 388 | Paperclip::Thumbnail.expects(:make).never | ||
| 389 | @dummy.avatar = @file | ||
| 390 | end | ||
| 391 | |||
| 392 | should "cancel the processing if a before_avatar_post_process returns false" do | ||
| 393 | @dummy.expects(:do_before_avatar).with().returns(false) | ||
| 394 | @dummy.expects(:do_after_avatar).never | ||
| 395 | @dummy.expects(:do_before_all).with().returns(true) | ||
| 396 | @dummy.expects(:do_after_all).never | ||
| 397 | Paperclip::Thumbnail.expects(:make).never | ||
| 398 | @dummy.avatar = @file | ||
| 399 | end | ||
| 400 | end | ||
| 401 | |||
| 402 | context "Assigning an attachment" do | ||
| 403 | setup do | ||
| 404 | rebuild_model :styles => { :something => "100x100#" } | ||
| 405 | @file = StringIO.new(".") | ||
| 406 | @file.expects(:original_filename).returns("5k.png\n\n") | ||
| 407 | @file.expects(:content_type).returns("image/png\n\n") | ||
| 408 | @file.stubs(:to_tempfile).returns(@file) | ||
| 409 | @dummy = Dummy.new | ||
| 410 | Paperclip::Thumbnail.expects(:make).returns(@file) | ||
| 411 | @dummy.expects(:run_callbacks).with(:before_avatar_post_process, {:original => @file}) | ||
| 412 | @dummy.expects(:run_callbacks).with(:before_post_process, {:original => @file}) | ||
| 413 | @dummy.expects(:run_callbacks).with(:after_avatar_post_process, {:original => @file, :something => @file}) | ||
| 414 | @dummy.expects(:run_callbacks).with(:after_post_process, {:original => @file, :something => @file}) | ||
| 415 | @attachment = @dummy.avatar | ||
| 416 | @dummy.avatar = @file | ||
| 417 | end | ||
| 418 | |||
| 419 | should "strip whitespace from original_filename field" do | ||
| 420 | assert_equal "5k.png", @dummy.avatar.original_filename | ||
| 421 | end | ||
| 422 | |||
| 423 | should "strip whitespace from content_type field" do | ||
| 424 | assert_equal "image/png", @dummy.avatar.instance.avatar_content_type | ||
| 425 | end | ||
| 426 | end | ||
| 427 | |||
| 428 | context "Attachment with strange letters" do | ||
| 429 | setup do | ||
| 430 | rebuild_model | ||
| 431 | |||
| 432 | @not_file = mock | ||
| 433 | @tempfile = mock | ||
| 434 | @not_file.stubs(:nil?).returns(false) | ||
| 435 | @not_file.expects(:size).returns(10) | ||
| 436 | @tempfile.expects(:size).returns(10) | ||
| 437 | @not_file.expects(:to_tempfile).returns(@tempfile) | ||
| 438 | @not_file.expects(:original_filename).returns("sheep_say_bæ.png\r\n") | ||
| 439 | @not_file.expects(:content_type).returns("image/png\r\n") | ||
| 440 | |||
| 441 | @dummy = Dummy.new | ||
| 442 | @attachment = @dummy.avatar | ||
| 443 | @attachment.expects(:valid_assignment?).with(@not_file).returns(true) | ||
| 444 | @attachment.expects(:queue_existing_for_delete) | ||
| 445 | @attachment.expects(:post_process) | ||
| 446 | @attachment.expects(:valid?).returns(true) | ||
| 447 | @attachment.expects(:validate) | ||
| 448 | @dummy.avatar = @not_file | ||
| 449 | end | ||
| 450 | |||
| 451 | should "remove strange letters and replace with underscore (_)" do | ||
| 452 | assert_equal "sheep_say_b_.png", @dummy.avatar.original_filename | ||
| 453 | end | ||
| 454 | |||
| 455 | end | ||
| 456 | |||
| 457 | context "An attachment" do | ||
| 458 | setup do | ||
| 459 | Paperclip::Attachment.default_options.merge!({ | ||
| 460 | :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension" | ||
| 461 | }) | ||
| 462 | FileUtils.rm_rf("tmp") | ||
| 463 | rebuild_model | ||
| 464 | @instance = Dummy.new | ||
| 465 | @attachment = Paperclip::Attachment.new(:avatar, @instance) | ||
| 466 | @file = File.new(File.join(File.dirname(__FILE__), | ||
| 467 | "fixtures", | ||
| 468 | "5k.png"), 'rb') | ||
| 469 | end | ||
| 470 | |||
| 471 | teardown { @file.close } | ||
| 472 | |||
| 473 | should "raise if there are not the correct columns when you try to assign" do | ||
| 474 | @other_attachment = Paperclip::Attachment.new(:not_here, @instance) | ||
| 475 | assert_raises(Paperclip::PaperclipError) do | ||
| 476 | @other_attachment.assign(@file) | ||
| 477 | end | ||
| 478 | end | ||
| 479 | |||
| 480 | should "return its default_url when no file assigned" do | ||
| 481 | assert @attachment.to_file.nil? | ||
| 482 | assert_equal "/avatars/original/missing.png", @attachment.url | ||
| 483 | assert_equal "/avatars/blah/missing.png", @attachment.url(:blah) | ||
| 484 | end | ||
| 485 | |||
| 486 | should "return nil as path when no file assigned" do | ||
| 487 | assert @attachment.to_file.nil? | ||
| 488 | assert_equal nil, @attachment.path | ||
| 489 | assert_equal nil, @attachment.path(:blah) | ||
| 490 | end | ||
| 491 | |||
| 492 | context "with a file assigned in the database" do | ||
| 493 | setup do | ||
| 494 | @attachment.stubs(:instance_read).with(:file_name).returns("5k.png") | ||
| 495 | @attachment.stubs(:instance_read).with(:content_type).returns("image/png") | ||
| 496 | @attachment.stubs(:instance_read).with(:file_size).returns(12345) | ||
| 497 | now = Time.now | ||
| 498 | Time.stubs(:now).returns(now) | ||
| 499 | @attachment.stubs(:instance_read).with(:updated_at).returns(Time.now) | ||
| 500 | end | ||
| 501 | |||
| 502 | should "return a correct url even if the file does not exist" do | ||
| 503 | assert_nil @attachment.to_file | ||
| 504 | assert_match %r{^/system/avatars/#{@instance.id}/blah/5k\.png}, @attachment.url(:blah) | ||
| 505 | end | ||
| 506 | |||
| 507 | should "make sure the updated_at mtime is in the url if it is defined" do | ||
| 508 | assert_match %r{#{Time.now.to_i}$}, @attachment.url(:blah) | ||
| 509 | end | ||
| 510 | |||
| 511 | should "make sure the updated_at mtime is NOT in the url if false is passed to the url method" do | ||
| 512 | assert_no_match %r{#{Time.now.to_i}$}, @attachment.url(:blah, false) | ||
| 513 | end | ||
| 514 | |||
| 515 | context "with the updated_at field removed" do | ||
| 516 | setup do | ||
| 517 | @attachment.stubs(:instance_read).with(:updated_at).returns(nil) | ||
| 518 | end | ||
| 519 | |||
| 520 | should "only return the url without the updated_at when sent #url" do | ||
| 521 | assert_match "/avatars/#{@instance.id}/blah/5k.png", @attachment.url(:blah) | ||
| 522 | end | ||
| 523 | end | ||
| 524 | |||
| 525 | should "return the proper path when filename has a single .'s" do | ||
| 526 | assert_equal "./test/../tmp/avatars/dummies/original/#{@instance.id}/5k.png", @attachment.path | ||
| 527 | end | ||
| 528 | |||
| 529 | should "return the proper path when filename has multiple .'s" do | ||
| 530 | @attachment.stubs(:instance_read).with(:file_name).returns("5k.old.png") | ||
| 531 | assert_equal "./test/../tmp/avatars/dummies/original/#{@instance.id}/5k.old.png", @attachment.path | ||
| 532 | end | ||
| 533 | |||
| 534 | context "when expecting three styles" do | ||
| 535 | setup do | ||
| 536 | styles = {:styles => { :large => ["400x400", :png], | ||
| 537 | :medium => ["100x100", :gif], | ||
| 538 | :small => ["32x32#", :jpg]}} | ||
| 539 | @attachment = Paperclip::Attachment.new(:avatar, | ||
| 540 | @instance, | ||
| 541 | styles) | ||
| 542 | end | ||
| 543 | |||
| 544 | context "and assigned a file" do | ||
| 545 | setup do | ||
| 546 | now = Time.now | ||
| 547 | Time.stubs(:now).returns(now) | ||
| 548 | @attachment.assign(@file) | ||
| 549 | end | ||
| 550 | |||
| 551 | should "be dirty" do | ||
| 552 | assert @attachment.dirty? | ||
| 553 | end | ||
| 554 | |||
| 555 | context "and saved" do | ||
| 556 | setup do | ||
| 557 | @attachment.save | ||
| 558 | end | ||
| 559 | |||
| 560 | should "return the real url" do | ||
| 561 | file = @attachment.to_file | ||
| 562 | assert file | ||
| 563 | assert_match %r{^/system/avatars/#{@instance.id}/original/5k\.png}, @attachment.url | ||
| 564 | assert_match %r{^/system/avatars/#{@instance.id}/small/5k\.jpg}, @attachment.url(:small) | ||
| 565 | file.close | ||
| 566 | end | ||
| 567 | |||
| 568 | should "commit the files to disk" do | ||
| 569 | [:large, :medium, :small].each do |style| | ||
| 570 | io = @attachment.to_io(style) | ||
| 571 | assert File.exists?(io) | ||
| 572 | assert ! io.is_a?(::Tempfile) | ||
| 573 | io.close | ||
| 574 | end | ||
| 575 | end | ||
| 576 | |||
| 577 | should "save the files as the right formats and sizes" do | ||
| 578 | [[:large, 400, 61, "PNG"], | ||
| 579 | [:medium, 100, 15, "GIF"], | ||
| 580 | [:small, 32, 32, "JPEG"]].each do |style| | ||
| 581 | cmd = %Q[identify -format "%w %h %b %m" "#{@attachment.path(style.first)}"] | ||
| 582 | out = `#{cmd}` | ||
| 583 | width, height, size, format = out.split(" ") | ||
| 584 | assert_equal style[1].to_s, width.to_s | ||
| 585 | assert_equal style[2].to_s, height.to_s | ||
| 586 | assert_equal style[3].to_s, format.to_s | ||
| 587 | end | ||
| 588 | end | ||
| 589 | |||
| 590 | should "still have its #file attribute not be nil" do | ||
| 591 | assert ! (file = @attachment.to_file).nil? | ||
| 592 | file.close | ||
| 593 | end | ||
| 594 | |||
| 595 | context "and trying to delete" do | ||
| 596 | setup do | ||
| 597 | @existing_names = @attachment.styles.keys.collect do |style| | ||
| 598 | @attachment.path(style) | ||
| 599 | end | ||
| 600 | end | ||
| 601 | |||
| 602 | should "delete the files after assigning nil" do | ||
| 603 | @attachment.expects(:instance_write).with(:file_name, nil) | ||
| 604 | @attachment.expects(:instance_write).with(:content_type, nil) | ||
| 605 | @attachment.expects(:instance_write).with(:file_size, nil) | ||
| 606 | @attachment.expects(:instance_write).with(:updated_at, nil) | ||
| 607 | @attachment.assign nil | ||
| 608 | @attachment.save | ||
| 609 | @existing_names.each{|f| assert ! File.exists?(f) } | ||
| 610 | end | ||
| 611 | |||
| 612 | should "delete the files when you call #clear and #save" do | ||
| 613 | @attachment.expects(:instance_write).with(:file_name, nil) | ||
| 614 | @attachment.expects(:instance_write).with(:content_type, nil) | ||
| 615 | @attachment.expects(:instance_write).with(:file_size, nil) | ||
| 616 | @attachment.expects(:instance_write).with(:updated_at, nil) | ||
| 617 | @attachment.clear | ||
| 618 | @attachment.save | ||
| 619 | @existing_names.each{|f| assert ! File.exists?(f) } | ||
| 620 | end | ||
| 621 | |||
| 622 | should "delete the files when you call #delete" do | ||
| 623 | @attachment.expects(:instance_write).with(:file_name, nil) | ||
| 624 | @attachment.expects(:instance_write).with(:content_type, nil) | ||
| 625 | @attachment.expects(:instance_write).with(:file_size, nil) | ||
| 626 | @attachment.expects(:instance_write).with(:updated_at, nil) | ||
| 627 | @attachment.destroy | ||
| 628 | @existing_names.each{|f| assert ! File.exists?(f) } | ||
| 629 | end | ||
| 630 | end | ||
| 631 | end | ||
| 632 | end | ||
| 633 | end | ||
| 634 | |||
| 635 | end | ||
| 636 | |||
| 637 | context "when trying a nonexistant storage type" do | ||
| 638 | setup do | ||
| 639 | rebuild_model :storage => :not_here | ||
| 640 | end | ||
| 641 | |||
| 642 | should "not be able to find the module" do | ||
| 643 | assert_raise(NameError){ Dummy.new.avatar } | ||
| 644 | end | ||
| 645 | end | ||
| 646 | end | ||
| 647 | |||
| 648 | context "An attachment with only a avatar_file_name column" do | ||
| 649 | setup do | ||
| 650 | ActiveRecord::Base.connection.create_table :dummies, :force => true do |table| | ||
| 651 | table.column :avatar_file_name, :string | ||
| 652 | end | ||
| 653 | rebuild_class | ||
| 654 | @dummy = Dummy.new | ||
| 655 | @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb') | ||
| 656 | end | ||
| 657 | |||
| 658 | teardown { @file.close } | ||
| 659 | |||
| 660 | should "not error when assigned an attachment" do | ||
| 661 | assert_nothing_raised { @dummy.avatar = @file } | ||
| 662 | end | ||
| 663 | |||
| 664 | should "return the time when sent #avatar_updated_at" do | ||
| 665 | now = Time.now | ||
| 666 | Time.stubs(:now).returns(now) | ||
| 667 | @dummy.avatar = @file | ||
| 668 | assert now, @dummy.avatar.updated_at | ||
| 669 | end | ||
| 670 | |||
| 671 | should "return nil when reloaded and sent #avatar_updated_at" do | ||
| 672 | @dummy.save | ||
| 673 | @dummy.reload | ||
| 674 | assert_nil @dummy.avatar.updated_at | ||
| 675 | end | ||
| 676 | |||
| 677 | should "return the right value when sent #avatar_file_size" do | ||
| 678 | @dummy.avatar = @file | ||
| 679 | assert_equal @file.size, @dummy.avatar.size | ||
| 680 | end | ||
| 681 | |||
| 682 | context "and avatar_updated_at column" do | ||
| 683 | setup do | ||
| 684 | ActiveRecord::Base.connection.add_column :dummies, :avatar_updated_at, :timestamp | ||
| 685 | rebuild_class | ||
| 686 | @dummy = Dummy.new | ||
| 687 | end | ||
| 688 | |||
| 689 | should "not error when assigned an attachment" do | ||
| 690 | assert_nothing_raised { @dummy.avatar = @file } | ||
| 691 | end | ||
| 692 | |||
| 693 | should "return the right value when sent #avatar_updated_at" do | ||
| 694 | now = Time.now | ||
| 695 | Time.stubs(:now).returns(now) | ||
| 696 | @dummy.avatar = @file | ||
| 697 | assert_equal now.to_i, @dummy.avatar.updated_at | ||
| 698 | end | ||
| 699 | end | ||
| 700 | |||
| 701 | context "and avatar_content_type column" do | ||
| 702 | setup do | ||
| 703 | ActiveRecord::Base.connection.add_column :dummies, :avatar_content_type, :string | ||
| 704 | rebuild_class | ||
| 705 | @dummy = Dummy.new | ||
| 706 | end | ||
| 707 | |||
| 708 | should "not error when assigned an attachment" do | ||
| 709 | assert_nothing_raised { @dummy.avatar = @file } | ||
| 710 | end | ||
| 711 | |||
| 712 | should "return the right value when sent #avatar_content_type" do | ||
| 713 | @dummy.avatar = @file | ||
| 714 | assert_equal "image/png", @dummy.avatar.content_type | ||
| 715 | end | ||
| 716 | end | ||
| 717 | |||
| 718 | context "and avatar_file_size column" do | ||
| 719 | setup do | ||
| 720 | ActiveRecord::Base.connection.add_column :dummies, :avatar_file_size, :integer | ||
| 721 | rebuild_class | ||
| 722 | @dummy = Dummy.new | ||
| 723 | end | ||
| 724 | |||
| 725 | should "not error when assigned an attachment" do | ||
| 726 | assert_nothing_raised { @dummy.avatar = @file } | ||
| 727 | end | ||
| 728 | |||
| 729 | should "return the right value when sent #avatar_file_size" do | ||
| 730 | @dummy.avatar = @file | ||
| 731 | assert_equal @file.size, @dummy.avatar.size | ||
| 732 | end | ||
| 733 | |||
| 734 | should "return the right value when saved, reloaded, and sent #avatar_file_size" do | ||
| 735 | @dummy.avatar = @file | ||
| 736 | @dummy.save | ||
| 737 | @dummy = Dummy.find(@dummy.id) | ||
| 738 | assert_equal @file.size, @dummy.avatar.size | ||
| 739 | end | ||
| 740 | end | ||
| 741 | end | ||
| 742 | end | ||
diff --git a/vendor/plugins/paperclip/test/fixtures/12k.png b/vendor/plugins/paperclip/test/fixtures/12k.png deleted file mode 100644 index f819d45..0000000 --- a/vendor/plugins/paperclip/test/fixtures/12k.png +++ /dev/null | |||
| Binary files differ | |||
diff --git a/vendor/plugins/paperclip/test/fixtures/50x50.png b/vendor/plugins/paperclip/test/fixtures/50x50.png deleted file mode 100644 index 63f5646..0000000 --- a/vendor/plugins/paperclip/test/fixtures/50x50.png +++ /dev/null | |||
| Binary files differ | |||
diff --git a/vendor/plugins/paperclip/test/fixtures/5k.png b/vendor/plugins/paperclip/test/fixtures/5k.png deleted file mode 100644 index 75d9f04..0000000 --- a/vendor/plugins/paperclip/test/fixtures/5k.png +++ /dev/null | |||
| Binary files differ | |||
diff --git a/vendor/plugins/paperclip/test/fixtures/bad.png b/vendor/plugins/paperclip/test/fixtures/bad.png deleted file mode 100644 index 7ba4f07..0000000 --- a/vendor/plugins/paperclip/test/fixtures/bad.png +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | This is not an image. | ||
diff --git a/vendor/plugins/paperclip/test/fixtures/text.txt b/vendor/plugins/paperclip/test/fixtures/text.txt deleted file mode 100644 index e69de29..0000000 --- a/vendor/plugins/paperclip/test/fixtures/text.txt +++ /dev/null | |||
diff --git a/vendor/plugins/paperclip/test/fixtures/twopage.pdf b/vendor/plugins/paperclip/test/fixtures/twopage.pdf deleted file mode 100644 index 0c34a51..0000000 --- a/vendor/plugins/paperclip/test/fixtures/twopage.pdf +++ /dev/null | |||
| Binary files differ | |||
diff --git a/vendor/plugins/paperclip/test/geometry_test.rb b/vendor/plugins/paperclip/test/geometry_test.rb deleted file mode 100644 index 134372d..0000000 --- a/vendor/plugins/paperclip/test/geometry_test.rb +++ /dev/null | |||
| @@ -1,168 +0,0 @@ | |||
| 1 | require 'test/helper' | ||
| 2 | |||
| 3 | class GeometryTest < Test::Unit::TestCase | ||
| 4 | context "Paperclip::Geometry" do | ||
| 5 | should "correctly report its given dimensions" do | ||
| 6 | assert @geo = Paperclip::Geometry.new(1024, 768) | ||
| 7 | assert_equal 1024, @geo.width | ||
| 8 | assert_equal 768, @geo.height | ||
| 9 | end | ||
| 10 | |||
| 11 | should "set height to 0 if height dimension is missing" do | ||
| 12 | assert @geo = Paperclip::Geometry.new(1024) | ||
| 13 | assert_equal 1024, @geo.width | ||
| 14 | assert_equal 0, @geo.height | ||
| 15 | end | ||
| 16 | |||
| 17 | should "set width to 0 if width dimension is missing" do | ||
| 18 | assert @geo = Paperclip::Geometry.new(nil, 768) | ||
| 19 | assert_equal 0, @geo.width | ||
| 20 | assert_equal 768, @geo.height | ||
| 21 | end | ||
| 22 | |||
| 23 | should "be generated from a WxH-formatted string" do | ||
| 24 | assert @geo = Paperclip::Geometry.parse("800x600") | ||
| 25 | assert_equal 800, @geo.width | ||
| 26 | assert_equal 600, @geo.height | ||
| 27 | end | ||
| 28 | |||
| 29 | should "be generated from a xH-formatted string" do | ||
| 30 | assert @geo = Paperclip::Geometry.parse("x600") | ||
| 31 | assert_equal 0, @geo.width | ||
| 32 | assert_equal 600, @geo.height | ||
| 33 | end | ||
| 34 | |||
| 35 | should "be generated from a Wx-formatted string" do | ||
| 36 | assert @geo = Paperclip::Geometry.parse("800x") | ||
| 37 | assert_equal 800, @geo.width | ||
| 38 | assert_equal 0, @geo.height | ||
| 39 | end | ||
| 40 | |||
| 41 | should "be generated from a W-formatted string" do | ||
| 42 | assert @geo = Paperclip::Geometry.parse("800") | ||
| 43 | assert_equal 800, @geo.width | ||
| 44 | assert_equal 0, @geo.height | ||
| 45 | end | ||
| 46 | |||
| 47 | should "ensure the modifier is nil if not present" do | ||
| 48 | assert @geo = Paperclip::Geometry.parse("123x456") | ||
| 49 | assert_nil @geo.modifier | ||
| 50 | end | ||
| 51 | |||
| 52 | ['>', '<', '#', '@', '%', '^', '!', nil].each do |mod| | ||
| 53 | should "ensure the modifier #{mod.inspect} is preserved" do | ||
| 54 | assert @geo = Paperclip::Geometry.parse("123x456#{mod}") | ||
| 55 | assert_equal mod, @geo.modifier | ||
| 56 | assert_equal "123x456#{mod}", @geo.to_s | ||
| 57 | end | ||
| 58 | end | ||
| 59 | |||
| 60 | ['>', '<', '#', '@', '%', '^', '!', nil].each do |mod| | ||
| 61 | should "ensure the modifier #{mod.inspect} is preserved with no height" do | ||
| 62 | assert @geo = Paperclip::Geometry.parse("123x#{mod}") | ||
| 63 | assert_equal mod, @geo.modifier | ||
| 64 | assert_equal "123#{mod}", @geo.to_s | ||
| 65 | end | ||
| 66 | end | ||
| 67 | |||
| 68 | should "make sure the modifier gets passed during transformation_to" do | ||
| 69 | assert @src = Paperclip::Geometry.parse("123x456") | ||
| 70 | assert @dst = Paperclip::Geometry.parse("123x456>") | ||
| 71 | assert_equal "123x456>", @src.transformation_to(@dst).to_s | ||
| 72 | end | ||
| 73 | |||
| 74 | should "generate correct ImageMagick formatting string for W-formatted string" do | ||
| 75 | assert @geo = Paperclip::Geometry.parse("800") | ||
| 76 | assert_equal "800", @geo.to_s | ||
| 77 | end | ||
| 78 | |||
| 79 | should "generate correct ImageMagick formatting string for Wx-formatted string" do | ||
| 80 | assert @geo = Paperclip::Geometry.parse("800x") | ||
| 81 | assert_equal "800", @geo.to_s | ||
| 82 | end | ||
| 83 | |||
| 84 | should "generate correct ImageMagick formatting string for xH-formatted string" do | ||
| 85 | assert @geo = Paperclip::Geometry.parse("x600") | ||
| 86 | assert_equal "x600", @geo.to_s | ||
| 87 | end | ||
| 88 | |||
| 89 | should "generate correct ImageMagick formatting string for WxH-formatted string" do | ||
| 90 | assert @geo = Paperclip::Geometry.parse("800x600") | ||
| 91 | assert_equal "800x600", @geo.to_s | ||
| 92 | end | ||
| 93 | |||
| 94 | should "be generated from a file" do | ||
| 95 | file = File.join(File.dirname(__FILE__), "fixtures", "5k.png") | ||
| 96 | file = File.new(file, 'rb') | ||
| 97 | assert_nothing_raised{ @geo = Paperclip::Geometry.from_file(file) } | ||
| 98 | assert @geo.height > 0 | ||
| 99 | assert @geo.width > 0 | ||
| 100 | end | ||
| 101 | |||
| 102 | should "be generated from a file path" do | ||
| 103 | file = File.join(File.dirname(__FILE__), "fixtures", "5k.png") | ||
| 104 | assert_nothing_raised{ @geo = Paperclip::Geometry.from_file(file) } | ||
| 105 | assert @geo.height > 0 | ||
| 106 | assert @geo.width > 0 | ||
| 107 | end | ||
| 108 | |||
| 109 | should "not generate from a bad file" do | ||
| 110 | file = "/home/This File Does Not Exist.omg" | ||
| 111 | assert_raise(Paperclip::NotIdentifiedByImageMagickError){ @geo = Paperclip::Geometry.from_file(file) } | ||
| 112 | end | ||
| 113 | |||
| 114 | [['vertical', 900, 1440, true, false, false, 1440, 900, 0.625], | ||
| 115 | ['horizontal', 1024, 768, false, true, false, 1024, 768, 1.3333], | ||
| 116 | ['square', 100, 100, false, false, true, 100, 100, 1]].each do |args| | ||
| 117 | context "performing calculations on a #{args[0]} viewport" do | ||
| 118 | setup do | ||
| 119 | @geo = Paperclip::Geometry.new(args[1], args[2]) | ||
| 120 | end | ||
| 121 | |||
| 122 | should "#{args[3] ? "" : "not"} be vertical" do | ||
| 123 | assert_equal args[3], @geo.vertical? | ||
| 124 | end | ||
| 125 | |||
| 126 | should "#{args[4] ? "" : "not"} be horizontal" do | ||
| 127 | assert_equal args[4], @geo.horizontal? | ||
| 128 | end | ||
| 129 | |||
| 130 | should "#{args[5] ? "" : "not"} be square" do | ||
| 131 | assert_equal args[5], @geo.square? | ||
| 132 | end | ||
| 133 | |||
| 134 | should "report that #{args[6]} is the larger dimension" do | ||
| 135 | assert_equal args[6], @geo.larger | ||
| 136 | end | ||
| 137 | |||
| 138 | should "report that #{args[7]} is the smaller dimension" do | ||
| 139 | assert_equal args[7], @geo.smaller | ||
| 140 | end | ||
| 141 | |||
| 142 | should "have an aspect ratio of #{args[8]}" do | ||
| 143 | assert_in_delta args[8], @geo.aspect, 0.0001 | ||
| 144 | end | ||
| 145 | end | ||
| 146 | end | ||
| 147 | |||
| 148 | [[ [1000, 100], [64, 64], "x64", "64x64+288+0" ], | ||
| 149 | [ [100, 1000], [50, 950], "x950", "50x950+22+0" ], | ||
| 150 | [ [100, 1000], [50, 25], "50x", "50x25+0+237" ]]. each do |args| | ||
| 151 | context "of #{args[0].inspect} and given a Geometry #{args[1].inspect} and sent transform_to" do | ||
| 152 | setup do | ||
| 153 | @geo = Paperclip::Geometry.new(*args[0]) | ||
| 154 | @dst = Paperclip::Geometry.new(*args[1]) | ||
| 155 | @scale, @crop = @geo.transformation_to @dst, true | ||
| 156 | end | ||
| 157 | |||
| 158 | should "be able to return the correct scaling transformation geometry #{args[2]}" do | ||
| 159 | assert_equal args[2], @scale | ||
| 160 | end | ||
| 161 | |||
| 162 | should "be able to return the correct crop transformation geometry #{args[3]}" do | ||
| 163 | assert_equal args[3], @crop | ||
| 164 | end | ||
| 165 | end | ||
| 166 | end | ||
| 167 | end | ||
| 168 | end | ||
diff --git a/vendor/plugins/paperclip/test/helper.rb b/vendor/plugins/paperclip/test/helper.rb deleted file mode 100644 index 3e7e6a1..0000000 --- a/vendor/plugins/paperclip/test/helper.rb +++ /dev/null | |||
| @@ -1,82 +0,0 @@ | |||
| 1 | require 'rubygems' | ||
| 2 | require 'test/unit' | ||
| 3 | gem 'thoughtbot-shoulda', ">= 2.9.0" | ||
| 4 | require 'shoulda' | ||
| 5 | require 'mocha' | ||
| 6 | require 'tempfile' | ||
| 7 | |||
| 8 | gem 'sqlite3-ruby' | ||
| 9 | |||
| 10 | require 'active_record' | ||
| 11 | require 'active_support' | ||
| 12 | begin | ||
| 13 | require 'ruby-debug' | ||
| 14 | rescue LoadError | ||
| 15 | puts "ruby-debug not loaded" | ||
| 16 | end | ||
| 17 | |||
| 18 | ROOT = File.join(File.dirname(__FILE__), '..') | ||
| 19 | RAILS_ROOT = ROOT | ||
| 20 | |||
| 21 | $LOAD_PATH << File.join(ROOT, 'lib') | ||
| 22 | $LOAD_PATH << File.join(ROOT, 'lib', 'paperclip') | ||
| 23 | |||
| 24 | require File.join(ROOT, 'lib', 'paperclip.rb') | ||
| 25 | |||
| 26 | require 'shoulda_macros/paperclip' | ||
| 27 | |||
| 28 | ENV['RAILS_ENV'] ||= 'test' | ||
| 29 | |||
| 30 | FIXTURES_DIR = File.join(File.dirname(__FILE__), "fixtures") | ||
| 31 | config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml')) | ||
| 32 | ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log") | ||
| 33 | ActiveRecord::Base.establish_connection(config['test']) | ||
| 34 | |||
| 35 | def reset_class class_name | ||
| 36 | ActiveRecord::Base.send(:include, Paperclip) | ||
| 37 | Object.send(:remove_const, class_name) rescue nil | ||
| 38 | klass = Object.const_set(class_name, Class.new(ActiveRecord::Base)) | ||
| 39 | klass.class_eval{ include Paperclip } | ||
| 40 | klass | ||
| 41 | end | ||
| 42 | |||
| 43 | def reset_table table_name, &block | ||
| 44 | block ||= lambda{ true } | ||
| 45 | ActiveRecord::Base.connection.create_table :dummies, {:force => true}, &block | ||
| 46 | end | ||
| 47 | |||
| 48 | def modify_table table_name, &block | ||
| 49 | ActiveRecord::Base.connection.change_table :dummies, &block | ||
| 50 | end | ||
| 51 | |||
| 52 | def rebuild_model options = {} | ||
| 53 | ActiveRecord::Base.connection.create_table :dummies, :force => true do |table| | ||
| 54 | table.column :other, :string | ||
| 55 | table.column :avatar_file_name, :string | ||
| 56 | table.column :avatar_content_type, :string | ||
| 57 | table.column :avatar_file_size, :integer | ||
| 58 | table.column :avatar_updated_at, :datetime | ||
| 59 | end | ||
| 60 | rebuild_class options | ||
| 61 | end | ||
| 62 | |||
| 63 | def rebuild_class options = {} | ||
| 64 | ActiveRecord::Base.send(:include, Paperclip) | ||
| 65 | Object.send(:remove_const, "Dummy") rescue nil | ||
| 66 | Object.const_set("Dummy", Class.new(ActiveRecord::Base)) | ||
| 67 | Dummy.class_eval do | ||
| 68 | include Paperclip | ||
| 69 | has_attached_file :avatar, options | ||
| 70 | end | ||
| 71 | end | ||
| 72 | |||
| 73 | def temporary_rails_env(new_env) | ||
| 74 | old_env = defined?(RAILS_ENV) ? RAILS_ENV : nil | ||
| 75 | silence_warnings do | ||
| 76 | Object.const_set("RAILS_ENV", new_env) | ||
| 77 | end | ||
| 78 | yield | ||
| 79 | silence_warnings do | ||
| 80 | Object.const_set("RAILS_ENV", old_env) | ||
| 81 | end | ||
| 82 | end | ||
diff --git a/vendor/plugins/paperclip/test/integration_test.rb b/vendor/plugins/paperclip/test/integration_test.rb deleted file mode 100644 index f7014ac..0000000 --- a/vendor/plugins/paperclip/test/integration_test.rb +++ /dev/null | |||
| @@ -1,481 +0,0 @@ | |||
| 1 | require 'test/helper' | ||
| 2 | |||
| 3 | class IntegrationTest < Test::Unit::TestCase | ||
| 4 | context "Many models at once" do | ||
| 5 | setup do | ||
| 6 | rebuild_model | ||
| 7 | @file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb') | ||
| 8 | 300.times do |i| | ||
| 9 | Dummy.create! :avatar => @file | ||
| 10 | end | ||
| 11 | end | ||
| 12 | |||
| 13 | should "not exceed the open file limit" do | ||
| 14 | assert_nothing_raised do | ||
| 15 | dummies = Dummy.find(:all) | ||
| 16 | dummies.each { |dummy| dummy.avatar } | ||
| 17 | end | ||
| 18 | end | ||
| 19 | end | ||
| 20 | |||
| 21 | context "An attachment" do | ||
| 22 | setup do | ||
| 23 | rebuild_model :styles => { :thumb => "50x50#" } | ||
| 24 | @dummy = Dummy.new | ||
| 25 | @file = File.new(File.join(File.dirname(__FILE__), | ||
| 26 | "fixtures", | ||
| 27 | "5k.png"), 'rb') | ||
| 28 | @dummy.avatar = @file | ||
| 29 | assert @dummy.save | ||
| 30 | end | ||
| 31 | |||
| 32 | teardown { @file.close } | ||
| 33 | |||
| 34 | should "create its thumbnails properly" do | ||
| 35 | assert_match /\b50x50\b/, `identify "#{@dummy.avatar.path(:thumb)}"` | ||
| 36 | end | ||
| 37 | |||
| 38 | context "redefining its attachment styles" do | ||
| 39 | setup do | ||
| 40 | Dummy.class_eval do | ||
| 41 | has_attached_file :avatar, :styles => { :thumb => "150x25#" } | ||
| 42 | has_attached_file :avatar, :styles => { :thumb => "150x25#", :dynamic => lambda { |a| '50x50#' } } | ||
| 43 | end | ||
| 44 | @d2 = Dummy.find(@dummy.id) | ||
| 45 | @d2.avatar.reprocess! | ||
| 46 | @d2.save | ||
| 47 | end | ||
| 48 | |||
| 49 | should "create its thumbnails properly" do | ||
| 50 | assert_match /\b150x25\b/, `identify "#{@dummy.avatar.path(:thumb)}"` | ||
| 51 | assert_match /\b50x50\b/, `identify "#{@dummy.avatar.path(:dynamic)}"` | ||
| 52 | end | ||
| 53 | end | ||
| 54 | end | ||
| 55 | |||
| 56 | context "A model that modifies its original" do | ||
| 57 | setup do | ||
| 58 | rebuild_model :styles => { :original => "2x2#" } | ||
| 59 | @dummy = Dummy.new | ||
| 60 | @file = File.new(File.join(File.dirname(__FILE__), | ||
| 61 | "fixtures", | ||
| 62 | "5k.png"), 'rb') | ||
| 63 | @dummy.avatar = @file | ||
| 64 | end | ||
| 65 | |||
| 66 | should "report the file size of the processed file and not the original" do | ||
| 67 | assert_not_equal @file.size, @dummy.avatar.size | ||
| 68 | end | ||
| 69 | |||
| 70 | teardown { @file.close } | ||
| 71 | end | ||
| 72 | |||
| 73 | context "A model with attachments scoped under an id" do | ||
| 74 | setup do | ||
| 75 | rebuild_model :styles => { :large => "100x100", | ||
| 76 | :medium => "50x50" }, | ||
| 77 | :path => ":rails_root/tmp/:id/:attachments/:style.:extension" | ||
| 78 | @dummy = Dummy.new | ||
| 79 | @file = File.new(File.join(File.dirname(__FILE__), | ||
| 80 | "fixtures", | ||
| 81 | "5k.png"), 'rb') | ||
| 82 | @dummy.avatar = @file | ||
| 83 | end | ||
| 84 | |||
| 85 | teardown { @file.close } | ||
| 86 | |||
| 87 | context "when saved" do | ||
| 88 | setup do | ||
| 89 | @dummy.save | ||
| 90 | @saved_path = @dummy.avatar.path(:large) | ||
| 91 | end | ||
| 92 | |||
| 93 | should "have a large file in the right place" do | ||
| 94 | assert File.exists?(@dummy.avatar.path(:large)) | ||
| 95 | end | ||
| 96 | |||
| 97 | context "and deleted" do | ||
| 98 | setup do | ||
| 99 | @dummy.avatar.clear | ||
| 100 | @dummy.save | ||
| 101 | end | ||
| 102 | |||
| 103 | should "not have a large file in the right place anymore" do | ||
| 104 | assert ! File.exists?(@saved_path) | ||
| 105 | end | ||
| 106 | |||
| 107 | should "not have its next two parent directories" do | ||
| 108 | assert ! File.exists?(File.dirname(@saved_path)) | ||
| 109 | assert ! File.exists?(File.dirname(File.dirname(@saved_path))) | ||
| 110 | end | ||
| 111 | |||
| 112 | before_should "not die if an unexpected SystemCallError happens" do | ||
| 113 | FileUtils.stubs(:rmdir).raises(Errno::EPIPE) | ||
| 114 | end | ||
| 115 | end | ||
| 116 | end | ||
| 117 | end | ||
| 118 | |||
| 119 | context "A model with no attachment validation" do | ||
| 120 | setup do | ||
| 121 | rebuild_model :styles => { :large => "300x300>", | ||
| 122 | :medium => "100x100", | ||
| 123 | :thumb => ["32x32#", :gif] }, | ||
| 124 | :default_style => :medium, | ||
| 125 | :url => "/:attachment/:class/:style/:id/:basename.:extension", | ||
| 126 | :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension" | ||
| 127 | @dummy = Dummy.new | ||
| 128 | end | ||
| 129 | |||
| 130 | should "have its definition return false when asked about whiny_thumbnails" do | ||
| 131 | assert ! Dummy.attachment_definitions[:avatar][:whiny_thumbnails] | ||
| 132 | end | ||
| 133 | |||
| 134 | context "when validates_attachment_thumbnails is called" do | ||
| 135 | setup do | ||
| 136 | Dummy.validates_attachment_thumbnails :avatar | ||
| 137 | end | ||
| 138 | |||
| 139 | should "have its definition return true when asked about whiny_thumbnails" do | ||
| 140 | assert_equal true, Dummy.attachment_definitions[:avatar][:whiny_thumbnails] | ||
| 141 | end | ||
| 142 | end | ||
| 143 | |||
| 144 | context "redefined to have attachment validations" do | ||
| 145 | setup do | ||
| 146 | rebuild_model :styles => { :large => "300x300>", | ||
| 147 | :medium => "100x100", | ||
| 148 | :thumb => ["32x32#", :gif] }, | ||
| 149 | :whiny_thumbnails => true, | ||
| 150 | :default_style => :medium, | ||
| 151 | :url => "/:attachment/:class/:style/:id/:basename.:extension", | ||
| 152 | :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension" | ||
| 153 | end | ||
| 154 | |||
| 155 | should "have its definition return true when asked about whiny_thumbnails" do | ||
| 156 | assert_equal true, Dummy.attachment_definitions[:avatar][:whiny_thumbnails] | ||
| 157 | end | ||
| 158 | end | ||
| 159 | end | ||
| 160 | |||
| 161 | context "A model with no convert_options setting" do | ||
| 162 | setup do | ||
| 163 | rebuild_model :styles => { :large => "300x300>", | ||
| 164 | :medium => "100x100", | ||
| 165 | :thumb => ["32x32#", :gif] }, | ||
| 166 | :default_style => :medium, | ||
| 167 | :url => "/:attachment/:class/:style/:id/:basename.:extension", | ||
| 168 | :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension" | ||
| 169 | @dummy = Dummy.new | ||
| 170 | end | ||
| 171 | |||
| 172 | should "have its definition return nil when asked about convert_options" do | ||
| 173 | assert ! Dummy.attachment_definitions[:avatar][:convert_options] | ||
| 174 | end | ||
| 175 | |||
| 176 | context "redefined to have convert_options setting" do | ||
| 177 | setup do | ||
| 178 | rebuild_model :styles => { :large => "300x300>", | ||
| 179 | :medium => "100x100", | ||
| 180 | :thumb => ["32x32#", :gif] }, | ||
| 181 | :convert_options => "-strip -depth 8", | ||
| 182 | :default_style => :medium, | ||
| 183 | :url => "/:attachment/:class/:style/:id/:basename.:extension", | ||
| 184 | :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension" | ||
| 185 | end | ||
| 186 | |||
| 187 | should "have its definition return convert_options value when asked about convert_options" do | ||
| 188 | assert_equal "-strip -depth 8", Dummy.attachment_definitions[:avatar][:convert_options] | ||
| 189 | end | ||
| 190 | end | ||
| 191 | end | ||
| 192 | |||
| 193 | context "A model with a filesystem attachment" do | ||
| 194 | setup do | ||
| 195 | rebuild_model :styles => { :large => "300x300>", | ||
| 196 | :medium => "100x100", | ||
| 197 | :thumb => ["32x32#", :gif] }, | ||
| 198 | :whiny_thumbnails => true, | ||
| 199 | :default_style => :medium, | ||
| 200 | :url => "/:attachment/:class/:style/:id/:basename.:extension", | ||
| 201 | :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension" | ||
| 202 | @dummy = Dummy.new | ||
| 203 | @file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb') | ||
| 204 | @bad_file = File.new(File.join(FIXTURES_DIR, "bad.png"), 'rb') | ||
| 205 | |||
| 206 | assert @dummy.avatar = @file | ||
| 207 | assert @dummy.valid? | ||
| 208 | assert @dummy.save | ||
| 209 | end | ||
| 210 | |||
| 211 | should "write and delete its files" do | ||
| 212 | [["434x66", :original], | ||
| 213 | ["300x46", :large], | ||
| 214 | ["100x15", :medium], | ||
| 215 | ["32x32", :thumb]].each do |geo, style| | ||
| 216 | cmd = %Q[identify -format "%wx%h" "#{@dummy.avatar.path(style)}"] | ||
| 217 | assert_equal geo, `#{cmd}`.chomp, cmd | ||
| 218 | end | ||
| 219 | |||
| 220 | saved_paths = [:thumb, :medium, :large, :original].collect{|s| @dummy.avatar.path(s) } | ||
| 221 | |||
| 222 | @d2 = Dummy.find(@dummy.id) | ||
| 223 | assert_equal "100x15", `identify -format "%wx%h" "#{@d2.avatar.path}"`.chomp | ||
| 224 | assert_equal "434x66", `identify -format "%wx%h" "#{@d2.avatar.path(:original)}"`.chomp | ||
| 225 | assert_equal "300x46", `identify -format "%wx%h" "#{@d2.avatar.path(:large)}"`.chomp | ||
| 226 | assert_equal "100x15", `identify -format "%wx%h" "#{@d2.avatar.path(:medium)}"`.chomp | ||
| 227 | assert_equal "32x32", `identify -format "%wx%h" "#{@d2.avatar.path(:thumb)}"`.chomp | ||
| 228 | |||
| 229 | @dummy.avatar = "not a valid file but not nil" | ||
| 230 | assert_equal File.basename(@file.path), @dummy.avatar_file_name | ||
| 231 | assert @dummy.valid? | ||
| 232 | assert @dummy.save | ||
| 233 | |||
| 234 | saved_paths.each do |p| | ||
| 235 | assert File.exists?(p) | ||
| 236 | end | ||
| 237 | |||
| 238 | @dummy.avatar.clear | ||
| 239 | assert_nil @dummy.avatar_file_name | ||
| 240 | assert @dummy.valid? | ||
| 241 | assert @dummy.save | ||
| 242 | |||
| 243 | saved_paths.each do |p| | ||
| 244 | assert ! File.exists?(p) | ||
| 245 | end | ||
| 246 | |||
| 247 | @d2 = Dummy.find(@dummy.id) | ||
| 248 | assert_nil @d2.avatar_file_name | ||
| 249 | end | ||
| 250 | |||
| 251 | should "work exactly the same when new as when reloaded" do | ||
| 252 | @d2 = Dummy.find(@dummy.id) | ||
| 253 | |||
| 254 | assert_equal @dummy.avatar_file_name, @d2.avatar_file_name | ||
| 255 | [:thumb, :medium, :large, :original].each do |style| | ||
| 256 | assert_equal @dummy.avatar.path(style), @d2.avatar.path(style) | ||
| 257 | end | ||
| 258 | |||
| 259 | saved_paths = [:thumb, :medium, :large, :original].collect{|s| @dummy.avatar.path(s) } | ||
| 260 | |||
| 261 | @d2.avatar.clear | ||
| 262 | assert @d2.save | ||
| 263 | |||
| 264 | saved_paths.each do |p| | ||
| 265 | assert ! File.exists?(p) | ||
| 266 | end | ||
| 267 | end | ||
| 268 | |||
| 269 | should "know the difference between good files, bad files, and not files" do | ||
| 270 | expected = @dummy.avatar.to_file | ||
| 271 | @dummy.avatar = "not a file" | ||
| 272 | assert @dummy.valid? | ||
| 273 | assert_equal expected.path, @dummy.avatar.path | ||
| 274 | expected.close | ||
| 275 | |||
| 276 | @dummy.avatar = @bad_file | ||
| 277 | assert ! @dummy.valid? | ||
| 278 | end | ||
| 279 | |||
| 280 | should "know the difference between good files, bad files, and not files when validating" do | ||
| 281 | Dummy.validates_attachment_presence :avatar | ||
| 282 | @d2 = Dummy.find(@dummy.id) | ||
| 283 | @d2.avatar = @file | ||
| 284 | assert @d2.valid?, @d2.errors.full_messages.inspect | ||
| 285 | @d2.avatar = @bad_file | ||
| 286 | assert ! @d2.valid? | ||
| 287 | end | ||
| 288 | |||
| 289 | should "be able to reload without saving and not have the file disappear" do | ||
| 290 | @dummy.avatar = @file | ||
| 291 | assert @dummy.save | ||
| 292 | @dummy.avatar.clear | ||
| 293 | assert_nil @dummy.avatar_file_name | ||
| 294 | @dummy.reload | ||
| 295 | assert_equal "5k.png", @dummy.avatar_file_name | ||
| 296 | end | ||
| 297 | |||
| 298 | context "that is assigned its file from another Paperclip attachment" do | ||
| 299 | setup do | ||
| 300 | @dummy2 = Dummy.new | ||
| 301 | @file2 = File.new(File.join(FIXTURES_DIR, "12k.png"), 'rb') | ||
| 302 | assert @dummy2.avatar = @file2 | ||
| 303 | @dummy2.save | ||
| 304 | end | ||
| 305 | |||
| 306 | should "work when assigned a file" do | ||
| 307 | assert_not_equal `identify -format "%wx%h" "#{@dummy.avatar.path(:original)}"`, | ||
| 308 | `identify -format "%wx%h" "#{@dummy2.avatar.path(:original)}"` | ||
| 309 | |||
| 310 | assert @dummy.avatar = @dummy2.avatar | ||
| 311 | @dummy.save | ||
| 312 | assert_equal `identify -format "%wx%h" "#{@dummy.avatar.path(:original)}"`, | ||
| 313 | `identify -format "%wx%h" "#{@dummy2.avatar.path(:original)}"` | ||
| 314 | end | ||
| 315 | end | ||
| 316 | |||
| 317 | end | ||
| 318 | |||
| 319 | context "A model with an attachments association and a Paperclip attachment" do | ||
| 320 | setup do | ||
| 321 | Dummy.class_eval do | ||
| 322 | has_many :attachments, :class_name => 'Dummy' | ||
| 323 | end | ||
| 324 | |||
| 325 | @dummy = Dummy.new | ||
| 326 | @dummy.avatar = File.new(File.join(File.dirname(__FILE__), | ||
| 327 | "fixtures", | ||
| 328 | "5k.png"), 'rb') | ||
| 329 | end | ||
| 330 | |||
| 331 | should "should not error when saving" do | ||
| 332 | assert_nothing_raised do | ||
| 333 | @dummy.save! | ||
| 334 | end | ||
| 335 | end | ||
| 336 | end | ||
| 337 | |||
| 338 | if ENV['S3_TEST_BUCKET'] | ||
| 339 | def s3_files_for attachment | ||
| 340 | [:thumb, :medium, :large, :original].inject({}) do |files, style| | ||
| 341 | data = `curl "#{attachment.url(style)}" 2>/dev/null`.chomp | ||
| 342 | t = Tempfile.new("paperclip-test") | ||
| 343 | t.binmode | ||
| 344 | t.write(data) | ||
| 345 | t.rewind | ||
| 346 | files[style] = t | ||
| 347 | files | ||
| 348 | end | ||
| 349 | end | ||
| 350 | |||
| 351 | def s3_headers_for attachment, style | ||
| 352 | `curl --head "#{attachment.url(style)}" 2>/dev/null`.split("\n").inject({}) do |h,head| | ||
| 353 | split_head = head.chomp.split(/\s*:\s*/, 2) | ||
| 354 | h[split_head.first.downcase] = split_head.last unless split_head.empty? | ||
| 355 | h | ||
| 356 | end | ||
| 357 | end | ||
| 358 | |||
| 359 | context "A model with an S3 attachment" do | ||
| 360 | setup do | ||
| 361 | rebuild_model :styles => { :large => "300x300>", | ||
| 362 | :medium => "100x100", | ||
| 363 | :thumb => ["32x32#", :gif] }, | ||
| 364 | :storage => :s3, | ||
| 365 | :whiny_thumbnails => true, | ||
| 366 | # :s3_options => {:logger => Logger.new(StringIO.new)}, | ||
| 367 | :s3_credentials => File.new(File.join(File.dirname(__FILE__), "s3.yml")), | ||
| 368 | :default_style => :medium, | ||
| 369 | :bucket => ENV['S3_TEST_BUCKET'], | ||
| 370 | :path => ":class/:attachment/:id/:style/:basename.:extension" | ||
| 371 | @dummy = Dummy.new | ||
| 372 | @file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb') | ||
| 373 | @bad_file = File.new(File.join(FIXTURES_DIR, "bad.png"), 'rb') | ||
| 374 | |||
| 375 | assert @dummy.avatar = @file | ||
| 376 | assert @dummy.valid? | ||
| 377 | assert @dummy.save | ||
| 378 | |||
| 379 | @files_on_s3 = s3_files_for @dummy.avatar | ||
| 380 | end | ||
| 381 | |||
| 382 | should "write and delete its files" do | ||
| 383 | [["434x66", :original], | ||
| 384 | ["300x46", :large], | ||
| 385 | ["100x15", :medium], | ||
| 386 | ["32x32", :thumb]].each do |geo, style| | ||
| 387 | cmd = %Q[identify -format "%wx%h" "#{@files_on_s3[style].path}"] | ||
| 388 | assert_equal geo, `#{cmd}`.chomp, cmd | ||
| 389 | end | ||
| 390 | |||
| 391 | @d2 = Dummy.find(@dummy.id) | ||
| 392 | @d2_files = s3_files_for @d2.avatar | ||
| 393 | [["434x66", :original], | ||
| 394 | ["300x46", :large], | ||
| 395 | ["100x15", :medium], | ||
| 396 | ["32x32", :thumb]].each do |geo, style| | ||
| 397 | cmd = %Q[identify -format "%wx%h" "#{@d2_files[style].path}"] | ||
| 398 | assert_equal geo, `#{cmd}`.chomp, cmd | ||
| 399 | end | ||
| 400 | |||
| 401 | @dummy.avatar = "not a valid file but not nil" | ||
| 402 | assert_equal File.basename(@file.path), @dummy.avatar_file_name | ||
| 403 | assert @dummy.valid? | ||
| 404 | assert @dummy.save | ||
| 405 | |||
| 406 | saved_keys = [:thumb, :medium, :large, :original].collect{|s| @dummy.avatar.to_file(s) } | ||
| 407 | |||
| 408 | saved_keys.each do |key| | ||
| 409 | assert key.exists? | ||
| 410 | end | ||
| 411 | |||
| 412 | @dummy.avatar.clear | ||
| 413 | assert_nil @dummy.avatar_file_name | ||
| 414 | assert @dummy.valid? | ||
| 415 | assert @dummy.save | ||
| 416 | |||
| 417 | saved_keys.each do |key| | ||
| 418 | assert ! key.exists? | ||
| 419 | end | ||
| 420 | |||
| 421 | @d2 = Dummy.find(@dummy.id) | ||
| 422 | assert_nil @d2.avatar_file_name | ||
| 423 | end | ||
| 424 | |||
| 425 | should "work exactly the same when new as when reloaded" do | ||
| 426 | @d2 = Dummy.find(@dummy.id) | ||
| 427 | |||
| 428 | assert_equal @dummy.avatar_file_name, @d2.avatar_file_name | ||
| 429 | [:thumb, :medium, :large, :original].each do |style| | ||
| 430 | assert_equal @dummy.avatar.to_file(style).to_s, @d2.avatar.to_file(style).to_s | ||
| 431 | end | ||
| 432 | |||
| 433 | saved_keys = [:thumb, :medium, :large, :original].collect{|s| @dummy.avatar.to_file(s) } | ||
| 434 | |||
| 435 | @d2.avatar.clear | ||
| 436 | assert @d2.save | ||
| 437 | |||
| 438 | saved_keys.each do |key| | ||
| 439 | assert ! key.exists? | ||
| 440 | end | ||
| 441 | end | ||
| 442 | |||
| 443 | should "know the difference between good files, bad files, not files, and nil" do | ||
| 444 | expected = @dummy.avatar.to_file | ||
| 445 | @dummy.avatar = "not a file" | ||
| 446 | assert @dummy.valid? | ||
| 447 | assert_equal expected.full_name, @dummy.avatar.to_file.full_name | ||
| 448 | |||
| 449 | @dummy.avatar = @bad_file | ||
| 450 | assert ! @dummy.valid? | ||
| 451 | @dummy.avatar = nil | ||
| 452 | assert @dummy.valid? | ||
| 453 | |||
| 454 | Dummy.validates_attachment_presence :avatar | ||
| 455 | @d2 = Dummy.find(@dummy.id) | ||
| 456 | @d2.avatar = @file | ||
| 457 | assert @d2.valid? | ||
| 458 | @d2.avatar = @bad_file | ||
| 459 | assert ! @d2.valid? | ||
| 460 | @d2.avatar = nil | ||
| 461 | assert ! @d2.valid? | ||
| 462 | end | ||
| 463 | |||
| 464 | should "be able to reload without saving and not have the file disappear" do | ||
| 465 | @dummy.avatar = @file | ||
| 466 | assert @dummy.save | ||
| 467 | @dummy.avatar = nil | ||
| 468 | assert_nil @dummy.avatar_file_name | ||
| 469 | @dummy.reload | ||
| 470 | assert_equal "5k.png", @dummy.avatar_file_name | ||
| 471 | end | ||
| 472 | |||
| 473 | should "have the right content type" do | ||
| 474 | headers = s3_headers_for(@dummy.avatar, :original) | ||
| 475 | p headers | ||
| 476 | assert_equal 'image/png', headers['content-type'] | ||
| 477 | end | ||
| 478 | end | ||
| 479 | end | ||
| 480 | end | ||
| 481 | |||
diff --git a/vendor/plugins/paperclip/test/iostream_test.rb b/vendor/plugins/paperclip/test/iostream_test.rb deleted file mode 100644 index 97030b5..0000000 --- a/vendor/plugins/paperclip/test/iostream_test.rb +++ /dev/null | |||
| @@ -1,71 +0,0 @@ | |||
| 1 | require 'test/helper' | ||
| 2 | |||
| 3 | class IOStreamTest < Test::Unit::TestCase | ||
| 4 | context "IOStream" do | ||
| 5 | should "be included in IO, File, Tempfile, and StringIO" do | ||
| 6 | [IO, File, Tempfile, StringIO].each do |klass| | ||
| 7 | assert klass.included_modules.include?(IOStream), "Not in #{klass}" | ||
| 8 | end | ||
| 9 | end | ||
| 10 | end | ||
| 11 | |||
| 12 | context "A file" do | ||
| 13 | setup do | ||
| 14 | @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb') | ||
| 15 | end | ||
| 16 | |||
| 17 | teardown { @file.close } | ||
| 18 | |||
| 19 | context "that is sent #stream_to" do | ||
| 20 | |||
| 21 | context "and given a String" do | ||
| 22 | setup do | ||
| 23 | FileUtils.mkdir_p(File.join(ROOT, 'tmp')) | ||
| 24 | assert @result = @file.stream_to(File.join(ROOT, 'tmp', 'iostream.string.test')) | ||
| 25 | end | ||
| 26 | |||
| 27 | should "return a File" do | ||
| 28 | assert @result.is_a?(File) | ||
| 29 | end | ||
| 30 | |||
| 31 | should "contain the same data as the original file" do | ||
| 32 | @file.rewind; @result.rewind | ||
| 33 | assert_equal @file.read, @result.read | ||
| 34 | end | ||
| 35 | end | ||
| 36 | |||
| 37 | context "and given a Tempfile" do | ||
| 38 | setup do | ||
| 39 | tempfile = Tempfile.new('iostream.test') | ||
| 40 | tempfile.binmode | ||
| 41 | assert @result = @file.stream_to(tempfile) | ||
| 42 | end | ||
| 43 | |||
| 44 | should "return a Tempfile" do | ||
| 45 | assert @result.is_a?(Tempfile) | ||
| 46 | end | ||
| 47 | |||
| 48 | should "contain the same data as the original file" do | ||
| 49 | @file.rewind; @result.rewind | ||
| 50 | assert_equal @file.read, @result.read | ||
| 51 | end | ||
| 52 | end | ||
| 53 | |||
| 54 | end | ||
| 55 | |||
| 56 | context "that is sent #to_tempfile" do | ||
| 57 | setup do | ||
| 58 | assert @tempfile = @file.to_tempfile | ||
| 59 | end | ||
| 60 | |||
| 61 | should "convert it to a Tempfile" do | ||
| 62 | assert @tempfile.is_a?(Tempfile) | ||
| 63 | end | ||
| 64 | |||
| 65 | should "have the Tempfile contain the same data as the file" do | ||
| 66 | @file.rewind; @tempfile.rewind | ||
| 67 | assert_equal @file.read, @tempfile.read | ||
| 68 | end | ||
| 69 | end | ||
| 70 | end | ||
| 71 | end | ||
diff --git a/vendor/plugins/paperclip/test/matchers/have_attached_file_matcher_test.rb b/vendor/plugins/paperclip/test/matchers/have_attached_file_matcher_test.rb deleted file mode 100644 index b29ec37..0000000 --- a/vendor/plugins/paperclip/test/matchers/have_attached_file_matcher_test.rb +++ /dev/null | |||
| @@ -1,21 +0,0 @@ | |||
| 1 | require 'test/helper' | ||
| 2 | |||
| 3 | class HaveAttachedFileMatcherTest < Test::Unit::TestCase | ||
| 4 | context "have_attached_file" do | ||
| 5 | setup do | ||
| 6 | @dummy_class = reset_class "Dummy" | ||
| 7 | reset_table "dummies" | ||
| 8 | @matcher = self.class.have_attached_file(:avatar) | ||
| 9 | end | ||
| 10 | |||
| 11 | should "reject a class with no attachment" do | ||
| 12 | assert_rejects @matcher, @dummy_class | ||
| 13 | end | ||
| 14 | |||
| 15 | should "accept a class with an attachment" do | ||
| 16 | modify_table("dummies"){|d| d.string :avatar_file_name } | ||
| 17 | @dummy_class.has_attached_file :avatar | ||
| 18 | assert_accepts @matcher, @dummy_class | ||
| 19 | end | ||
| 20 | end | ||
| 21 | end | ||
diff --git a/vendor/plugins/paperclip/test/matchers/validate_attachment_content_type_matcher_test.rb b/vendor/plugins/paperclip/test/matchers/validate_attachment_content_type_matcher_test.rb deleted file mode 100644 index 241eb5f..0000000 --- a/vendor/plugins/paperclip/test/matchers/validate_attachment_content_type_matcher_test.rb +++ /dev/null | |||
| @@ -1,30 +0,0 @@ | |||
| 1 | require 'test/helper' | ||
| 2 | |||
| 3 | class ValidateAttachmentContentTypeMatcherTest < Test::Unit::TestCase | ||
| 4 | context "validate_attachment_content_type" do | ||
| 5 | setup do | ||
| 6 | reset_table("dummies") do |d| | ||
| 7 | d.string :avatar_file_name | ||
| 8 | end | ||
| 9 | @dummy_class = reset_class "Dummy" | ||
| 10 | @dummy_class.has_attached_file :avatar | ||
| 11 | @matcher = self.class.validate_attachment_content_type(:avatar). | ||
| 12 | allowing(%w(image/png image/jpeg)). | ||
| 13 | rejecting(%w(audio/mp3 application/octet-stream)) | ||
| 14 | end | ||
| 15 | |||
| 16 | should "reject a class with no validation" do | ||
| 17 | assert_rejects @matcher, @dummy_class | ||
| 18 | end | ||
| 19 | |||
| 20 | should "reject a class with a validation that doesn't match" do | ||
| 21 | @dummy_class.validates_attachment_content_type :avatar, :content_type => %r{audio/.*} | ||
| 22 | assert_rejects @matcher, @dummy_class | ||
| 23 | end | ||
| 24 | |||
| 25 | should "accept a class with a validation" do | ||
| 26 | @dummy_class.validates_attachment_content_type :avatar, :content_type => %r{image/.*} | ||
| 27 | assert_accepts @matcher, @dummy_class | ||
| 28 | end | ||
| 29 | end | ||
| 30 | end | ||
diff --git a/vendor/plugins/paperclip/test/matchers/validate_attachment_presence_matcher_test.rb b/vendor/plugins/paperclip/test/matchers/validate_attachment_presence_matcher_test.rb deleted file mode 100644 index 860a760..0000000 --- a/vendor/plugins/paperclip/test/matchers/validate_attachment_presence_matcher_test.rb +++ /dev/null | |||
| @@ -1,21 +0,0 @@ | |||
| 1 | require 'test/helper' | ||
| 2 | |||
| 3 | class ValidateAttachmentPresenceMatcherTest < Test::Unit::TestCase | ||
| 4 | context "validate_attachment_presence" do | ||
| 5 | setup do | ||
| 6 | reset_table("dummies"){|d| d.string :avatar_file_name } | ||
| 7 | @dummy_class = reset_class "Dummy" | ||
| 8 | @dummy_class.has_attached_file :avatar | ||
| 9 | @matcher = self.class.validate_attachment_presence(:avatar) | ||
| 10 | end | ||
| 11 | |||
| 12 | should "reject a class with no validation" do | ||
| 13 | assert_rejects @matcher, @dummy_class | ||
| 14 | end | ||
| 15 | |||
| 16 | should "accept a class with a validation" do | ||
| 17 | @dummy_class.validates_attachment_presence :avatar | ||
| 18 | assert_accepts @matcher, @dummy_class | ||
| 19 | end | ||
| 20 | end | ||
| 21 | end | ||
diff --git a/vendor/plugins/paperclip/test/matchers/validate_attachment_size_matcher_test.rb b/vendor/plugins/paperclip/test/matchers/validate_attachment_size_matcher_test.rb deleted file mode 100644 index 7e4c9b4..0000000 --- a/vendor/plugins/paperclip/test/matchers/validate_attachment_size_matcher_test.rb +++ /dev/null | |||
| @@ -1,50 +0,0 @@ | |||
| 1 | require 'test/helper' | ||
| 2 | |||
| 3 | class ValidateAttachmentSizeMatcherTest < Test::Unit::TestCase | ||
| 4 | context "validate_attachment_size" do | ||
| 5 | setup do | ||
| 6 | reset_table("dummies") do |d| | ||
| 7 | d.string :avatar_file_name | ||
| 8 | end | ||
| 9 | @dummy_class = reset_class "Dummy" | ||
| 10 | @dummy_class.has_attached_file :avatar | ||
| 11 | end | ||
| 12 | |||
| 13 | context "of limited size" do | ||
| 14 | setup{ @matcher = self.class.validate_attachment_size(:avatar).in(256..1024) } | ||
| 15 | |||
| 16 | should "reject a class with no validation" do | ||
| 17 | assert_rejects @matcher, @dummy_class | ||
| 18 | end | ||
| 19 | |||
| 20 | should "reject a class with a validation that's too high" do | ||
| 21 | @dummy_class.validates_attachment_size :avatar, :in => 256..2048 | ||
| 22 | assert_rejects @matcher, @dummy_class | ||
| 23 | end | ||
| 24 | |||
| 25 | should "reject a class with a validation that's too low" do | ||
| 26 | @dummy_class.validates_attachment_size :avatar, :in => 0..1024 | ||
| 27 | assert_rejects @matcher, @dummy_class | ||
| 28 | end | ||
| 29 | |||
| 30 | should "accept a class with a validation that matches" do | ||
| 31 | @dummy_class.validates_attachment_size :avatar, :in => 256..1024 | ||
| 32 | assert_accepts @matcher, @dummy_class | ||
| 33 | end | ||
| 34 | end | ||
| 35 | |||
| 36 | context "validates_attachment_size with infinite range" do | ||
| 37 | setup{ @matcher = self.class.validate_attachment_size(:avatar) } | ||
| 38 | |||
| 39 | should "accept a class with an upper limit" do | ||
| 40 | @dummy_class.validates_attachment_size :avatar, :less_than => 1 | ||
| 41 | assert_accepts @matcher, @dummy_class | ||
| 42 | end | ||
| 43 | |||
| 44 | should "accept a class with no upper limit" do | ||
| 45 | @dummy_class.validates_attachment_size :avatar, :greater_than => 1 | ||
| 46 | assert_accepts @matcher, @dummy_class | ||
| 47 | end | ||
| 48 | end | ||
| 49 | end | ||
| 50 | end | ||
diff --git a/vendor/plugins/paperclip/test/paperclip_test.rb b/vendor/plugins/paperclip/test/paperclip_test.rb deleted file mode 100644 index 8365649..0000000 --- a/vendor/plugins/paperclip/test/paperclip_test.rb +++ /dev/null | |||
| @@ -1,233 +0,0 @@ | |||
| 1 | require 'test/helper' | ||
| 2 | |||
| 3 | class PaperclipTest < Test::Unit::TestCase | ||
| 4 | [:image_magick_path, :convert_path].each do |path| | ||
| 5 | context "Calling Paperclip.run with an #{path} specified" do | ||
| 6 | setup do | ||
| 7 | Paperclip.options[:image_magick_path] = nil | ||
| 8 | Paperclip.options[:convert_path] = nil | ||
| 9 | Paperclip.options[path] = "/usr/bin" | ||
| 10 | end | ||
| 11 | |||
| 12 | should "execute the right command" do | ||
| 13 | Paperclip.expects(:path_for_command).with("convert").returns("/usr/bin/convert") | ||
| 14 | Paperclip.expects(:bit_bucket).returns("/dev/null") | ||
| 15 | Paperclip.expects(:"`").with("/usr/bin/convert one.jpg two.jpg 2>/dev/null") | ||
| 16 | Paperclip.run("convert", "one.jpg two.jpg") | ||
| 17 | end | ||
| 18 | end | ||
| 19 | end | ||
| 20 | |||
| 21 | context "Calling Paperclip.run with no path specified" do | ||
| 22 | setup do | ||
| 23 | Paperclip.options[:image_magick_path] = nil | ||
| 24 | Paperclip.options[:convert_path] = nil | ||
| 25 | end | ||
| 26 | |||
| 27 | should "execute the right command" do | ||
| 28 | Paperclip.expects(:path_for_command).with("convert").returns("convert") | ||
| 29 | Paperclip.expects(:bit_bucket).returns("/dev/null") | ||
| 30 | Paperclip.expects(:"`").with("convert one.jpg two.jpg 2>/dev/null") | ||
| 31 | Paperclip.run("convert", "one.jpg two.jpg") | ||
| 32 | end | ||
| 33 | end | ||
| 34 | |||
| 35 | should "raise when sent #processor and the name of a class that exists but isn't a subclass of Processor" do | ||
| 36 | assert_raises(Paperclip::PaperclipError){ Paperclip.processor(:attachment) } | ||
| 37 | end | ||
| 38 | |||
| 39 | should "raise when sent #processor and the name of a class that doesn't exist" do | ||
| 40 | assert_raises(NameError){ Paperclip.processor(:boogey_man) } | ||
| 41 | end | ||
| 42 | |||
| 43 | should "return a class when sent #processor and the name of a class under Paperclip" do | ||
| 44 | assert_equal ::Paperclip::Thumbnail, Paperclip.processor(:thumbnail) | ||
| 45 | end | ||
| 46 | |||
| 47 | context "Paperclip.bit_bucket" do | ||
| 48 | context "on systems without /dev/null" do | ||
| 49 | setup do | ||
| 50 | File.expects(:exists?).with("/dev/null").returns(false) | ||
| 51 | end | ||
| 52 | |||
| 53 | should "return 'NUL'" do | ||
| 54 | assert_equal "NUL", Paperclip.bit_bucket | ||
| 55 | end | ||
| 56 | end | ||
| 57 | |||
| 58 | context "on systems with /dev/null" do | ||
| 59 | setup do | ||
| 60 | File.expects(:exists?).with("/dev/null").returns(true) | ||
| 61 | end | ||
| 62 | |||
| 63 | should "return '/dev/null'" do | ||
| 64 | assert_equal "/dev/null", Paperclip.bit_bucket | ||
| 65 | end | ||
| 66 | end | ||
| 67 | end | ||
| 68 | |||
| 69 | context "An ActiveRecord model with an 'avatar' attachment" do | ||
| 70 | setup do | ||
| 71 | rebuild_model :path => "tmp/:class/omg/:style.:extension" | ||
| 72 | @file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb') | ||
| 73 | end | ||
| 74 | |||
| 75 | teardown { @file.close } | ||
| 76 | |||
| 77 | should "not error when trying to also create a 'blah' attachment" do | ||
| 78 | assert_nothing_raised do | ||
| 79 | Dummy.class_eval do | ||
| 80 | has_attached_file :blah | ||
| 81 | end | ||
| 82 | end | ||
| 83 | end | ||
| 84 | |||
| 85 | context "that is attr_protected" do | ||
| 86 | setup do | ||
| 87 | Dummy.class_eval do | ||
| 88 | attr_protected :avatar | ||
| 89 | end | ||
| 90 | @dummy = Dummy.new | ||
| 91 | end | ||
| 92 | |||
| 93 | should "not assign the avatar on mass-set" do | ||
| 94 | @dummy.attributes = { :other => "I'm set!", | ||
| 95 | :avatar => @file } | ||
| 96 | |||
| 97 | assert_equal "I'm set!", @dummy.other | ||
| 98 | assert ! @dummy.avatar? | ||
| 99 | end | ||
| 100 | |||
| 101 | should "still allow assigment on normal set" do | ||
| 102 | @dummy.other = "I'm set!" | ||
| 103 | @dummy.avatar = @file | ||
| 104 | |||
| 105 | assert_equal "I'm set!", @dummy.other | ||
| 106 | assert @dummy.avatar? | ||
| 107 | end | ||
| 108 | end | ||
| 109 | |||
| 110 | context "with a subclass" do | ||
| 111 | setup do | ||
| 112 | class ::SubDummy < Dummy; end | ||
| 113 | end | ||
| 114 | |||
| 115 | should "be able to use the attachment from the subclass" do | ||
| 116 | assert_nothing_raised do | ||
| 117 | @subdummy = SubDummy.create(:avatar => @file) | ||
| 118 | end | ||
| 119 | end | ||
| 120 | |||
| 121 | should "be able to see the attachment definition from the subclass's class" do | ||
| 122 | assert_equal "tmp/:class/omg/:style.:extension", SubDummy.attachment_definitions[:avatar][:path] | ||
| 123 | end | ||
| 124 | |||
| 125 | teardown do | ||
| 126 | Object.send(:remove_const, "SubDummy") rescue nil | ||
| 127 | end | ||
| 128 | end | ||
| 129 | |||
| 130 | should "have an #avatar method" do | ||
| 131 | assert Dummy.new.respond_to?(:avatar) | ||
| 132 | end | ||
| 133 | |||
| 134 | should "have an #avatar= method" do | ||
| 135 | assert Dummy.new.respond_to?(:avatar=) | ||
| 136 | end | ||
| 137 | |||
| 138 | context "that is valid" do | ||
| 139 | setup do | ||
| 140 | @dummy = Dummy.new | ||
| 141 | @dummy.avatar = @file | ||
| 142 | end | ||
| 143 | |||
| 144 | should "be valid" do | ||
| 145 | assert @dummy.valid? | ||
| 146 | end | ||
| 147 | |||
| 148 | context "then has a validation added that makes it invalid" do | ||
| 149 | setup do | ||
| 150 | assert @dummy.save | ||
| 151 | Dummy.class_eval do | ||
| 152 | validates_attachment_content_type :avatar, :content_type => ["text/plain"] | ||
| 153 | end | ||
| 154 | @dummy2 = Dummy.find(@dummy.id) | ||
| 155 | end | ||
| 156 | |||
| 157 | should "be invalid when reloaded" do | ||
| 158 | assert ! @dummy2.valid?, @dummy2.errors.inspect | ||
| 159 | end | ||
| 160 | |||
| 161 | should "be able to call #valid? twice without having duplicate errors" do | ||
| 162 | @dummy2.avatar.valid? | ||
| 163 | first_errors = @dummy2.avatar.errors | ||
| 164 | @dummy2.avatar.valid? | ||
| 165 | assert_equal first_errors, @dummy2.avatar.errors | ||
| 166 | end | ||
| 167 | end | ||
| 168 | end | ||
| 169 | |||
| 170 | def self.should_validate validation, options, valid_file, invalid_file | ||
| 171 | context "with #{validation} validation and #{options.inspect} options" do | ||
| 172 | setup do | ||
| 173 | Dummy.send(:"validates_attachment_#{validation}", :avatar, options) | ||
| 174 | @dummy = Dummy.new | ||
| 175 | end | ||
| 176 | context "and assigning nil" do | ||
| 177 | setup do | ||
| 178 | @dummy.avatar = nil | ||
| 179 | @dummy.valid? | ||
| 180 | end | ||
| 181 | if validation == :presence | ||
| 182 | should "have an error on the attachment" do | ||
| 183 | assert @dummy.errors.on(:avatar) | ||
| 184 | end | ||
| 185 | else | ||
| 186 | should "not have an error on the attachment" do | ||
| 187 | assert_nil @dummy.errors.on(:avatar) | ||
| 188 | end | ||
| 189 | end | ||
| 190 | end | ||
| 191 | context "and assigned a valid file" do | ||
| 192 | setup do | ||
| 193 | @dummy.avatar = valid_file | ||
| 194 | @dummy.valid? | ||
| 195 | end | ||
| 196 | should "not have an error when assigned a valid file" do | ||
| 197 | assert ! @dummy.avatar.errors.key?(validation) | ||
| 198 | end | ||
| 199 | should "not have an error on the attachment" do | ||
| 200 | assert_nil @dummy.errors.on(:avatar) | ||
| 201 | end | ||
| 202 | end | ||
| 203 | context "and assigned an invalid file" do | ||
| 204 | setup do | ||
| 205 | @dummy.avatar = invalid_file | ||
| 206 | @dummy.valid? | ||
| 207 | end | ||
| 208 | should "have an error when assigned a valid file" do | ||
| 209 | assert_not_nil @dummy.avatar.errors[validation] | ||
| 210 | end | ||
| 211 | should "have an error on the attachment" do | ||
| 212 | assert @dummy.errors.on(:avatar) | ||
| 213 | end | ||
| 214 | end | ||
| 215 | end | ||
| 216 | end | ||
| 217 | |||
| 218 | [[:presence, {}, "5k.png", nil], | ||
| 219 | [:size, {:in => 1..10240}, nil, "12k.png"], | ||
| 220 | [:size, {:less_than => 10240}, "5k.png", "12k.png"], | ||
| 221 | [:size, {:greater_than => 8096}, "12k.png", "5k.png"], | ||
| 222 | [:content_type, {:content_type => "image/png"}, "5k.png", "text.txt"], | ||
| 223 | [:content_type, {:content_type => "text/plain"}, "text.txt", "5k.png"], | ||
| 224 | [:content_type, {:content_type => %r{image/.*}}, "5k.png", "text.txt"]].each do |args| | ||
| 225 | validation, options, valid_file, invalid_file = args | ||
| 226 | valid_file &&= File.open(File.join(FIXTURES_DIR, valid_file), "rb") | ||
| 227 | invalid_file &&= File.open(File.join(FIXTURES_DIR, invalid_file), "rb") | ||
| 228 | |||
| 229 | should_validate validation, options, valid_file, invalid_file | ||
| 230 | end | ||
| 231 | |||
| 232 | end | ||
| 233 | end | ||
diff --git a/vendor/plugins/paperclip/test/processor_test.rb b/vendor/plugins/paperclip/test/processor_test.rb deleted file mode 100644 index a05f0a9..0000000 --- a/vendor/plugins/paperclip/test/processor_test.rb +++ /dev/null | |||
| @@ -1,10 +0,0 @@ | |||
| 1 | require 'test/helper' | ||
| 2 | |||
| 3 | class ProcessorTest < Test::Unit::TestCase | ||
| 4 | should "instantiate and call #make when sent #make to the class" do | ||
| 5 | processor = mock | ||
| 6 | processor.expects(:make).with() | ||
| 7 | Paperclip::Processor.expects(:new).with(:one, :two, :three).returns(processor) | ||
| 8 | Paperclip::Processor.make(:one, :two, :three) | ||
| 9 | end | ||
| 10 | end | ||
diff --git a/vendor/plugins/paperclip/test/storage_test.rb b/vendor/plugins/paperclip/test/storage_test.rb deleted file mode 100644 index e2ed8a4..0000000 --- a/vendor/plugins/paperclip/test/storage_test.rb +++ /dev/null | |||
| @@ -1,277 +0,0 @@ | |||
| 1 | require 'test/helper' | ||
| 2 | |||
| 3 | class StorageTest < Test::Unit::TestCase | ||
| 4 | context "Parsing S3 credentials" do | ||
| 5 | setup do | ||
| 6 | rebuild_model :storage => :s3, | ||
| 7 | :bucket => "testing", | ||
| 8 | :s3_credentials => {:not => :important} | ||
| 9 | |||
| 10 | @dummy = Dummy.new | ||
| 11 | @avatar = @dummy.avatar | ||
| 12 | |||
| 13 | @current_env = ENV['RAILS_ENV'] | ||
| 14 | end | ||
| 15 | |||
| 16 | teardown do | ||
| 17 | ENV['RAILS_ENV'] = @current_env | ||
| 18 | end | ||
| 19 | |||
| 20 | should "get the correct credentials when RAILS_ENV is production" do | ||
| 21 | ENV['RAILS_ENV'] = 'production' | ||
| 22 | assert_equal({:key => "12345"}, | ||
| 23 | @avatar.parse_credentials('production' => {:key => '12345'}, | ||
| 24 | :development => {:key => "54321"})) | ||
| 25 | end | ||
| 26 | |||
| 27 | should "get the correct credentials when RAILS_ENV is development" do | ||
| 28 | ENV['RAILS_ENV'] = 'development' | ||
| 29 | assert_equal({:key => "54321"}, | ||
| 30 | @avatar.parse_credentials('production' => {:key => '12345'}, | ||
| 31 | :development => {:key => "54321"})) | ||
| 32 | end | ||
| 33 | |||
| 34 | should "return the argument if the key does not exist" do | ||
| 35 | ENV['RAILS_ENV'] = "not really an env" | ||
| 36 | assert_equal({:test => "12345"}, @avatar.parse_credentials(:test => "12345")) | ||
| 37 | end | ||
| 38 | end | ||
| 39 | |||
| 40 | context "" do | ||
| 41 | setup do | ||
| 42 | rebuild_model :storage => :s3, | ||
| 43 | :s3_credentials => {}, | ||
| 44 | :bucket => "bucket", | ||
| 45 | :path => ":attachment/:basename.:extension", | ||
| 46 | :url => ":s3_path_url" | ||
| 47 | @dummy = Dummy.new | ||
| 48 | @dummy.avatar = StringIO.new(".") | ||
| 49 | end | ||
| 50 | |||
| 51 | should "return a url based on an S3 path" do | ||
| 52 | assert_match %r{^http://s3.amazonaws.com/bucket/avatars/stringio.txt}, @dummy.avatar.url | ||
| 53 | end | ||
| 54 | end | ||
| 55 | context "" do | ||
| 56 | setup do | ||
| 57 | rebuild_model :storage => :s3, | ||
| 58 | :s3_credentials => {}, | ||
| 59 | :bucket => "bucket", | ||
| 60 | :path => ":attachment/:basename.:extension", | ||
| 61 | :url => ":s3_domain_url" | ||
| 62 | @dummy = Dummy.new | ||
| 63 | @dummy.avatar = StringIO.new(".") | ||
| 64 | end | ||
| 65 | |||
| 66 | should "return a url based on an S3 subdomain" do | ||
| 67 | assert_match %r{^http://bucket.s3.amazonaws.com/avatars/stringio.txt}, @dummy.avatar.url | ||
| 68 | end | ||
| 69 | end | ||
| 70 | context "" do | ||
| 71 | setup do | ||
| 72 | rebuild_model :storage => :s3, | ||
| 73 | :s3_credentials => { | ||
| 74 | :production => { :bucket => "prod_bucket" }, | ||
| 75 | :development => { :bucket => "dev_bucket" } | ||
| 76 | }, | ||
| 77 | :s3_host_alias => "something.something.com", | ||
| 78 | :path => ":attachment/:basename.:extension", | ||
| 79 | :url => ":s3_alias_url" | ||
| 80 | @dummy = Dummy.new | ||
| 81 | @dummy.avatar = StringIO.new(".") | ||
| 82 | end | ||
| 83 | |||
| 84 | should "return a url based on the host_alias" do | ||
| 85 | assert_match %r{^http://something.something.com/avatars/stringio.txt}, @dummy.avatar.url | ||
| 86 | end | ||
| 87 | end | ||
| 88 | |||
| 89 | context "Parsing S3 credentials with a bucket in them" do | ||
| 90 | setup do | ||
| 91 | rebuild_model :storage => :s3, | ||
| 92 | :s3_credentials => { | ||
| 93 | :production => { :bucket => "prod_bucket" }, | ||
| 94 | :development => { :bucket => "dev_bucket" } | ||
| 95 | } | ||
| 96 | @dummy = Dummy.new | ||
| 97 | end | ||
| 98 | |||
| 99 | should "get the right bucket in production", :before => lambda{ ENV.expects(:[]).returns('production') } do | ||
| 100 | assert_equal "prod_bucket", @dummy.avatar.bucket_name | ||
| 101 | end | ||
| 102 | |||
| 103 | should "get the right bucket in development", :before => lambda{ ENV.expects(:[]).returns('development') } do | ||
| 104 | assert_equal "dev_bucket", @dummy.avatar.bucket_name | ||
| 105 | end | ||
| 106 | end | ||
| 107 | |||
| 108 | context "An attachment with S3 storage" do | ||
| 109 | setup do | ||
| 110 | rebuild_model :storage => :s3, | ||
| 111 | :bucket => "testing", | ||
| 112 | :path => ":attachment/:style/:basename.:extension", | ||
| 113 | :s3_credentials => { | ||
| 114 | 'access_key_id' => "12345", | ||
| 115 | 'secret_access_key' => "54321" | ||
| 116 | } | ||
| 117 | end | ||
| 118 | |||
| 119 | should "be extended by the S3 module" do | ||
| 120 | assert Dummy.new.avatar.is_a?(Paperclip::Storage::S3) | ||
| 121 | end | ||
| 122 | |||
| 123 | should "not be extended by the Filesystem module" do | ||
| 124 | assert ! Dummy.new.avatar.is_a?(Paperclip::Storage::Filesystem) | ||
| 125 | end | ||
| 126 | |||
| 127 | context "when assigned" do | ||
| 128 | setup do | ||
| 129 | @file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb') | ||
| 130 | @dummy = Dummy.new | ||
| 131 | @dummy.avatar = @file | ||
| 132 | end | ||
| 133 | |||
| 134 | teardown { @file.close } | ||
| 135 | |||
| 136 | should "not get a bucket to get a URL" do | ||
| 137 | @dummy.avatar.expects(:s3).never | ||
| 138 | @dummy.avatar.expects(:s3_bucket).never | ||
| 139 | assert_match %r{^http://s3\.amazonaws\.com/testing/avatars/original/5k\.png}, @dummy.avatar.url | ||
| 140 | end | ||
| 141 | |||
| 142 | context "and saved" do | ||
| 143 | setup do | ||
| 144 | @s3_mock = stub | ||
| 145 | @bucket_mock = stub | ||
| 146 | RightAws::S3.expects(:new).with("12345", "54321", {}).returns(@s3_mock) | ||
| 147 | @s3_mock.expects(:bucket).with("testing", true, "public-read").returns(@bucket_mock) | ||
| 148 | @key_mock = stub | ||
| 149 | @bucket_mock.expects(:key).returns(@key_mock) | ||
| 150 | @key_mock.expects(:data=) | ||
| 151 | @key_mock.expects(:put).with(nil, 'public-read', 'Content-type' => 'image/png') | ||
| 152 | @dummy.save | ||
| 153 | end | ||
| 154 | |||
| 155 | should "succeed" do | ||
| 156 | assert true | ||
| 157 | end | ||
| 158 | end | ||
| 159 | |||
| 160 | context "and remove" do | ||
| 161 | setup do | ||
| 162 | @s3_mock = stub | ||
| 163 | @bucket_mock = stub | ||
| 164 | RightAws::S3.expects(:new).with("12345", "54321", {}).returns(@s3_mock) | ||
| 165 | @s3_mock.expects(:bucket).with("testing", true, "public-read").returns(@bucket_mock) | ||
| 166 | @key_mock = stub | ||
| 167 | @bucket_mock.expects(:key).at_least(2).returns(@key_mock) | ||
| 168 | @key_mock.expects(:delete) | ||
| 169 | @dummy.destroy_attached_files | ||
| 170 | end | ||
| 171 | |||
| 172 | should "succeed" do | ||
| 173 | assert true | ||
| 174 | end | ||
| 175 | end | ||
| 176 | end | ||
| 177 | end | ||
| 178 | |||
| 179 | context "An attachment with S3 storage and bucket defined as a Proc" do | ||
| 180 | setup do | ||
| 181 | rebuild_model :storage => :s3, | ||
| 182 | :bucket => lambda { |attachment| "bucket_#{attachment.instance.other}" }, | ||
| 183 | :s3_credentials => {:not => :important} | ||
| 184 | end | ||
| 185 | |||
| 186 | should "get the right bucket name" do | ||
| 187 | assert "bucket_a", Dummy.new(:other => 'a').avatar.bucket_name | ||
| 188 | assert "bucket_b", Dummy.new(:other => 'b').avatar.bucket_name | ||
| 189 | end | ||
| 190 | end | ||
| 191 | |||
| 192 | context "An attachment with S3 storage and specific s3 headers set" do | ||
| 193 | setup do | ||
| 194 | rebuild_model :storage => :s3, | ||
| 195 | :bucket => "testing", | ||
| 196 | :path => ":attachment/:style/:basename.:extension", | ||
| 197 | :s3_credentials => { | ||
| 198 | 'access_key_id' => "12345", | ||
| 199 | 'secret_access_key' => "54321" | ||
| 200 | }, | ||
| 201 | :s3_headers => {'Cache-Control' => 'max-age=31557600'} | ||
| 202 | end | ||
| 203 | |||
| 204 | context "when assigned" do | ||
| 205 | setup do | ||
| 206 | @file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb') | ||
| 207 | @dummy = Dummy.new | ||
| 208 | @dummy.avatar = @file | ||
| 209 | end | ||
| 210 | |||
| 211 | teardown { @file.close } | ||
| 212 | |||
| 213 | context "and saved" do | ||
| 214 | setup do | ||
| 215 | @s3_mock = stub | ||
| 216 | @bucket_mock = stub | ||
| 217 | RightAws::S3.expects(:new).with("12345", "54321", {}).returns(@s3_mock) | ||
| 218 | @s3_mock.expects(:bucket).with("testing", true, "public-read").returns(@bucket_mock) | ||
| 219 | @key_mock = stub | ||
| 220 | @bucket_mock.expects(:key).returns(@key_mock) | ||
| 221 | @key_mock.expects(:data=) | ||
| 222 | @key_mock.expects(:put).with(nil, | ||
| 223 | 'public-read', | ||
| 224 | 'Content-type' => 'image/png', | ||
| 225 | 'Cache-Control' => 'max-age=31557600') | ||
| 226 | @dummy.save | ||
| 227 | end | ||
| 228 | |||
| 229 | should "succeed" do | ||
| 230 | assert true | ||
| 231 | end | ||
| 232 | end | ||
| 233 | end | ||
| 234 | end | ||
| 235 | |||
| 236 | unless ENV["S3_TEST_BUCKET"].blank? | ||
| 237 | context "Using S3 for real, an attachment with S3 storage" do | ||
| 238 | setup do | ||
| 239 | rebuild_model :styles => { :thumb => "100x100", :square => "32x32#" }, | ||
| 240 | :storage => :s3, | ||
| 241 | :bucket => ENV["S3_TEST_BUCKET"], | ||
| 242 | :path => ":class/:attachment/:id/:style.:extension", | ||
| 243 | :s3_credentials => File.new(File.join(File.dirname(__FILE__), "s3.yml")) | ||
| 244 | |||
| 245 | Dummy.delete_all | ||
| 246 | @dummy = Dummy.new | ||
| 247 | end | ||
| 248 | |||
| 249 | should "be extended by the S3 module" do | ||
| 250 | assert Dummy.new.avatar.is_a?(Paperclip::Storage::S3) | ||
| 251 | end | ||
| 252 | |||
| 253 | context "when assigned" do | ||
| 254 | setup do | ||
| 255 | @file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb') | ||
| 256 | @dummy.avatar = @file | ||
| 257 | end | ||
| 258 | |||
| 259 | teardown { @file.close } | ||
| 260 | |||
| 261 | should "still return a Tempfile when sent #to_io" do | ||
| 262 | assert_equal Tempfile, @dummy.avatar.to_io.class | ||
| 263 | end | ||
| 264 | |||
| 265 | context "and saved" do | ||
| 266 | setup do | ||
| 267 | @dummy.save | ||
| 268 | end | ||
| 269 | |||
| 270 | should "be on S3" do | ||
| 271 | assert true | ||
| 272 | end | ||
| 273 | end | ||
| 274 | end | ||
| 275 | end | ||
| 276 | end | ||
| 277 | end | ||
diff --git a/vendor/plugins/paperclip/test/thumbnail_test.rb b/vendor/plugins/paperclip/test/thumbnail_test.rb deleted file mode 100644 index 624e7fa..0000000 --- a/vendor/plugins/paperclip/test/thumbnail_test.rb +++ /dev/null | |||
| @@ -1,177 +0,0 @@ | |||
| 1 | require 'test/helper' | ||
| 2 | |||
| 3 | class ThumbnailTest < Test::Unit::TestCase | ||
| 4 | |||
| 5 | context "A Paperclip Tempfile" do | ||
| 6 | setup do | ||
| 7 | @tempfile = Paperclip::Tempfile.new("file.jpg") | ||
| 8 | end | ||
| 9 | |||
| 10 | should "have its path contain a real extension" do | ||
| 11 | assert_equal ".jpg", File.extname(@tempfile.path) | ||
| 12 | end | ||
| 13 | |||
| 14 | should "be a real Tempfile" do | ||
| 15 | assert @tempfile.is_a?(::Tempfile) | ||
| 16 | end | ||
| 17 | end | ||
| 18 | |||
| 19 | context "Another Paperclip Tempfile" do | ||
| 20 | setup do | ||
| 21 | @tempfile = Paperclip::Tempfile.new("file") | ||
| 22 | end | ||
| 23 | |||
| 24 | should "not have an extension if not given one" do | ||
| 25 | assert_equal "", File.extname(@tempfile.path) | ||
| 26 | end | ||
| 27 | |||
| 28 | should "still be a real Tempfile" do | ||
| 29 | assert @tempfile.is_a?(::Tempfile) | ||
| 30 | end | ||
| 31 | end | ||
| 32 | |||
| 33 | context "An image" do | ||
| 34 | setup do | ||
| 35 | @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb') | ||
| 36 | end | ||
| 37 | |||
| 38 | teardown { @file.close } | ||
| 39 | |||
| 40 | [["600x600>", "434x66"], | ||
| 41 | ["400x400>", "400x61"], | ||
| 42 | ["32x32<", "434x66"] | ||
| 43 | ].each do |args| | ||
| 44 | context "being thumbnailed with a geometry of #{args[0]}" do | ||
| 45 | setup do | ||
| 46 | @thumb = Paperclip::Thumbnail.new(@file, :geometry => args[0]) | ||
| 47 | end | ||
| 48 | |||
| 49 | should "start with dimensions of 434x66" do | ||
| 50 | cmd = %Q[identify -format "%wx%h" "#{@file.path}"] | ||
| 51 | assert_equal "434x66", `#{cmd}`.chomp | ||
| 52 | end | ||
| 53 | |||
| 54 | should "report the correct target geometry" do | ||
| 55 | assert_equal args[0], @thumb.target_geometry.to_s | ||
| 56 | end | ||
| 57 | |||
| 58 | context "when made" do | ||
| 59 | setup do | ||
| 60 | @thumb_result = @thumb.make | ||
| 61 | end | ||
| 62 | |||
| 63 | should "be the size we expect it to be" do | ||
| 64 | cmd = %Q[identify -format "%wx%h" "#{@thumb_result.path}"] | ||
| 65 | assert_equal args[1], `#{cmd}`.chomp | ||
| 66 | end | ||
| 67 | end | ||
| 68 | end | ||
| 69 | end | ||
| 70 | |||
| 71 | context "being thumbnailed at 100x50 with cropping" do | ||
| 72 | setup do | ||
| 73 | @thumb = Paperclip::Thumbnail.new(@file, :geometry => "100x50#") | ||
| 74 | end | ||
| 75 | |||
| 76 | should "report its correct current and target geometries" do | ||
| 77 | assert_equal "100x50#", @thumb.target_geometry.to_s | ||
| 78 | assert_equal "434x66", @thumb.current_geometry.to_s | ||
| 79 | end | ||
| 80 | |||
| 81 | should "report its correct format" do | ||
| 82 | assert_nil @thumb.format | ||
| 83 | end | ||
| 84 | |||
| 85 | should "have whiny turned on by default" do | ||
| 86 | assert @thumb.whiny | ||
| 87 | end | ||
| 88 | |||
| 89 | should "have convert_options set to nil by default" do | ||
| 90 | assert_equal nil, @thumb.convert_options | ||
| 91 | end | ||
| 92 | |||
| 93 | should "send the right command to convert when sent #make" do | ||
| 94 | Paperclip.expects(:"`").with do |arg| | ||
| 95 | arg.match %r{convert\s+"#{File.expand_path(@thumb.file.path)}\[0\]"\s+-resize\s+\"x50\"\s+-crop\s+\"100x50\+114\+0\"\s+\+repage\s+".*?"} | ||
| 96 | end | ||
| 97 | @thumb.make | ||
| 98 | end | ||
| 99 | |||
| 100 | should "create the thumbnail when sent #make" do | ||
| 101 | dst = @thumb.make | ||
| 102 | assert_match /100x50/, `identify "#{dst.path}"` | ||
| 103 | end | ||
| 104 | end | ||
| 105 | |||
| 106 | context "being thumbnailed with convert options set" do | ||
| 107 | setup do | ||
| 108 | @thumb = Paperclip::Thumbnail.new(@file, | ||
| 109 | :geometry => "100x50#", | ||
| 110 | :convert_options => "-strip -depth 8") | ||
| 111 | end | ||
| 112 | |||
| 113 | should "have convert_options value set" do | ||
| 114 | assert_equal "-strip -depth 8", @thumb.convert_options | ||
| 115 | end | ||
| 116 | |||
| 117 | should "send the right command to convert when sent #make" do | ||
| 118 | Paperclip.expects(:"`").with do |arg| | ||
| 119 | arg.match %r{convert\s+"#{File.expand_path(@thumb.file.path)}\[0\]"\s+-resize\s+"x50"\s+-crop\s+"100x50\+114\+0"\s+\+repage\s+-strip\s+-depth\s+8\s+".*?"} | ||
| 120 | end | ||
| 121 | @thumb.make | ||
| 122 | end | ||
| 123 | |||
| 124 | should "create the thumbnail when sent #make" do | ||
| 125 | dst = @thumb.make | ||
| 126 | assert_match /100x50/, `identify "#{dst.path}"` | ||
| 127 | end | ||
| 128 | |||
| 129 | context "redefined to have bad convert_options setting" do | ||
| 130 | setup do | ||
| 131 | @thumb = Paperclip::Thumbnail.new(@file, | ||
| 132 | :geometry => "100x50#", | ||
| 133 | :convert_options => "-this-aint-no-option") | ||
| 134 | end | ||
| 135 | |||
| 136 | should "error when trying to create the thumbnail" do | ||
| 137 | assert_raises(Paperclip::PaperclipError) do | ||
| 138 | @thumb.make | ||
| 139 | end | ||
| 140 | end | ||
| 141 | end | ||
| 142 | end | ||
| 143 | end | ||
| 144 | |||
| 145 | context "A multipage PDF" do | ||
| 146 | setup do | ||
| 147 | @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "twopage.pdf"), 'rb') | ||
| 148 | end | ||
| 149 | |||
| 150 | teardown { @file.close } | ||
| 151 | |||
| 152 | should "start with two pages with dimensions 612x792" do | ||
| 153 | cmd = %Q[identify -format "%wx%h" "#{@file.path}"] | ||
| 154 | assert_equal "612x792"*2, `#{cmd}`.chomp | ||
| 155 | end | ||
| 156 | |||
| 157 | context "being thumbnailed at 100x100 with cropping" do | ||
| 158 | setup do | ||
| 159 | @thumb = Paperclip::Thumbnail.new(@file, :geometry => "100x100#", :format => :png) | ||
| 160 | end | ||
| 161 | |||
| 162 | should "report its correct current and target geometries" do | ||
| 163 | assert_equal "100x100#", @thumb.target_geometry.to_s | ||
| 164 | assert_equal "612x792", @thumb.current_geometry.to_s | ||
| 165 | end | ||
| 166 | |||
| 167 | should "report its correct format" do | ||
| 168 | assert_equal :png, @thumb.format | ||
| 169 | end | ||
| 170 | |||
| 171 | should "create the thumbnail when sent #make" do | ||
| 172 | dst = @thumb.make | ||
| 173 | assert_match /100x100/, `identify "#{dst.path}"` | ||
| 174 | end | ||
| 175 | end | ||
| 176 | end | ||
| 177 | end | ||
diff --git a/vendor/plugins/routing-filter/.gitignore b/vendor/plugins/routing-filter/.gitignore deleted file mode 100644 index 5657f6e..0000000 --- a/vendor/plugins/routing-filter/.gitignore +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | vendor \ No newline at end of file | ||
diff --git a/vendor/plugins/routing-filter/MIT-LICENSE b/vendor/plugins/routing-filter/MIT-LICENSE deleted file mode 100644 index ac93a58..0000000 --- a/vendor/plugins/routing-filter/MIT-LICENSE +++ /dev/null | |||
| @@ -1,20 +0,0 @@ | |||
| 1 | Copyright (c) 2008 Sven Fuchs | ||
| 2 | |||
| 3 | Permission is hereby granted, free of charge, to any person obtaining | ||
| 4 | a copy of this software and associated documentation files (the | ||
| 5 | "Software"), to deal in the Software without restriction, including | ||
| 6 | without limitation the rights to use, copy, modify, merge, publish, | ||
| 7 | distribute, sublicense, and/or sell copies of the Software, and to | ||
| 8 | permit persons to whom the Software is furnished to do so, subject to | ||
| 9 | the following conditions: | ||
| 10 | |||
| 11 | The above copyright notice and this permission notice shall be | ||
| 12 | included in all copies or substantial portions of the Software. | ||
| 13 | |||
| 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
| 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
| 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
| 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
| 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
| 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
| 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file | ||
diff --git a/vendor/plugins/routing-filter/README.markdown b/vendor/plugins/routing-filter/README.markdown deleted file mode 100644 index 77ee55d..0000000 --- a/vendor/plugins/routing-filter/README.markdown +++ /dev/null | |||
| @@ -1,123 +0,0 @@ | |||
| 1 | ## Routing Filter | ||
| 2 | |||
| 3 | This plugin is a wild hack that wraps around the complex beast that the Rails | ||
| 4 | routing system is to allow for unseen flexibility and power in Rails URL | ||
| 5 | recognition and generation. | ||
| 6 | |||
| 7 | As powerful and awesome the Rails' routes are, when you need to design your | ||
| 8 | URLs in a manner that only slightly leaves the paved cowpaths of Rails | ||
| 9 | conventions, you're usually unable to use all the goodness of helpers and | ||
| 10 | convenience that Rails ships with. | ||
| 11 | |||
| 12 | ## Usage | ||
| 13 | |||
| 14 | This plugin comes with a locale routing filter that demonstrates the | ||
| 15 | implementation of a custom filter. | ||
| 16 | |||
| 17 | The following would be a sceleton of an empty filter: | ||
| 18 | |||
| 19 | module RoutingFilter | ||
| 20 | class Awesomeness < Base | ||
| 21 | def around_recognize(route, path, env) | ||
| 22 | # Alter the path here before it gets recognized. | ||
| 23 | # Make sure to yield (calls the next around filter if present and | ||
| 24 | # eventually `recognize_path` on the routeset): | ||
| 25 | returning yield do |params| | ||
| 26 | # You can additionally modify the params here before they get passed | ||
| 27 | # to the controller. | ||
| 28 | end | ||
| 29 | end | ||
| 30 | |||
| 31 | def around_generate(controller, *args, &block) | ||
| 32 | # Alter arguments here before they are passed to `url_for`. | ||
| 33 | # Make sure to yield (calls the next around filter if present and | ||
| 34 | # eventually `url_for` on the controller): | ||
| 35 | returning yield do |result| | ||
| 36 | # You can change the generated url_or_path here. Make sure to use | ||
| 37 | # one of the "in-place" modifying String methods though (like sub! | ||
| 38 | # and friends). | ||
| 39 | end | ||
| 40 | end | ||
| 41 | end | ||
| 42 | end | ||
| 43 | |||
| 44 | You then have to specify the filter explicitely in your routes.rb: | ||
| 45 | |||
| 46 | ActionController::Routing::Routes.draw do |map| | ||
| 47 | map.filter 'awesomeness' | ||
| 48 | end | ||
| 49 | |||
| 50 | (I am not sure if it makes sense to provide more technical information than | ||
| 51 | this because the usage of this plugin definitely requires some advanced | ||
| 52 | knowledge about Rails internals and especially its routing system. So, I | ||
| 53 | figure, anyone who could use this should also be able to read the code and | ||
| 54 | figure out what it's doing much better then from any lengthy documentation. | ||
| 55 | |||
| 56 | If I'm mistaken on this please drop me an email with your suggestions.) | ||
| 57 | |||
| 58 | |||
| 59 | ## Rationale: Two example usecases | ||
| 60 | |||
| 61 | An early usecase from which this originated was the need to define a locale | ||
| 62 | at the beginning of an URL in a way so that | ||
| 63 | |||
| 64 | * the locale can be omitted when it is the default locale | ||
| 65 | * all the url\_helpers that are generated by named routes continue to work in | ||
| 66 | a concise manner (i.e. without specifying all parameters again and again) | ||
| 67 | * ideally also plays nicely with default route helpers in tests/specs | ||
| 68 | |||
| 69 | You can read about this struggle and two possible, yet unsatisfying solutions | ||
| 70 | [here](http://www.artweb-design.de/2007/5/13/concise-localized-rails-url-helpers-solved-twice). | ||
| 71 | The conclusion so far is that Rails itself does not provide the tools to solve | ||
| 72 | this problem in a clean and dry way. | ||
| 73 | |||
| 74 | Another usecase that eventually spawned the manifestation of this plugin was | ||
| 75 | the need to map an arbitrary count of path segments to a certain model | ||
| 76 | instance. In an application that I've been working on recently I needed to | ||
| 77 | map URL paths to a nested tree of models like so: | ||
| 78 | |||
| 79 | root | ||
| 80 | + docs | ||
| 81 | + api | ||
| 82 | + wiki | ||
| 83 | |||
| 84 | E.g. the docs section should map to the path `/docs`, the api section to | ||
| 85 | the path `/docs/api` and so on. Furthermore, after these paths there need to be | ||
| 86 | more things to be specified. E.g. the wiki needs to define a whole Rails | ||
| 87 | resource with URLs like `/docs/wiki/pages/1/edit`. | ||
| 88 | |||
| 89 | The only way to solve this problem with Rails' routing toolkit is to map | ||
| 90 | a big, bold `/*everything` catch-all ("globbing") route and process the whole | ||
| 91 | path in a custom dispatcher. | ||
| 92 | |||
| 93 | This, of course, is a really unsatisfying solution because one has to | ||
| 94 | reimplement everything that Rails routes are here to help with: regarding both | ||
| 95 | URL recognition (like parameter mappings, resources, ...) and generation | ||
| 96 | (url\_helpers). | ||
| 97 | |||
| 98 | ## Solution | ||
| 99 | |||
| 100 | This plugin offers a solution that takes exactly the opposite route. | ||
| 101 | |||
| 102 | Instead of trying to change things *between* the URL recognition and | ||
| 103 | generation stages to achieve the desired result it *wraps around* the whole | ||
| 104 | routing system and allows to pre- and post-filter both what goes into it | ||
| 105 | (URL recognition) and what comes out of it (URL generation). | ||
| 106 | |||
| 107 | This way we can leave *everything* else completely untouched. | ||
| 108 | |||
| 109 | * We can tinker with the URLs that we receive from the server and feed URLs to | ||
| 110 | Rails that perfectly match the best breed of Rails' conventions. | ||
| 111 | * Inside of the application we can use all the nice helper goodness and | ||
| 112 | conveniences that rely on these conventions being followed. | ||
| 113 | * Finally we can accept URLs that have been generated by the url\_helpers and, | ||
| 114 | again, mutate them in the way that matches our requirements. | ||
| 115 | |||
| 116 | So, even though the plugin itself is a blatant monkey-patch to one of the | ||
| 117 | most complex area of Rails internals, this solution seems to be effectively | ||
| 118 | less intrusive and pricey than others are. | ||
| 119 | |||
| 120 | ## Etc | ||
| 121 | |||
| 122 | Authors: [Sven Fuchs](http://www.artweb-design.de) <svenfuchs at artweb-design dot de> | ||
| 123 | License: MIT \ No newline at end of file | ||
diff --git a/vendor/plugins/routing-filter/init.rb b/vendor/plugins/routing-filter/init.rb deleted file mode 100644 index 1189921..0000000 --- a/vendor/plugins/routing-filter/init.rb +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | require 'routing_filter' \ No newline at end of file | ||
diff --git a/vendor/plugins/routing-filter/lib/routing_filter.rb b/vendor/plugins/routing-filter/lib/routing_filter.rb deleted file mode 100644 index d67be14..0000000 --- a/vendor/plugins/routing-filter/lib/routing_filter.rb +++ /dev/null | |||
| @@ -1,69 +0,0 @@ | |||
| 1 | module RoutingFilter | ||
| 2 | mattr_accessor :active | ||
| 3 | @@active = true | ||
| 4 | |||
| 5 | class Chain < Array | ||
| 6 | def << (filter) | ||
| 7 | filter.successor = last | ||
| 8 | super | ||
| 9 | end | ||
| 10 | |||
| 11 | def run(method, *args, &final) | ||
| 12 | RoutingFilter.active ? last.run(method, *args, &final) : final.call | ||
| 13 | end | ||
| 14 | end | ||
| 15 | end | ||
| 16 | |||
| 17 | # allows to install a filter to the route set by calling: map.filter 'locale' | ||
| 18 | ActionController::Routing::RouteSet::Mapper.class_eval do | ||
| 19 | def filter(name, options = {}) | ||
| 20 | require "routing_filter/#{name}" | ||
| 21 | klass = RoutingFilter.const_get name.to_s.camelize | ||
| 22 | @set.filters << klass.new(options) | ||
| 23 | end | ||
| 24 | end | ||
| 25 | |||
| 26 | # same here for the optimized url generation in named routes | ||
| 27 | ActionController::Routing::RouteSet::NamedRouteCollection.class_eval do | ||
| 28 | # gosh. monkey engineering optimization code | ||
| 29 | def generate_optimisation_block_with_filtering(*args) | ||
| 30 | code = generate_optimisation_block_without_filtering *args | ||
| 31 | if match = code.match(%r(^return (.*) if (.*))) | ||
| 32 | # returned string must not contain newlines, or we'll spill out of inline code comments in ActionController::Routing::RouteSet::NamedRouteCollection#define_url_helper (as of http://github.com/rails/rails/commit/a2270ef2594b97891994848138614657363f2806) | ||
| 33 | "returning(#{match[1]}) { |result| ActionController::Routing::Routes.filters.run :around_generate, *args, &lambda{ result } } if #{match[2]}" | ||
| 34 | end | ||
| 35 | end | ||
| 36 | alias_method_chain :generate_optimisation_block, :filtering | ||
| 37 | end | ||
| 38 | |||
| 39 | ActionController::Routing::RouteSet.class_eval do | ||
| 40 | def filters | ||
| 41 | @filters ||= RoutingFilter::Chain.new | ||
| 42 | end | ||
| 43 | |||
| 44 | def recognize_path_with_filtering(path, env) | ||
| 45 | path = path.dup # string is frozen due to memoize | ||
| 46 | filters.run :around_recognize, path, env, &lambda{ recognize_path_without_filtering(path, env) } | ||
| 47 | end | ||
| 48 | alias_method_chain :recognize_path, :filtering | ||
| 49 | |||
| 50 | def generate_with_filtering(*args) | ||
| 51 | filters.run :around_generate, args.first, &lambda{ generate_without_filtering(*args) } | ||
| 52 | end | ||
| 53 | alias_method_chain :generate, :filtering | ||
| 54 | |||
| 55 | # add some useful information to the request environment | ||
| 56 | # right, this is from jamis buck's excellent article about routes internals | ||
| 57 | # http://weblog.jamisbuck.org/2006/10/26/monkey-patching-rails-extending-routes-2 | ||
| 58 | # TODO move this ... where? | ||
| 59 | alias_method :extract_request_environment_without_host, :extract_request_environment unless method_defined? :extract_request_environment_without_host | ||
| 60 | def extract_request_environment(request) | ||
| 61 | returning extract_request_environment_without_host(request) do |env| | ||
| 62 | env.merge! :host => request.host, | ||
| 63 | :port => request.port, | ||
| 64 | :host_with_port => request.host_with_port, | ||
| 65 | :domain => request.domain, | ||
| 66 | :subdomain => request.subdomains.first | ||
| 67 | end | ||
| 68 | end | ||
| 69 | end \ No newline at end of file | ||
diff --git a/vendor/plugins/routing-filter/lib/routing_filter/base.rb b/vendor/plugins/routing-filter/lib/routing_filter/base.rb deleted file mode 100644 index bc60ba5..0000000 --- a/vendor/plugins/routing-filter/lib/routing_filter/base.rb +++ /dev/null | |||
| @@ -1,15 +0,0 @@ | |||
| 1 | module RoutingFilter | ||
| 2 | class Base | ||
| 3 | attr_accessor :successor, :options | ||
| 4 | |||
| 5 | def initialize(options) | ||
| 6 | @options = options | ||
| 7 | options.each{|name, value| instance_variable_set :"@#{name}", value } | ||
| 8 | end | ||
| 9 | |||
| 10 | def run(method, *args, &block) | ||
| 11 | successor = @successor ? lambda { @successor.run(method, *args, &block) } : block | ||
| 12 | send method, *args, &successor | ||
| 13 | end | ||
| 14 | end | ||
| 15 | end \ No newline at end of file | ||
diff --git a/vendor/plugins/routing-filter/lib/routing_filter/locale.rb b/vendor/plugins/routing-filter/lib/routing_filter/locale.rb deleted file mode 100644 index 6fc3e11..0000000 --- a/vendor/plugins/routing-filter/lib/routing_filter/locale.rb +++ /dev/null | |||
| @@ -1,35 +0,0 @@ | |||
| 1 | require 'i18n' | ||
| 2 | require 'routing_filter/base' | ||
| 3 | |||
| 4 | module RoutingFilter | ||
| 5 | class Locale < Base | ||
| 6 | @@default_locale = :he | ||
| 7 | cattr_reader :default_locale | ||
| 8 | |||
| 9 | class << self | ||
| 10 | def default_locale=(locale) | ||
| 11 | @@default_locale = locale.to_sym | ||
| 12 | end | ||
| 13 | end | ||
| 14 | |||
| 15 | # remove the locale from the beginning of the path, pass the path | ||
| 16 | # to the given block and set it to the resulting params hash | ||
| 17 | def around_recognize(path, env, &block) | ||
| 18 | locale = nil | ||
| 19 | path.sub! %r(^/([a-zA-Z]{2})(?=/|$)) do locale = $1; '' end | ||
| 20 | returning yield do |params| | ||
| 21 | params[:locale] = locale if locale | ||
| 22 | end | ||
| 23 | end | ||
| 24 | |||
| 25 | def around_generate(*args, &block) | ||
| 26 | locale = args.extract_options!.delete(:locale) || I18n.locale | ||
| 27 | returning yield do |result| | ||
| 28 | if locale.to_sym != @@default_locale | ||
| 29 | target = result.is_a?(Array) ? result.first : result | ||
| 30 | target.sub!(%r(^(http.?://[^/]*)?(.*))){ "#{$1}/#{locale}#{$2}" } | ||
| 31 | end | ||
| 32 | end | ||
| 33 | end | ||
| 34 | end | ||
| 35 | end \ No newline at end of file | ||
diff --git a/vendor/plugins/routing-filter/lib/routing_filter/pagination.rb b/vendor/plugins/routing-filter/lib/routing_filter/pagination.rb deleted file mode 100644 index a5bd7aa..0000000 --- a/vendor/plugins/routing-filter/lib/routing_filter/pagination.rb +++ /dev/null | |||
| @@ -1,19 +0,0 @@ | |||
| 1 | require 'routing_filter/base' | ||
| 2 | |||
| 3 | module RoutingFilter | ||
| 4 | class Pagination < Base | ||
| 5 | def around_recognize(path, env, &block) | ||
| 6 | path.gsub! %r(/pages/([\d]+)/?$), '' | ||
| 7 | returning yield(path, env) do |params| | ||
| 8 | params[:page] = $1.to_i if $1 | ||
| 9 | end | ||
| 10 | end | ||
| 11 | |||
| 12 | def around_generate(*args, &block) | ||
| 13 | page = args.extract_options!.delete(:page) | ||
| 14 | returning yield do |result| | ||
| 15 | result.replace "#{result}/pages/#{page}" if page && page != 1 | ||
| 16 | end | ||
| 17 | end | ||
| 18 | end | ||
| 19 | end \ No newline at end of file | ||
diff --git a/vendor/plugins/routing-filter/spec/generation_spec.rb b/vendor/plugins/routing-filter/spec/generation_spec.rb deleted file mode 100644 index 224cd4e..0000000 --- a/vendor/plugins/routing-filter/spec/generation_spec.rb +++ /dev/null | |||
| @@ -1,283 +0,0 @@ | |||
| 1 | require File.dirname(__FILE__) + '/spec_helper.rb' | ||
| 2 | |||
| 3 | describe 'RoutingFilter', 'url generation' do | ||
| 4 | include RoutingFilterHelpers | ||
| 5 | |||
| 6 | before :each do | ||
| 7 | RoutingFilter::Locale.default_locale = :en | ||
| 8 | I18n.default_locale = :en | ||
| 9 | I18n.locale = :en | ||
| 10 | |||
| 11 | @controller = instantiate_controller :locale => 'de', :id => 1 | ||
| 12 | @set = draw_routes do |map| | ||
| 13 | map.section 'sections/:id', :controller => 'sections', :action => "show" | ||
| 14 | map.section_article 'sections/:section_id/articles/:id', :controller => 'articles', :action => "show" | ||
| 15 | |||
| 16 | map.filter 'locale' | ||
| 17 | map.filter 'pagination' | ||
| 18 | end | ||
| 19 | |||
| 20 | @site = Site.new | ||
| 21 | @section = Section.new | ||
| 22 | @article = Article.new | ||
| 23 | |||
| 24 | @params = {:controller => 'sections', :action => "show", :id => "1"} | ||
| 25 | @article_params = {:controller => 'articles', :action => 'show', :section_id => "1", :id => "1"} | ||
| 26 | @locale_filter = @set.filters.first | ||
| 27 | |||
| 28 | Section.stub!(:types).and_return ['Section'] | ||
| 29 | Section.stub!(:find).and_return @section | ||
| 30 | end | ||
| 31 | |||
| 32 | def should_recognize_path(path, params) | ||
| 33 | @set.recognize_path(path, {}).should == params | ||
| 34 | end | ||
| 35 | |||
| 36 | def section_path(*args) | ||
| 37 | @controller.send :section_path, *args | ||
| 38 | end | ||
| 39 | |||
| 40 | def section_article_path(*args) | ||
| 41 | @controller.send :section_article_path, *args | ||
| 42 | end | ||
| 43 | |||
| 44 | def url_for(*args) | ||
| 45 | @controller.send :url_for, *args | ||
| 46 | end | ||
| 47 | |||
| 48 | describe "named route url_helpers" do | ||
| 49 | describe "a not nested resource" do | ||
| 50 | it 'does not change the section_path when the current locale is the default locale and no page option given' do | ||
| 51 | section_path(:id => 1).should == '/sections/1' | ||
| 52 | end | ||
| 53 | |||
| 54 | it 'does not change the section_path when given page option equals 1' do | ||
| 55 | section_path(:id => 1, :page => 1).should == '/sections/1' | ||
| 56 | end | ||
| 57 | |||
| 58 | it 'appends the pages segments to section_path when given page option does not equal 1' do | ||
| 59 | section_path(:id => 1, :page => 2).should == '/sections/1/pages/2' | ||
| 60 | end | ||
| 61 | |||
| 62 | it 'prepends the current locale to section_path when it is not the default locale' do | ||
| 63 | I18n.locale = :de | ||
| 64 | section_path(:id => 1).should == '/de/sections/1' | ||
| 65 | end | ||
| 66 | |||
| 67 | it 'prepends a given locale param to section_path when it is not the default locale' do | ||
| 68 | I18n.locale = :de | ||
| 69 | section_path(:id => 1, :locale => :fi).should == '/fi/sections/1' | ||
| 70 | end | ||
| 71 | |||
| 72 | it 'works on section_path with both a locale and page option' do | ||
| 73 | section_path(:id => 1, :locale => :fi, :page => 2).should == '/fi/sections/1/pages/2' | ||
| 74 | end | ||
| 75 | end | ||
| 76 | |||
| 77 | describe "a nested resource" do | ||
| 78 | it 'does not change the section_article_path when the current locale is the default locale and no page option given' do | ||
| 79 | section_article_path(:section_id => 1, :id => 1).should == '/sections/1/articles/1' | ||
| 80 | end | ||
| 81 | |||
| 82 | it 'does not change the section_article_path when given page option equals 1' do | ||
| 83 | section_article_path(:section_id => 1, :id => 1, :page => 1).should == '/sections/1/articles/1' | ||
| 84 | end | ||
| 85 | |||
| 86 | it 'appends the pages segments to section_article_path when given page option does not equal 1' do | ||
| 87 | section_article_path(:section_id => 1, :id => 1, :page => 2).should == '/sections/1/articles/1/pages/2' | ||
| 88 | end | ||
| 89 | |||
| 90 | it 'prepends the current locale to section_article_path when it is not the default locale' do | ||
| 91 | I18n.locale = :de | ||
| 92 | section_article_path(:section_id => 1, :id => 1).should == '/de/sections/1/articles/1' | ||
| 93 | end | ||
| 94 | |||
| 95 | it 'prepends a given locale param to section_article_path when it is not the default locale' do | ||
| 96 | I18n.locale = :de | ||
| 97 | section_article_path(:section_id => 1, :id => 1, :locale => :fi).should == '/fi/sections/1/articles/1' | ||
| 98 | end | ||
| 99 | |||
| 100 | it 'works on section_article_path with both a locale and page option' do | ||
| 101 | section_article_path(:section_id => 1, :id => 1, :locale => :fi, :page => 2).should == '/fi/sections/1/articles/1/pages/2' | ||
| 102 | end | ||
| 103 | end | ||
| 104 | end | ||
| 105 | |||
| 106 | describe 'when used with named route url_helper with "optimized" generation blocks' do | ||
| 107 | describe "a not nested resource" do | ||
| 108 | # uses optimization | ||
| 109 | it 'does not change the section_path when the current locale is the default locale and no page option given' do | ||
| 110 | section_path(1).should == '/sections/1' | ||
| 111 | end | ||
| 112 | |||
| 113 | # uses optimization | ||
| 114 | it 'prepends the current locale to section_path when it is not the default locale' do | ||
| 115 | I18n.locale = :de | ||
| 116 | section_path(1).should == '/de/sections/1' | ||
| 117 | end | ||
| 118 | |||
| 119 | it 'prepends a given locale param to section_path when it is not the default locale' do | ||
| 120 | I18n.locale = :de | ||
| 121 | section_path(1, :locale => :fi).should == '/fi/sections/1' | ||
| 122 | end | ||
| 123 | |||
| 124 | it 'does not change the section_path when given page option equals 1' do | ||
| 125 | section_path(1, :page => 1).should == '/sections/1' | ||
| 126 | end | ||
| 127 | |||
| 128 | it 'appends the pages segments to section_path when given page option does not equal 1' do | ||
| 129 | section_path(1, :page => 2).should == '/sections/1/pages/2' | ||
| 130 | end | ||
| 131 | |||
| 132 | it 'works for section_path with both a locale and page option' do | ||
| 133 | section_path(1, :locale => :fi, :page => 2).should == '/fi/sections/1/pages/2' | ||
| 134 | end | ||
| 135 | end | ||
| 136 | |||
| 137 | describe "a nested resource" do | ||
| 138 | # uses optimization | ||
| 139 | it 'does not change the section_article_path when the current locale is the default locale and no page option given' do | ||
| 140 | section_article_path(1, 1).should == '/sections/1/articles/1' | ||
| 141 | end | ||
| 142 | |||
| 143 | # uses optimization | ||
| 144 | it 'prepends the current locale to section_article_path when it is not the default locale' do | ||
| 145 | I18n.locale = :de | ||
| 146 | section_article_path(1, 1).should == '/de/sections/1/articles/1' | ||
| 147 | end | ||
| 148 | |||
| 149 | it 'prepends a given locale param when it is not the default locale' do | ||
| 150 | I18n.locale = :de | ||
| 151 | section_article_path(1, 1, :locale => :fi).should == '/fi/sections/1/articles/1' | ||
| 152 | end | ||
| 153 | |||
| 154 | it 'does not change the section_article_path when given page option equals 1' do | ||
| 155 | section_article_path(1, 1, :page => 1).should == '/sections/1/articles/1' | ||
| 156 | end | ||
| 157 | |||
| 158 | it 'appends the pages segments to section_article_path when given page option does not equal 1' do | ||
| 159 | section_article_path(1, 1, :page => 2).should == '/sections/1/articles/1/pages/2' | ||
| 160 | end | ||
| 161 | |||
| 162 | it 'works for section_article_path with both a locale and page option' do | ||
| 163 | section_article_path(1, 1, :locale => :fi, :page => 2).should == '/fi/sections/1/articles/1/pages/2' | ||
| 164 | end | ||
| 165 | end | ||
| 166 | end | ||
| 167 | |||
| 168 | describe 'when used with a polymorphic_path' do | ||
| 169 | describe "a not nested resource" do | ||
| 170 | # uses optimization | ||
| 171 | it 'does not change the section_path when the current locale is the default locale and no page option given' do | ||
| 172 | section_path(@section).should == '/sections/1' | ||
| 173 | end | ||
| 174 | |||
| 175 | # uses optimization | ||
| 176 | it 'prepends the current locale to section_path when it is not the default locale' do | ||
| 177 | I18n.locale = :de | ||
| 178 | section_path(@section).should == '/de/sections/1' | ||
| 179 | end | ||
| 180 | |||
| 181 | it 'prepends a given locale param to section_path when it is not the default locale' do | ||
| 182 | I18n.locale = :de | ||
| 183 | section_path(@section, :locale => :fi).should == '/fi/sections/1' | ||
| 184 | end | ||
| 185 | |||
| 186 | it 'does not change the section_path when given page option equals 1' do | ||
| 187 | section_path(@section, :page => 1).should == '/sections/1' | ||
| 188 | end | ||
| 189 | |||
| 190 | it 'appends the pages segments to section_path when given page option does not equal 1' do | ||
| 191 | section_path(@section, :page => 2).should == '/sections/1/pages/2' | ||
| 192 | end | ||
| 193 | |||
| 194 | it 'works for section_path with both a locale and page option' do | ||
| 195 | section_path(@section, :locale => :fi, :page => 2).should == '/fi/sections/1/pages/2' | ||
| 196 | end | ||
| 197 | end | ||
| 198 | |||
| 199 | describe "a nested resource" do | ||
| 200 | # uses optimization | ||
| 201 | it 'does not change the section_article_path when the current locale is the default locale and no page option given' do | ||
| 202 | section_article_path(@section, @article).should == '/sections/1/articles/1' | ||
| 203 | end | ||
| 204 | |||
| 205 | # uses optimization | ||
| 206 | it 'prepends the current locale to section_article_path when it is not the default locale' do | ||
| 207 | I18n.locale = :de | ||
| 208 | section_article_path(@section, @article).should == '/de/sections/1/articles/1' | ||
| 209 | end | ||
| 210 | |||
| 211 | it 'prepends a given locale param to section_article_path when it is not the default locale' do | ||
| 212 | I18n.locale = :de | ||
| 213 | section_article_path(@section, @article, :locale => :fi).should == '/fi/sections/1/articles/1' | ||
| 214 | end | ||
| 215 | |||
| 216 | it 'does not change the section_article_path when given page option equals 1' do | ||
| 217 | section_article_path(@section, @article, :page => 1).should == '/sections/1/articles/1' | ||
| 218 | end | ||
| 219 | |||
| 220 | it 'appends the pages segments to section_article_path when given page option does not equal 1' do | ||
| 221 | section_article_path(@section, @article, :page => 2).should == '/sections/1/articles/1/pages/2' | ||
| 222 | end | ||
| 223 | |||
| 224 | it 'works for section_article_path with both a locale and page option' do | ||
| 225 | section_article_path(@section, @article, :locale => :fi, :page => 2).should == '/fi/sections/1/articles/1/pages/2' | ||
| 226 | end | ||
| 227 | end | ||
| 228 | end | ||
| 229 | |||
| 230 | describe 'when used with url_for and an ActivRecord instance' do | ||
| 231 | describe "a not nested resource" do | ||
| 232 | it 'prepends the current locale to section_path when it is not the default locale' do | ||
| 233 | I18n.locale = :de | ||
| 234 | url_for(@section).should == 'http://test.host/de/sections/1' | ||
| 235 | end | ||
| 236 | |||
| 237 | it 'does not change the section_path when no page option given' do | ||
| 238 | url_for(@section).should == 'http://test.host/sections/1' | ||
| 239 | end | ||
| 240 | |||
| 241 | it 'does not change the section_path when given page option equals 1' do | ||
| 242 | params = @params.update :id => @section, :page => 1 | ||
| 243 | url_for(params).should == 'http://test.host/sections/1' | ||
| 244 | end | ||
| 245 | |||
| 246 | it 'appends the pages segments to section_path when given page option does not equal 1' do | ||
| 247 | params = @params.update :id => @section, :page => 2 | ||
| 248 | url_for(params).should == 'http://test.host/sections/1/pages/2' | ||
| 249 | end | ||
| 250 | |||
| 251 | it 'works for section_path with both a locale and page option' do | ||
| 252 | params = @params.update :id => @section, :locale => :fi, :page => 2 | ||
| 253 | url_for(params).should == 'http://test.host/fi/sections/1/pages/2' | ||
| 254 | end | ||
| 255 | end | ||
| 256 | |||
| 257 | describe "a nested resource" do | ||
| 258 | it 'prepends the current locale to section_article_path when it is not the default locale' do | ||
| 259 | I18n.locale = :de | ||
| 260 | url_for([@section, @article]).should == 'http://test.host/de/sections/1/articles/1' | ||
| 261 | end | ||
| 262 | |||
| 263 | it 'does not change the section_article_path when no page option given' do | ||
| 264 | url_for([@section, @article]).should == 'http://test.host/sections/1/articles/1' | ||
| 265 | end | ||
| 266 | |||
| 267 | it 'does not change the section_article_path when given page option equals 1' do | ||
| 268 | params = @article_params.update :section_id => @section, :id => @article, :page => 1 | ||
| 269 | url_for(params).should == 'http://test.host/sections/1/articles/1' | ||
| 270 | end | ||
| 271 | |||
| 272 | it 'appends the pages segments to section_article_path when given page option does not equal 1' do | ||
| 273 | params = @article_params.update :section_id => @section, :id => @article, :page => 2 | ||
| 274 | url_for(params).should == 'http://test.host/sections/1/articles/1/pages/2' | ||
| 275 | end | ||
| 276 | |||
| 277 | it 'works for section_article_path with both a locale and page option' do | ||
| 278 | params = @article_params.update :section_id => @section, :id => @article, :locale => :fi, :page => 2 | ||
| 279 | url_for(params).should == 'http://test.host/fi/sections/1/articles/1/pages/2' | ||
| 280 | end | ||
| 281 | end | ||
| 282 | end | ||
| 283 | end \ No newline at end of file | ||
diff --git a/vendor/plugins/routing-filter/spec/recognition_spec.rb b/vendor/plugins/routing-filter/spec/recognition_spec.rb deleted file mode 100644 index 11f0892..0000000 --- a/vendor/plugins/routing-filter/spec/recognition_spec.rb +++ /dev/null | |||
| @@ -1,76 +0,0 @@ | |||
| 1 | require File.dirname(__FILE__) + '/spec_helper.rb' | ||
| 2 | |||
| 3 | describe 'RoutingFilter', 'url recognition' do | ||
| 4 | include RoutingFilterHelpers | ||
| 5 | |||
| 6 | before :each do | ||
| 7 | RoutingFilter::Locale.default_locale = :en | ||
| 8 | I18n.default_locale = :en | ||
| 9 | I18n.locale = :en | ||
| 10 | |||
| 11 | @controller = instantiate_controller :locale => 'de', :id => 1 | ||
| 12 | @set = draw_routes do |map| | ||
| 13 | map.filter 'locale' | ||
| 14 | map.filter 'pagination' | ||
| 15 | |||
| 16 | map.section 'sections/:id', :controller => 'sections', :action => "show" | ||
| 17 | map.article 'sections/:section_id/articles/:id', :controller => 'articles', :action => "show" | ||
| 18 | end | ||
| 19 | |||
| 20 | @section_params = {:controller => 'sections', :action => "show", :id => "1"} | ||
| 21 | @article_params = {:controller => 'articles', :action => "show", :section_id => "1", :id => "1"} | ||
| 22 | @locale_filter = @set.filters.first | ||
| 23 | end | ||
| 24 | |||
| 25 | def should_recognize_path(path, params) | ||
| 26 | @set.recognize_path(path, {}).should == params | ||
| 27 | end | ||
| 28 | |||
| 29 | def section_path(*args) | ||
| 30 | @controller.send :section_path, *args | ||
| 31 | end | ||
| 32 | |||
| 33 | def url_for(*args) | ||
| 34 | @controller.send :url_for, *args | ||
| 35 | end | ||
| 36 | |||
| 37 | it 'recognizes the path /de/sections/1 and sets the :locale param' do | ||
| 38 | should_recognize_path '/de/sections/1', @section_params.update(:locale => 'de') | ||
| 39 | end | ||
| 40 | |||
| 41 | it 'recognizes the path /sections/1/pages/1 and sets the :page param' do | ||
| 42 | should_recognize_path '/sections/1/pages/1', @section_params.update(:page => 1) | ||
| 43 | end | ||
| 44 | |||
| 45 | it 'recognizes the path /de/sections/1/pages/1 and sets the :locale param' do | ||
| 46 | should_recognize_path '/de/sections/1/pages/1', @section_params.update(:locale => 'de', :page => 1) | ||
| 47 | end | ||
| 48 | |||
| 49 | it 'recognizes the path /sections/1/articles/1 and sets the :locale param' do | ||
| 50 | should_recognize_path '/sections/1/articles/1', @article_params | ||
| 51 | end | ||
| 52 | |||
| 53 | it 'recognizes the path /de/sections/1/articles/1 and sets the :locale param' do | ||
| 54 | should_recognize_path '/de/sections/1/articles/1', @article_params.update(:locale => 'de') | ||
| 55 | end | ||
| 56 | |||
| 57 | it 'recognizes the path /de/sections/1/articles/1/pages/1 and sets the :locale param' do | ||
| 58 | should_recognize_path '/de/sections/1/articles/1/pages/1', @article_params.update(:locale => 'de', :page => 1) | ||
| 59 | end | ||
| 60 | |||
| 61 | it 'recognizes the path /sections/1 and does not set a :locale param' do | ||
| 62 | should_recognize_path '/sections/1', @section_params | ||
| 63 | end | ||
| 64 | |||
| 65 | it 'recognizes the path /sections/1 and does not set a :page param' do | ||
| 66 | should_recognize_path '/sections/1', @section_params | ||
| 67 | end | ||
| 68 | |||
| 69 | it 'recognizes the path /sections/1/articles/1 and does not set a :locale param' do | ||
| 70 | should_recognize_path '/sections/1/articles/1', @article_params | ||
| 71 | end | ||
| 72 | |||
| 73 | it 'recognizes the path /sections/1/articles/1 and does not set a :page param' do | ||
| 74 | should_recognize_path '/sections/1/articles/1', @article_params | ||
| 75 | end | ||
| 76 | end \ No newline at end of file | ||
diff --git a/vendor/plugins/routing-filter/spec/routing_filter_spec.rb b/vendor/plugins/routing-filter/spec/routing_filter_spec.rb deleted file mode 100644 index f919c29..0000000 --- a/vendor/plugins/routing-filter/spec/routing_filter_spec.rb +++ /dev/null | |||
| @@ -1,70 +0,0 @@ | |||
| 1 | require File.dirname(__FILE__) + '/spec_helper.rb' | ||
| 2 | |||
| 3 | describe 'RoutingFilter' do | ||
| 4 | include RoutingFilterHelpers | ||
| 5 | |||
| 6 | before :each do | ||
| 7 | @controller = instantiate_controller :locale => 'de', :section_id => 1 | ||
| 8 | @set = draw_routes do |map| | ||
| 9 | map.section 'sections/:section_id', :controller => 'sections', :action => "show" | ||
| 10 | map.filter 'locale' | ||
| 11 | map.filter 'pagination' | ||
| 12 | end | ||
| 13 | @locale_filter = @set.filters.first | ||
| 14 | @pagination_filter = @set.filters.last | ||
| 15 | end | ||
| 16 | |||
| 17 | def recognize_path(path = '/de/sections/1', options = {}) | ||
| 18 | @set.recognize_path path, options | ||
| 19 | end | ||
| 20 | |||
| 21 | def url_for(options) | ||
| 22 | @controller.send :url_for, options | ||
| 23 | end | ||
| 24 | |||
| 25 | def section_path(*args) | ||
| 26 | @controller.send :section_path, *args | ||
| 27 | end | ||
| 28 | |||
| 29 | it 'installs filters to the route set' do | ||
| 30 | @locale_filter.should be_instance_of(RoutingFilter::Locale) | ||
| 31 | @pagination_filter.should be_instance_of(RoutingFilter::Pagination) | ||
| 32 | end | ||
| 33 | |||
| 34 | it 'calls the first filter for route recognition' do | ||
| 35 | @locale_filter.should_receive(:around_recognize).and_return :foo => :bar | ||
| 36 | recognize_path.should == {:foo => :bar} | ||
| 37 | end | ||
| 38 | |||
| 39 | it 'calls the second filter for route recognition' do | ||
| 40 | @pagination_filter.should_receive(:around_recognize).and_return :foo => :bar | ||
| 41 | recognize_path.should == {:foo => :bar} | ||
| 42 | end | ||
| 43 | |||
| 44 | it 'calls the first filter for url generation' do | ||
| 45 | @locale_filter.should_receive(:around_generate).and_return '/sections/1' | ||
| 46 | url_for :controller => 'sections', :action => 'show', :section_id => 1 | ||
| 47 | end | ||
| 48 | |||
| 49 | it 'calls the second filter for url generation' do | ||
| 50 | @pagination_filter.should_receive(:around_generate).and_return '/sections/1' | ||
| 51 | url_for :controller => 'sections', :action => 'show', :section_id => 1 | ||
| 52 | end | ||
| 53 | |||
| 54 | it 'calls the first filter for named route url_helper' do | ||
| 55 | @locale_filter.should_receive(:around_generate).and_return '/sections/1' | ||
| 56 | section_path :section_id => 1 | ||
| 57 | end | ||
| 58 | |||
| 59 | it 'calls the filter for named route url_helper with "optimized" generation blocks' do | ||
| 60 | # at_least(1) since the inline code comments in ActionController::Routing::RouteSet::NamedRouteCollection#define_url_helper also call us (as of http://github.com/rails/rails/commit/a2270ef2594b97891994848138614657363f2806) | ||
| 61 | @locale_filter.should_receive(:around_generate).at_least(1).and_return '/sections/1' | ||
| 62 | section_path 1 | ||
| 63 | end | ||
| 64 | |||
| 65 | it 'calls the filter for named route polymorphic_path' do | ||
| 66 | # at_least(1) since the inline code comments in ActionController::Routing::RouteSet::NamedRouteCollection#define_url_helper also call us (as of http://github.com/rails/rails/commit/a2270ef2594b97891994848138614657363f2806) | ||
| 67 | @locale_filter.should_receive(:around_generate).at_least(1).and_return '/sections/1' | ||
| 68 | section_path Section.new | ||
| 69 | end | ||
| 70 | end \ No newline at end of file | ||
diff --git a/vendor/plugins/routing-filter/spec/spec.opts b/vendor/plugins/routing-filter/spec/spec.opts deleted file mode 100644 index 391705b..0000000 --- a/vendor/plugins/routing-filter/spec/spec.opts +++ /dev/null | |||
| @@ -1,4 +0,0 @@ | |||
| 1 | --colour | ||
| 2 | --format progress | ||
| 3 | --loadby mtime | ||
| 4 | --reverse | ||
diff --git a/vendor/plugins/routing-filter/spec/spec_helper.rb b/vendor/plugins/routing-filter/spec/spec_helper.rb deleted file mode 100644 index a92a3d9..0000000 --- a/vendor/plugins/routing-filter/spec/spec_helper.rb +++ /dev/null | |||
| @@ -1,49 +0,0 @@ | |||
| 1 | $: << File.dirname(__FILE__) | ||
| 2 | $: << File.dirname(__FILE__) + '/../lib/' | ||
| 3 | $: << File.dirname(__FILE__) + '/../vendor/rails/actionpack/lib' | ||
| 4 | $: << File.dirname(__FILE__) + '/../vendor/rails/activesupport/lib' | ||
| 5 | |||
| 6 | require 'action_controller' | ||
| 7 | require 'action_controller/test_process' | ||
| 8 | require 'active_support/vendor' | ||
| 9 | |||
| 10 | require 'routing_filter' | ||
| 11 | require 'routing_filter/locale' | ||
| 12 | require 'routing_filter/pagination' | ||
| 13 | |||
| 14 | class Site | ||
| 15 | end | ||
| 16 | |||
| 17 | class Section | ||
| 18 | def id; 1 end | ||
| 19 | alias :to_param :id | ||
| 20 | |||
| 21 | def type; 'Section' end | ||
| 22 | |||
| 23 | def path; 'section' end | ||
| 24 | end | ||
| 25 | |||
| 26 | class Article | ||
| 27 | def to_param; 1 end | ||
| 28 | end | ||
| 29 | |||
| 30 | module RoutingFilterHelpers | ||
| 31 | def draw_routes(&block) | ||
| 32 | set = returning ActionController::Routing::RouteSet.new do |set| | ||
| 33 | class << set; def clear!; end; end | ||
| 34 | set.draw &block | ||
| 35 | silence_warnings{ ActionController::Routing.const_set 'Routes', set } | ||
| 36 | end | ||
| 37 | set | ||
| 38 | end | ||
| 39 | |||
| 40 | def instantiate_controller(params) | ||
| 41 | returning ActionController::Base.new do |controller| | ||
| 42 | request = ActionController::TestRequest.new | ||
| 43 | url = ActionController::UrlRewriter.new(request, params) | ||
| 44 | controller.stub!(:request).and_return request | ||
| 45 | controller.instance_variable_set :@url, url | ||
| 46 | controller | ||
| 47 | end | ||
| 48 | end | ||
| 49 | end \ No newline at end of file | ||
diff --git a/vendor/plugins/will_paginate/.gitignore b/vendor/plugins/will_paginate/.gitignore deleted file mode 100644 index 2b437b9..0000000 --- a/vendor/plugins/will_paginate/.gitignore +++ /dev/null | |||
| @@ -1,4 +0,0 @@ | |||
| 1 | /doc | ||
| 2 | /rails | ||
| 3 | *.gem | ||
| 4 | /coverage | ||
diff --git a/vendor/plugins/will_paginate/.manifest b/vendor/plugins/will_paginate/.manifest deleted file mode 100644 index cda4af44..0000000 --- a/vendor/plugins/will_paginate/.manifest +++ /dev/null | |||
| @@ -1,49 +0,0 @@ | |||
| 1 | CHANGELOG.rdoc | ||
| 2 | LICENSE | ||
| 3 | README.rdoc | ||
| 4 | Rakefile | ||
| 5 | examples | ||
| 6 | examples/apple-circle.gif | ||
| 7 | examples/index.haml | ||
| 8 | examples/index.html | ||
| 9 | examples/pagination.css | ||
| 10 | examples/pagination.sass | ||
| 11 | init.rb | ||
| 12 | lib | ||
| 13 | lib/will_paginate | ||
| 14 | lib/will_paginate.rb | ||
| 15 | lib/will_paginate/array.rb | ||
| 16 | lib/will_paginate/collection.rb | ||
| 17 | lib/will_paginate/core_ext.rb | ||
| 18 | lib/will_paginate/finder.rb | ||
| 19 | lib/will_paginate/named_scope.rb | ||
| 20 | lib/will_paginate/named_scope_patch.rb | ||
| 21 | lib/will_paginate/version.rb | ||
| 22 | lib/will_paginate/view_helpers.rb | ||
| 23 | test | ||
| 24 | test/boot.rb | ||
| 25 | test/collection_test.rb | ||
| 26 | test/console | ||
| 27 | test/database.yml | ||
| 28 | test/finder_test.rb | ||
| 29 | test/fixtures | ||
| 30 | test/fixtures/admin.rb | ||
| 31 | test/fixtures/developer.rb | ||
| 32 | test/fixtures/developers_projects.yml | ||
| 33 | test/fixtures/project.rb | ||
| 34 | test/fixtures/projects.yml | ||
| 35 | test/fixtures/replies.yml | ||
| 36 | test/fixtures/reply.rb | ||
| 37 | test/fixtures/schema.rb | ||
| 38 | test/fixtures/topic.rb | ||
| 39 | test/fixtures/topics.yml | ||
| 40 | test/fixtures/user.rb | ||
| 41 | test/fixtures/users.yml | ||
| 42 | test/helper.rb | ||
| 43 | test/lib | ||
| 44 | test/lib/activerecord_test_case.rb | ||
| 45 | test/lib/activerecord_test_connector.rb | ||
| 46 | test/lib/load_fixtures.rb | ||
| 47 | test/lib/view_test_process.rb | ||
| 48 | test/tasks.rake | ||
| 49 | test/view_test.rb \ No newline at end of file | ||
diff --git a/vendor/plugins/will_paginate/CHANGELOG.rdoc b/vendor/plugins/will_paginate/CHANGELOG.rdoc deleted file mode 100644 index 01aea3a..0000000 --- a/vendor/plugins/will_paginate/CHANGELOG.rdoc +++ /dev/null | |||
| @@ -1,110 +0,0 @@ | |||
| 1 | == 2.3.6, released 2008-10-26 | ||
| 2 | |||
| 3 | * Rails 2.2 fix: stop using `extract_attribute_names_from_match` inernal AR method, it no longer exists | ||
| 4 | |||
| 5 | == 2.3.5, released 2008-10-07 | ||
| 6 | |||
| 7 | * update the backported named_scope implementation for Rails versions older than 2.1 | ||
| 8 | * break out of scope of paginated_each() yielded block when used on named scopes | ||
| 9 | * fix paginate(:from) | ||
| 10 | |||
| 11 | == 2.3.4, released 2008-09-16 | ||
| 12 | |||
| 13 | * Removed gem dependency to Active Support (causes trouble with vendored rails). | ||
| 14 | * Rails 2.1: fix a failing test and a deprecation warning. | ||
| 15 | * Cope with scoped :select when counting. | ||
| 16 | |||
| 17 | == 2.3.3, released 2008-08-29 | ||
| 18 | |||
| 19 | * Ensure that paginate_by_sql doesn't change the original SQL query. | ||
| 20 | * RDoc love (now live at http://mislav.caboo.se/static/will_paginate/doc/) | ||
| 21 | * Rename :prev_label to :previous_label for consistency. old name still functions but is deprecated | ||
| 22 | * ActiveRecord 2.1: Remove :include option from count_all query when it's possible. | ||
| 23 | |||
| 24 | == 2.3.2, released 2008-05-16 | ||
| 25 | |||
| 26 | * Fixed LinkRenderer#stringified_merge by removing "return" from iterator block | ||
| 27 | * Ensure that 'href' values in pagination links are escaped URLs | ||
| 28 | |||
| 29 | == 2.3.1, released 2008-05-04 | ||
| 30 | |||
| 31 | * Fixed page numbers not showing with custom routes and implicit first page | ||
| 32 | * Try to use Hanna for documentation (falls back to default RDoc template if not) | ||
| 33 | |||
| 34 | == 2.3.0, released 2008-04-29 | ||
| 35 | |||
| 36 | * Changed LinkRenderer to receive collection, options and reference to view template NOT in | ||
| 37 | constructor, but with the #prepare method. This is a step towards supporting passing of | ||
| 38 | LinkRenderer (or subclass) instances that may be preconfigured in some way | ||
| 39 | * LinkRenderer now has #page_link and #page_span methods for easier customization of output in | ||
| 40 | subclasses | ||
| 41 | * Changed page_entries_info() method to adjust its output according to humanized class name of | ||
| 42 | collection items. Override this with :entry_name parameter (singular). | ||
| 43 | |||
| 44 | page_entries_info(@posts) | ||
| 45 | #-> "Displaying all 12 posts" | ||
| 46 | page_entries_info(@posts, :entry_name => 'item') | ||
| 47 | #-> "Displaying all 12 items" | ||
| 48 | |||
| 49 | == 2.2.3, released 2008-04-26 | ||
| 50 | |||
| 51 | * will_paginate gem is no longer published on RubyForge, but on | ||
| 52 | gems.github.com: | ||
| 53 | |||
| 54 | gem sources -a http://gems.github.com/ (you only need to do this once) | ||
| 55 | gem install mislav-will_paginate | ||
| 56 | |||
| 57 | * extract reusable pagination testing stuff into WillPaginate::View | ||
| 58 | * rethink the page URL construction mechanizm to be more bulletproof when | ||
| 59 | combined with custom routing for page parameter | ||
| 60 | * test that anchor parameter can be used in pagination links | ||
| 61 | |||
| 62 | == 2.2.2, released 2008-04-21 | ||
| 63 | |||
| 64 | * Add support for page parameter in custom routes like "/foo/page/2" | ||
| 65 | * Change output of "page_entries_info" on single-page collection and erraneous | ||
| 66 | output with empty collection as reported by Tim Chater | ||
| 67 | |||
| 68 | == 2.2.1, released 2008-04-08 | ||
| 69 | |||
| 70 | * take less risky path when monkeypatching named_scope; fix that it no longer | ||
| 71 | requires ActiveRecord::VERSION | ||
| 72 | * use strings in "respond_to?" calls to work around a bug in acts_as_ferret | ||
| 73 | stable (ugh) | ||
| 74 | * add rake release task | ||
| 75 | |||
| 76 | |||
| 77 | == 2.2.0, released 2008-04-07 | ||
| 78 | |||
| 79 | === API changes | ||
| 80 | * Rename WillPaginate::Collection#page_count to "total_pages" for consistency. | ||
| 81 | If you implemented this interface, change your implementation accordingly. | ||
| 82 | * Remove old, deprecated style of calling Array#paginate as "paginate(page, | ||
| 83 | per_page)". If you want to specify :page, :per_page or :total_entries, use a | ||
| 84 | parameter hash. | ||
| 85 | * Rename LinkRenderer#url_options to "url_for" and drastically optimize it | ||
| 86 | |||
| 87 | === View changes | ||
| 88 | * Added "prev_page" and "next_page" CSS classes on previous/next page buttons | ||
| 89 | * Add examples of pagination links styling in "examples/index.html" | ||
| 90 | * Change gap in pagination links from "..." to | ||
| 91 | "<span class="gap">…</span>". | ||
| 92 | * Add "paginated_section", a block helper that renders pagination both above and | ||
| 93 | below content in the block | ||
| 94 | * Add rel="prev|next|start" to page links | ||
| 95 | |||
| 96 | === Other | ||
| 97 | |||
| 98 | * Add ability to opt-in for Rails 2.1 feature "named_scope" by calling | ||
| 99 | WillPaginate.enable_named_scope (tested in Rails 1.2.6 and 2.0.2) | ||
| 100 | * Support complex page parameters like "developers[page]" | ||
| 101 | * Move Array#paginate definition to will_paginate/array.rb. You can now easily | ||
| 102 | use pagination on arrays outside of Rails: | ||
| 103 | |||
| 104 | gem 'will_paginate' | ||
| 105 | require 'will_paginate/array' | ||
| 106 | |||
| 107 | * Add "paginated_each" method for iterating through every record by loading only | ||
| 108 | one page of records at the time | ||
| 109 | * Rails 2: Rescue from WillPaginate::InvalidPage error with 404 Not Found by | ||
| 110 | default | ||
diff --git a/vendor/plugins/will_paginate/LICENSE b/vendor/plugins/will_paginate/LICENSE deleted file mode 100644 index 96a48cb..0000000 --- a/vendor/plugins/will_paginate/LICENSE +++ /dev/null | |||
| @@ -1,18 +0,0 @@ | |||
| 1 | Copyright (c) 2007 PJ Hyett and Mislav Marohnić | ||
| 2 | |||
| 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
| 4 | this software and associated documentation files (the "Software"), to deal in | ||
| 5 | the Software without restriction, including without limitation the rights to | ||
| 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||
| 7 | the Software, and to permit persons to whom the Software is furnished to do so, | ||
| 8 | subject to the following conditions: | ||
| 9 | |||
| 10 | The above copyright notice and this permission notice shall be included in all | ||
| 11 | copies or substantial portions of the Software. | ||
| 12 | |||
| 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||
| 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||
| 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||
| 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
| 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
diff --git a/vendor/plugins/will_paginate/README.rdoc b/vendor/plugins/will_paginate/README.rdoc deleted file mode 100644 index 2a412f5..0000000 --- a/vendor/plugins/will_paginate/README.rdoc +++ /dev/null | |||
| @@ -1,107 +0,0 @@ | |||
| 1 | = WillPaginate | ||
| 2 | |||
| 3 | Pagination is just limiting the number of records displayed. Why should you let | ||
| 4 | it get in your way while developing, then? This plugin makes magic happen. Did | ||
| 5 | you ever want to be able to do just this on a model: | ||
| 6 | |||
| 7 | Post.paginate :page => 1, :order => 'created_at DESC' | ||
| 8 | |||
| 9 | ... and then render the page links with a single view helper? Well, now you | ||
| 10 | can. | ||
| 11 | |||
| 12 | Some resources to get you started: | ||
| 13 | |||
| 14 | * {Installation instructions}[http://github.com/mislav/will_paginate/wikis/installation] | ||
| 15 | on {the wiki}[http://github.com/mislav/will_paginate/wikis] | ||
| 16 | * Your mind reels with questions? Join our | ||
| 17 | {Google group}[http://groups.google.com/group/will_paginate]. | ||
| 18 | * {How to report bugs}[http://github.com/mislav/will_paginate/wikis/report-bugs] | ||
| 19 | |||
| 20 | |||
| 21 | == Example usage | ||
| 22 | |||
| 23 | Use a paginate finder in the controller: | ||
| 24 | |||
| 25 | @posts = Post.paginate_by_board_id @board.id, :page => params[:page], :order => 'updated_at DESC' | ||
| 26 | |||
| 27 | Yeah, +paginate+ works just like +find+ -- it just doesn't fetch all the | ||
| 28 | records. Don't forget to tell it which page you want, or it will complain! | ||
| 29 | Read more on WillPaginate::Finder::ClassMethods. | ||
| 30 | |||
| 31 | Render the posts in your view like you would normally do. When you need to render | ||
| 32 | pagination, just stick this in: | ||
| 33 | |||
| 34 | <%= will_paginate @posts %> | ||
| 35 | |||
| 36 | You're done. (You can find the option list at WillPaginate::ViewHelpers.) | ||
| 37 | |||
| 38 | How does it know how much items to fetch per page? It asks your model by calling | ||
| 39 | its <tt>per_page</tt> class method. You can define it like this: | ||
| 40 | |||
| 41 | class Post < ActiveRecord::Base | ||
| 42 | cattr_reader :per_page | ||
| 43 | @@per_page = 50 | ||
| 44 | end | ||
| 45 | |||
| 46 | ... or like this: | ||
| 47 | |||
| 48 | class Post < ActiveRecord::Base | ||
| 49 | def self.per_page | ||
| 50 | 50 | ||
| 51 | end | ||
| 52 | end | ||
| 53 | |||
| 54 | ... or don't worry about it at all. WillPaginate defines it to be <b>30</b> by default. | ||
| 55 | But you can always specify the count explicitly when calling +paginate+: | ||
| 56 | |||
| 57 | @posts = Post.paginate :page => params[:page], :per_page => 50 | ||
| 58 | |||
| 59 | The +paginate+ finder wraps the original finder and returns your resultset that now has | ||
| 60 | some new properties. You can use the collection as you would with any ActiveRecord | ||
| 61 | resultset. WillPaginate view helpers also need that object to be able to render pagination: | ||
| 62 | |||
| 63 | <ol> | ||
| 64 | <% for post in @posts -%> | ||
| 65 | <li>Render `post` in some nice way.</li> | ||
| 66 | <% end -%> | ||
| 67 | </ol> | ||
| 68 | |||
| 69 | <p>Now let's render us some pagination!</p> | ||
| 70 | <%= will_paginate @posts %> | ||
| 71 | |||
| 72 | More detailed documentation: | ||
| 73 | |||
| 74 | * WillPaginate::Finder::ClassMethods for pagination on your models; | ||
| 75 | * WillPaginate::ViewHelpers for your views. | ||
| 76 | |||
| 77 | |||
| 78 | == Authors and credits | ||
| 79 | |||
| 80 | Authors:: Mislav Marohnić, PJ Hyett | ||
| 81 | Original announcement:: http://errtheblog.com/post/929 | ||
| 82 | Original PHP source:: http://www.strangerstudios.com/sandbox/pagination/diggstyle.php | ||
| 83 | |||
| 84 | All these people helped making will_paginate what it is now with their code | ||
| 85 | contributions or just simply awesome ideas: | ||
| 86 | |||
| 87 | Chris Wanstrath, Dr. Nic Williams, K. Adam Christensen, Mike Garey, Bence | ||
| 88 | Golda, Matt Aimonetti, Charles Brian Quinn, Desi McAdam, James Coglan, Matijs | ||
| 89 | van Zuijlen, Maria, Brendan Ribera, Todd Willey, Bryan Helmkamp, Jan Berkel, | ||
| 90 | Lourens Naudé, Rick Olson, Russell Norris, Piotr Usewicz, Chris Eppstein, | ||
| 91 | Denis Barushev, Ben Pickles. | ||
| 92 | |||
| 93 | |||
| 94 | == Usable pagination in the UI | ||
| 95 | |||
| 96 | There are some CSS styles to get you started in the "examples/" directory. They | ||
| 97 | are {showcased online here}[http://mislav.caboo.se/static/will_paginate/]. | ||
| 98 | |||
| 99 | More reading about pagination as design pattern: | ||
| 100 | |||
| 101 | * {Pagination 101}[http://kurafire.net/log/archive/2007/06/22/pagination-101] | ||
| 102 | * {Pagination gallery}[http://www.smashingmagazine.com/2007/11/16/pagination-gallery-examples-and-good-practices/] | ||
| 103 | * {Pagination on Yahoo Design Pattern Library}[http://developer.yahoo.com/ypatterns/parent.php?pattern=pagination] | ||
| 104 | |||
| 105 | Want to discuss, request features, ask questions? Join the | ||
| 106 | {Google group}[http://groups.google.com/group/will_paginate]. | ||
| 107 | |||
diff --git a/vendor/plugins/will_paginate/Rakefile b/vendor/plugins/will_paginate/Rakefile deleted file mode 100644 index 253efd0..0000000 --- a/vendor/plugins/will_paginate/Rakefile +++ /dev/null | |||
| @@ -1,62 +0,0 @@ | |||
| 1 | require 'rubygems' | ||
| 2 | begin | ||
| 3 | hanna_dir = '/Users/mislav/Projects/Hanna/lib' | ||
| 4 | $:.unshift hanna_dir if File.exists? hanna_dir | ||
| 5 | require 'hanna/rdoctask' | ||
| 6 | rescue LoadError | ||
| 7 | require 'rake' | ||
| 8 | require 'rake/rdoctask' | ||
| 9 | end | ||
| 10 | load 'test/tasks.rake' | ||
| 11 | |||
| 12 | desc 'Default: run unit tests.' | ||
| 13 | task :default => :test | ||
| 14 | |||
| 15 | desc 'Generate RDoc documentation for the will_paginate plugin.' | ||
| 16 | Rake::RDocTask.new(:rdoc) do |rdoc| | ||
| 17 | rdoc.rdoc_files.include('README.rdoc', 'LICENSE', 'CHANGELOG.rdoc'). | ||
| 18 | include('lib/**/*.rb'). | ||
| 19 | exclude('lib/will_paginate/named_scope*'). | ||
| 20 | exclude('lib/will_paginate/array.rb'). | ||
| 21 | exclude('lib/will_paginate/version.rb') | ||
| 22 | |||
| 23 | rdoc.main = "README.rdoc" # page to start on | ||
| 24 | rdoc.title = "will_paginate documentation" | ||
| 25 | |||
| 26 | rdoc.rdoc_dir = 'doc' # rdoc output folder | ||
| 27 | rdoc.options << '--inline-source' << '--charset=UTF-8' | ||
| 28 | rdoc.options << '--webcvs=http://github.com/mislav/will_paginate/tree/master/' | ||
| 29 | end | ||
| 30 | |||
| 31 | desc %{Update ".manifest" with the latest list of project filenames. Respect\ | ||
| 32 | .gitignore by excluding everything that git ignores. Update `files` and\ | ||
| 33 | `test_files` arrays in "*.gemspec" file if it's present.} | ||
| 34 | task :manifest do | ||
| 35 | list = Dir['**/*'].sort | ||
| 36 | spec_file = Dir['*.gemspec'].first | ||
| 37 | list -= [spec_file] if spec_file | ||
| 38 | |||
| 39 | File.read('.gitignore').each_line do |glob| | ||
| 40 | glob = glob.chomp.sub(/^\//, '') | ||
| 41 | list -= Dir[glob] | ||
| 42 | list -= Dir["#{glob}/**/*"] if File.directory?(glob) and !File.symlink?(glob) | ||
| 43 | puts "excluding #{glob}" | ||
| 44 | end | ||
| 45 | |||
| 46 | if spec_file | ||
| 47 | spec = File.read spec_file | ||
| 48 | spec.gsub! /^(\s* s.(test_)?files \s* = \s* )( \[ [^\]]* \] | %w\( [^)]* \) )/mx do | ||
| 49 | assignment = $1 | ||
| 50 | bunch = $2 ? list.grep(/^test\//) : list | ||
| 51 | '%s%%w(%s)' % [assignment, bunch.join(' ')] | ||
| 52 | end | ||
| 53 | |||
| 54 | File.open(spec_file, 'w') {|f| f << spec } | ||
| 55 | end | ||
| 56 | File.open('.manifest', 'w') {|f| f << list.join("\n") } | ||
| 57 | end | ||
| 58 | |||
| 59 | task :examples do | ||
| 60 | %x(haml examples/index.haml examples/index.html) | ||
| 61 | %x(sass examples/pagination.sass examples/pagination.css) | ||
| 62 | end | ||
diff --git a/vendor/plugins/will_paginate/examples/apple-circle.gif b/vendor/plugins/will_paginate/examples/apple-circle.gif deleted file mode 100644 index df8cbf7..0000000 --- a/vendor/plugins/will_paginate/examples/apple-circle.gif +++ /dev/null | |||
| Binary files differ | |||
diff --git a/vendor/plugins/will_paginate/examples/index.haml b/vendor/plugins/will_paginate/examples/index.haml deleted file mode 100644 index fb41ac8..0000000 --- a/vendor/plugins/will_paginate/examples/index.haml +++ /dev/null | |||
| @@ -1,69 +0,0 @@ | |||
| 1 | !!! | ||
| 2 | %html | ||
| 3 | %head | ||
| 4 | %title Samples of pagination styling for will_paginate | ||
| 5 | %link{ :rel => 'stylesheet', :type => 'text/css', :href => 'pagination.css' } | ||
| 6 | %style{ :type => 'text/css' } | ||
| 7 | :sass | ||
| 8 | html | ||
| 9 | :margin 0 | ||
| 10 | :padding 0 | ||
| 11 | :background #999 | ||
| 12 | :font normal 76% "Lucida Grande", Verdana, Helvetica, sans-serif | ||
| 13 | body | ||
| 14 | :margin 2em | ||
| 15 | :padding 2em | ||
| 16 | :border 2px solid gray | ||
| 17 | :background white | ||
| 18 | :color #222 | ||
| 19 | h1 | ||
| 20 | :font-size 2em | ||
| 21 | :font-weight normal | ||
| 22 | :margin 0 0 1em 0 | ||
| 23 | h2 | ||
| 24 | :font-size 1.4em | ||
| 25 | :margin 1em 0 .5em 0 | ||
| 26 | pre | ||
| 27 | :font-size 13px | ||
| 28 | :font-family Monaco, "DejaVu Sans Mono", "Bitstream Vera Mono", "Courier New", monospace | ||
| 29 | |||
| 30 | - pagination = '<span class="disabled prev_page">« Previous</span> <span class="current">1</span> <a href="./?page=2" rel="next">2</a> <a href="./?page=3">3</a> <a href="./?page=4">4</a> <a href="./?page=5">5</a> <a href="./?page=6">6</a> <a href="./?page=7">7</a> <a href="./?page=8">8</a> <a href="./?page=9">9</a> <span class="gap">…</span> <a href="./?page=29">29</a> <a href="./?page=30">30</a> <a href="./?page=2" rel="next" class="next_page">Next »</a>' | ||
| 31 | - pagination_no_page_links = '<span class="disabled prev_page">« Previous</span> <a href="./?page=2" rel="next" class="next_page">Next »</a>' | ||
| 32 | |||
| 33 | %body | ||
| 34 | %h1 Samples of pagination styling for will_paginate | ||
| 35 | %p | ||
| 36 | Find these styles in <b>"examples/pagination.css"</b> of <i>will_paginate</i> library. | ||
| 37 | There is a Sass version of it for all you sassy people. | ||
| 38 | %p | ||
| 39 | Read about good rules for pagination: | ||
| 40 | %a{ :href => 'http://kurafire.net/log/archive/2007/06/22/pagination-101' } Pagination 101 | ||
| 41 | %p | ||
| 42 | %em Warning: | ||
| 43 | page links below don't lead anywhere (so don't click on them). | ||
| 44 | |||
| 45 | %h2 Unstyled pagination <span style="font-weight:normal">(<i>ewww!</i>)</span> | ||
| 46 | %div= pagination | ||
| 47 | |||
| 48 | %h2 Digg.com | ||
| 49 | .digg_pagination= pagination | ||
| 50 | |||
| 51 | %h2 Digg-style, no page links | ||
| 52 | .digg_pagination= pagination_no_page_links | ||
| 53 | %p Code that renders this: | ||
| 54 | %pre= '<code>%s</code>' % %[<%= will_paginate @posts, :page_links => false %>].gsub('<', '<').gsub('>', '>') | ||
| 55 | |||
| 56 | %h2 Digg-style, extra content | ||
| 57 | .digg_pagination | ||
| 58 | .page_info Displaying entries <b>1 - 6</b> of <b>180</b> in total | ||
| 59 | = pagination | ||
| 60 | %p Code that renders this: | ||
| 61 | %pre= '<code>%s</code>' % %[<div class="digg_pagination">\n <div clas="page_info">\n <%= page_entries_info @posts %>\n </div>\n <%= will_paginate @posts, :container => false %>\n</div>].gsub('<', '<').gsub('>', '>') | ||
| 62 | |||
| 63 | %h2 Apple.com store | ||
| 64 | .apple_pagination= pagination | ||
| 65 | |||
| 66 | %h2 Flickr.com | ||
| 67 | .flickr_pagination | ||
| 68 | = pagination | ||
| 69 | .page_info (118 photos) | ||
diff --git a/vendor/plugins/will_paginate/examples/index.html b/vendor/plugins/will_paginate/examples/index.html deleted file mode 100644 index 858f7c6..0000000 --- a/vendor/plugins/will_paginate/examples/index.html +++ /dev/null | |||
| @@ -1,92 +0,0 @@ | |||
| 1 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | ||
| 2 | <html> | ||
| 3 | </html> | ||
| 4 | <head> | ||
| 5 | <title>Samples of pagination styling for will_paginate</title> | ||
| 6 | <link href='pagination.css' rel='stylesheet' type='text/css' /> | ||
| 7 | <style type='text/css'> | ||
| 8 | html { | ||
| 9 | margin: 0; | ||
| 10 | padding: 0; | ||
| 11 | background: #999; | ||
| 12 | font: normal 76% "Lucida Grande", Verdana, Helvetica, sans-serif; } | ||
| 13 | |||
| 14 | body { | ||
| 15 | margin: 2em; | ||
| 16 | padding: 2em; | ||
| 17 | border: 2px solid gray; | ||
| 18 | background: white; | ||
| 19 | color: #222; } | ||
| 20 | |||
| 21 | h1 { | ||
| 22 | font-size: 2em; | ||
| 23 | font-weight: normal; | ||
| 24 | margin: 0 0 1em 0; } | ||
| 25 | |||
| 26 | h2 { | ||
| 27 | font-size: 1.4em; | ||
| 28 | margin: 1em 0 .5em 0; } | ||
| 29 | |||
| 30 | pre { | ||
| 31 | font-size: 13px; | ||
| 32 | font-family: Monaco, "DejaVu Sans Mono", "Bitstream Vera Mono", "Courier New", monospace; } | ||
| 33 | </style> | ||
| 34 | </head> | ||
| 35 | <body> | ||
| 36 | <h1>Samples of pagination styling for will_paginate</h1> | ||
| 37 | <p> | ||
| 38 | Find these styles in <b>"examples/pagination.css"</b> of <i>will_paginate</i> library. | ||
| 39 | There is a Sass version of it for all you sassy people. | ||
| 40 | </p> | ||
| 41 | <p> | ||
| 42 | Read about good rules for pagination: | ||
| 43 | <a href='http://kurafire.net/log/archive/2007/06/22/pagination-101'>Pagination 101</a> | ||
| 44 | </p> | ||
| 45 | <p> | ||
| 46 | <em>Warning:</em> | ||
| 47 | page links below don't lead anywhere (so don't click on them). | ||
| 48 | </p> | ||
| 49 | <h2> | ||
| 50 | Unstyled pagination <span style="font-weight:normal">(<i>ewww!</i>)</span> | ||
| 51 | </h2> | ||
| 52 | <div> | ||
| 53 | <span class="disabled prev_page">« Previous</span> <span class="current">1</span> <a href="./?page=2" rel="next">2</a> <a href="./?page=3">3</a> <a href="./?page=4">4</a> <a href="./?page=5">5</a> <a href="./?page=6">6</a> <a href="./?page=7">7</a> <a href="./?page=8">8</a> <a href="./?page=9">9</a> <span class="gap">…</span> <a href="./?page=29">29</a> <a href="./?page=30">30</a> <a href="./?page=2" rel="next" class="next_page">Next »</a> | ||
| 54 | </div> | ||
| 55 | <h2>Digg.com</h2> | ||
| 56 | <div class='digg_pagination'> | ||
| 57 | <span class="disabled prev_page">« Previous</span> <span class="current">1</span> <a href="./?page=2" rel="next">2</a> <a href="./?page=3">3</a> <a href="./?page=4">4</a> <a href="./?page=5">5</a> <a href="./?page=6">6</a> <a href="./?page=7">7</a> <a href="./?page=8">8</a> <a href="./?page=9">9</a> <span class="gap">…</span> <a href="./?page=29">29</a> <a href="./?page=30">30</a> <a href="./?page=2" rel="next" class="next_page">Next »</a> | ||
| 58 | </div> | ||
| 59 | <h2>Digg-style, no page links</h2> | ||
| 60 | <div class='digg_pagination'> | ||
| 61 | <span class="disabled prev_page">« Previous</span> <a href="./?page=2" rel="next" class="next_page">Next »</a> | ||
| 62 | </div> | ||
| 63 | <p>Code that renders this:</p> | ||
| 64 | <pre> | ||
| 65 | <code><%= will_paginate @posts, :page_links => false %></code> | ||
| 66 | </pre> | ||
| 67 | <h2>Digg-style, extra content</h2> | ||
| 68 | <div class='digg_pagination'> | ||
| 69 | <div class='page_info'> | ||
| 70 | Displaying entries <b>1 - 6</b> of <b>180</b> in total | ||
| 71 | </div> | ||
| 72 | <span class="disabled prev_page">« Previous</span> <span class="current">1</span> <a href="./?page=2" rel="next">2</a> <a href="./?page=3">3</a> <a href="./?page=4">4</a> <a href="./?page=5">5</a> <a href="./?page=6">6</a> <a href="./?page=7">7</a> <a href="./?page=8">8</a> <a href="./?page=9">9</a> <span class="gap">…</span> <a href="./?page=29">29</a> <a href="./?page=30">30</a> <a href="./?page=2" rel="next" class="next_page">Next »</a> | ||
| 73 | </div> | ||
| 74 | <p>Code that renders this:</p> | ||
| 75 | <pre> | ||
| 76 | <code><div class="digg_pagination"> | ||
| 77 | <div clas="page_info"> | ||
| 78 | <%= page_entries_info @posts %> | ||
| 79 | </div> | ||
| 80 | <%= will_paginate @posts, :container => false %> | ||
| 81 | </div></code> | ||
| 82 | </pre> | ||
| 83 | <h2>Apple.com store</h2> | ||
| 84 | <div class='apple_pagination'> | ||
| 85 | <span class="disabled prev_page">« Previous</span> <span class="current">1</span> <a href="./?page=2" rel="next">2</a> <a href="./?page=3">3</a> <a href="./?page=4">4</a> <a href="./?page=5">5</a> <a href="./?page=6">6</a> <a href="./?page=7">7</a> <a href="./?page=8">8</a> <a href="./?page=9">9</a> <span class="gap">…</span> <a href="./?page=29">29</a> <a href="./?page=30">30</a> <a href="./?page=2" rel="next" class="next_page">Next »</a> | ||
| 86 | </div> | ||
| 87 | <h2>Flickr.com</h2> | ||
| 88 | <div class='flickr_pagination'> | ||
| 89 | <span class="disabled prev_page">« Previous</span> <span class="current">1</span> <a href="./?page=2" rel="next">2</a> <a href="./?page=3">3</a> <a href="./?page=4">4</a> <a href="./?page=5">5</a> <a href="./?page=6">6</a> <a href="./?page=7">7</a> <a href="./?page=8">8</a> <a href="./?page=9">9</a> <span class="gap">…</span> <a href="./?page=29">29</a> <a href="./?page=30">30</a> <a href="./?page=2" rel="next" class="next_page">Next »</a> | ||
| 90 | <div class='page_info'>(118 photos)</div> | ||
| 91 | </div> | ||
| 92 | </body> | ||
diff --git a/vendor/plugins/will_paginate/examples/pagination.css b/vendor/plugins/will_paginate/examples/pagination.css deleted file mode 100644 index b55e977..0000000 --- a/vendor/plugins/will_paginate/examples/pagination.css +++ /dev/null | |||
| @@ -1,90 +0,0 @@ | |||
| 1 | .digg_pagination { | ||
| 2 | background: white; | ||
| 3 | /* self-clearing method: */ } | ||
| 4 | .digg_pagination a, .digg_pagination span { | ||
| 5 | padding: .2em .5em; | ||
| 6 | display: block; | ||
| 7 | float: left; | ||
| 8 | margin-right: 1px; } | ||
| 9 | .digg_pagination span.disabled { | ||
| 10 | color: #999; | ||
| 11 | border: 1px solid #DDD; } | ||
| 12 | .digg_pagination span.current { | ||
| 13 | font-weight: bold; | ||
| 14 | background: #2E6AB1; | ||
| 15 | color: white; | ||
| 16 | border: 1px solid #2E6AB1; } | ||
| 17 | .digg_pagination a { | ||
| 18 | text-decoration: none; | ||
| 19 | color: #105CB6; | ||
| 20 | border: 1px solid #9AAFE5; } | ||
| 21 | .digg_pagination a:hover, .digg_pagination a:focus { | ||
| 22 | color: #003; | ||
| 23 | border-color: #003; } | ||
| 24 | .digg_pagination .page_info { | ||
| 25 | background: #2E6AB1; | ||
| 26 | color: white; | ||
| 27 | padding: .4em .6em; | ||
| 28 | width: 22em; | ||
| 29 | margin-bottom: .3em; | ||
| 30 | text-align: center; } | ||
| 31 | .digg_pagination .page_info b { | ||
| 32 | color: #003; | ||
| 33 | background: #6aa6ed; | ||
| 34 | padding: .1em .25em; } | ||
| 35 | .digg_pagination:after { | ||
| 36 | content: "."; | ||
| 37 | display: block; | ||
| 38 | height: 0; | ||
| 39 | clear: both; | ||
| 40 | visibility: hidden; } | ||
| 41 | * html .digg_pagination { | ||
| 42 | height: 1%; } | ||
| 43 | *:first-child+html .digg_pagination { | ||
| 44 | overflow: hidden; } | ||
| 45 | |||
| 46 | .apple_pagination { | ||
| 47 | background: #F1F1F1; | ||
| 48 | border: 1px solid #E5E5E5; | ||
| 49 | text-align: center; | ||
| 50 | padding: 1em; } | ||
| 51 | .apple_pagination a, .apple_pagination span { | ||
| 52 | padding: .2em .3em; } | ||
| 53 | .apple_pagination span.disabled { | ||
| 54 | color: #AAA; } | ||
| 55 | .apple_pagination span.current { | ||
| 56 | font-weight: bold; | ||
| 57 | background: transparent url(apple-circle.gif) no-repeat 50% 50%; } | ||
| 58 | .apple_pagination a { | ||
| 59 | text-decoration: none; | ||
| 60 | color: black; } | ||
| 61 | .apple_pagination a:hover, .apple_pagination a:focus { | ||
| 62 | text-decoration: underline; } | ||
| 63 | |||
| 64 | .flickr_pagination { | ||
| 65 | text-align: center; | ||
| 66 | padding: .3em; } | ||
| 67 | .flickr_pagination a, .flickr_pagination span { | ||
| 68 | padding: .2em .5em; } | ||
| 69 | .flickr_pagination span.disabled { | ||
| 70 | color: #AAA; } | ||
| 71 | .flickr_pagination span.current { | ||
| 72 | font-weight: bold; | ||
| 73 | color: #FF0084; } | ||
| 74 | .flickr_pagination a { | ||
| 75 | border: 1px solid #DDDDDD; | ||
| 76 | color: #0063DC; | ||
| 77 | text-decoration: none; } | ||
| 78 | .flickr_pagination a:hover, .flickr_pagination a:focus { | ||
| 79 | border-color: #003366; | ||
| 80 | background: #0063DC; | ||
| 81 | color: white; } | ||
| 82 | .flickr_pagination .page_info { | ||
| 83 | color: #aaa; | ||
| 84 | padding-top: .8em; } | ||
| 85 | .flickr_pagination .prev_page, .flickr_pagination .next_page { | ||
| 86 | border-width: 2px; } | ||
| 87 | .flickr_pagination .prev_page { | ||
| 88 | margin-right: 1em; } | ||
| 89 | .flickr_pagination .next_page { | ||
| 90 | margin-left: 1em; } | ||
diff --git a/vendor/plugins/will_paginate/examples/pagination.sass b/vendor/plugins/will_paginate/examples/pagination.sass deleted file mode 100644 index 737a97b..0000000 --- a/vendor/plugins/will_paginate/examples/pagination.sass +++ /dev/null | |||
| @@ -1,91 +0,0 @@ | |||
| 1 | .digg_pagination | ||
| 2 | :background white | ||
| 3 | a, span | ||
| 4 | :padding .2em .5em | ||
| 5 | :display block | ||
| 6 | :float left | ||
| 7 | :margin-right 1px | ||
| 8 | span.disabled | ||
| 9 | :color #999 | ||
| 10 | :border 1px solid #DDD | ||
| 11 | span.current | ||
| 12 | :font-weight bold | ||
| 13 | :background #2E6AB1 | ||
| 14 | :color white | ||
| 15 | :border 1px solid #2E6AB1 | ||
| 16 | a | ||
| 17 | :text-decoration none | ||
| 18 | :color #105CB6 | ||
| 19 | :border 1px solid #9AAFE5 | ||
| 20 | &:hover, &:focus | ||
| 21 | :color #003 | ||
| 22 | :border-color #003 | ||
| 23 | .page_info | ||
| 24 | :background #2E6AB1 | ||
| 25 | :color white | ||
| 26 | :padding .4em .6em | ||
| 27 | :width 22em | ||
| 28 | :margin-bottom .3em | ||
| 29 | :text-align center | ||
| 30 | b | ||
| 31 | :color #003 | ||
| 32 | :background = #2E6AB1 + 60 | ||
| 33 | :padding .1em .25em | ||
| 34 | |||
| 35 | /* self-clearing method: | ||
| 36 | &:after | ||
| 37 | :content "." | ||
| 38 | :display block | ||
| 39 | :height 0 | ||
| 40 | :clear both | ||
| 41 | :visibility hidden | ||
| 42 | * html & | ||
| 43 | :height 1% | ||
| 44 | *:first-child+html & | ||
| 45 | :overflow hidden | ||
| 46 | |||
| 47 | .apple_pagination | ||
| 48 | :background #F1F1F1 | ||
| 49 | :border 1px solid #E5E5E5 | ||
| 50 | :text-align center | ||
| 51 | :padding 1em | ||
| 52 | a, span | ||
| 53 | :padding .2em .3em | ||
| 54 | span.disabled | ||
| 55 | :color #AAA | ||
| 56 | span.current | ||
| 57 | :font-weight bold | ||
| 58 | :background transparent url(apple-circle.gif) no-repeat 50% 50% | ||
| 59 | a | ||
| 60 | :text-decoration none | ||
| 61 | :color black | ||
| 62 | &:hover, &:focus | ||
| 63 | :text-decoration underline | ||
| 64 | |||
| 65 | .flickr_pagination | ||
| 66 | :text-align center | ||
| 67 | :padding .3em | ||
| 68 | a, span | ||
| 69 | :padding .2em .5em | ||
| 70 | span.disabled | ||
| 71 | :color #AAA | ||
| 72 | span.current | ||
| 73 | :font-weight bold | ||
| 74 | :color #FF0084 | ||
| 75 | a | ||
| 76 | :border 1px solid #DDDDDD | ||
| 77 | :color #0063DC | ||
| 78 | :text-decoration none | ||
| 79 | &:hover, &:focus | ||
| 80 | :border-color #003366 | ||
| 81 | :background #0063DC | ||
| 82 | :color white | ||
| 83 | .page_info | ||
| 84 | :color #aaa | ||
| 85 | :padding-top .8em | ||
| 86 | .prev_page, .next_page | ||
| 87 | :border-width 2px | ||
| 88 | .prev_page | ||
| 89 | :margin-right 1em | ||
| 90 | .next_page | ||
| 91 | :margin-left 1em | ||
diff --git a/vendor/plugins/will_paginate/init.rb b/vendor/plugins/will_paginate/init.rb deleted file mode 100644 index 838d30e..0000000 --- a/vendor/plugins/will_paginate/init.rb +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | require 'will_paginate' | ||
diff --git a/vendor/plugins/will_paginate/lib/will_paginate.rb b/vendor/plugins/will_paginate/lib/will_paginate.rb deleted file mode 100644 index e072412..0000000 --- a/vendor/plugins/will_paginate/lib/will_paginate.rb +++ /dev/null | |||
| @@ -1,78 +0,0 @@ | |||
| 1 | require 'active_support' | ||
| 2 | |||
| 3 | # = You *will* paginate! | ||
| 4 | # | ||
| 5 | # First read about WillPaginate::Finder::ClassMethods, then see | ||
| 6 | # WillPaginate::ViewHelpers. The magical array you're handling in-between is | ||
| 7 | # WillPaginate::Collection. | ||
| 8 | # | ||
| 9 | # Happy paginating! | ||
| 10 | module WillPaginate | ||
| 11 | class << self | ||
| 12 | # shortcut for <tt>enable_actionpack</tt> and <tt>enable_activerecord</tt> combined | ||
| 13 | def enable | ||
| 14 | enable_actionpack | ||
| 15 | enable_activerecord | ||
| 16 | end | ||
| 17 | |||
| 18 | # hooks WillPaginate::ViewHelpers into ActionView::Base | ||
| 19 | def enable_actionpack | ||
| 20 | return if ActionView::Base.instance_methods.include? 'will_paginate' | ||
| 21 | require 'will_paginate/view_helpers' | ||
| 22 | ActionView::Base.send :include, ViewHelpers | ||
| 23 | |||
| 24 | if defined?(ActionController::Base) and ActionController::Base.respond_to? :rescue_responses | ||
| 25 | ActionController::Base.rescue_responses['WillPaginate::InvalidPage'] = :not_found | ||
| 26 | end | ||
| 27 | end | ||
| 28 | |||
| 29 | # hooks WillPaginate::Finder into ActiveRecord::Base and classes that deal | ||
| 30 | # with associations | ||
| 31 | def enable_activerecord | ||
| 32 | return if ActiveRecord::Base.respond_to? :paginate | ||
| 33 | require 'will_paginate/finder' | ||
| 34 | ActiveRecord::Base.send :include, Finder | ||
| 35 | |||
| 36 | # support pagination on associations | ||
| 37 | a = ActiveRecord::Associations | ||
| 38 | returning([ a::AssociationCollection ]) { |classes| | ||
| 39 | # detect http://dev.rubyonrails.org/changeset/9230 | ||
| 40 | unless a::HasManyThroughAssociation.superclass == a::HasManyAssociation | ||
| 41 | classes << a::HasManyThroughAssociation | ||
| 42 | end | ||
| 43 | }.each do |klass| | ||
| 44 | klass.send :include, Finder::ClassMethods | ||
| 45 | klass.class_eval { alias_method_chain :method_missing, :paginate } | ||
| 46 | end | ||
| 47 | end | ||
| 48 | |||
| 49 | # Enable named_scope, a feature of Rails 2.1, even if you have older Rails | ||
| 50 | # (tested on Rails 2.0.2 and 1.2.6). | ||
| 51 | # | ||
| 52 | # You can pass +false+ for +patch+ parameter to skip monkeypatching | ||
| 53 | # *associations*. Use this if you feel that <tt>named_scope</tt> broke | ||
| 54 | # has_many, has_many :through or has_and_belongs_to_many associations in | ||
| 55 | # your app. By passing +false+, you can still use <tt>named_scope</tt> in | ||
| 56 | # your models, but not through associations. | ||
| 57 | def enable_named_scope(patch = true) | ||
| 58 | return if defined? ActiveRecord::NamedScope | ||
| 59 | require 'will_paginate/named_scope' | ||
| 60 | require 'will_paginate/named_scope_patch' if patch | ||
| 61 | |||
| 62 | ActiveRecord::Base.send :include, WillPaginate::NamedScope | ||
| 63 | end | ||
| 64 | end | ||
| 65 | |||
| 66 | module Deprecation # :nodoc: | ||
| 67 | extend ActiveSupport::Deprecation | ||
| 68 | |||
| 69 | def self.warn(message, callstack = caller) | ||
| 70 | message = 'WillPaginate: ' + message.strip.gsub(/\s+/, ' ') | ||
| 71 | ActiveSupport::Deprecation.warn(message, callstack) | ||
| 72 | end | ||
| 73 | end | ||
| 74 | end | ||
| 75 | |||
| 76 | if defined?(Rails) and defined?(ActiveRecord) and defined?(ActionController) | ||
| 77 | WillPaginate.enable | ||
| 78 | end | ||
diff --git a/vendor/plugins/will_paginate/lib/will_paginate/array.rb b/vendor/plugins/will_paginate/lib/will_paginate/array.rb deleted file mode 100644 index d061d2b..0000000 --- a/vendor/plugins/will_paginate/lib/will_paginate/array.rb +++ /dev/null | |||
| @@ -1,16 +0,0 @@ | |||
| 1 | require 'will_paginate/collection' | ||
| 2 | |||
| 3 | # http://www.desimcadam.com/archives/8 | ||
| 4 | Array.class_eval do | ||
| 5 | def paginate(options = {}) | ||
| 6 | raise ArgumentError, "parameter hash expected (got #{options.inspect})" unless Hash === options | ||
| 7 | |||
| 8 | WillPaginate::Collection.create( | ||
| 9 | options[:page] || 1, | ||
| 10 | options[:per_page] || 30, | ||
| 11 | options[:total_entries] || self.length | ||
| 12 | ) { |pager| | ||
| 13 | pager.replace self[pager.offset, pager.per_page].to_a | ||
| 14 | } | ||
| 15 | end | ||
| 16 | end | ||
diff --git a/vendor/plugins/will_paginate/lib/will_paginate/collection.rb b/vendor/plugins/will_paginate/lib/will_paginate/collection.rb deleted file mode 100644 index e253570..0000000 --- a/vendor/plugins/will_paginate/lib/will_paginate/collection.rb +++ /dev/null | |||
| @@ -1,146 +0,0 @@ | |||
| 1 | module WillPaginate | ||
| 2 | # = Invalid page number error | ||
| 3 | # This is an ArgumentError raised in case a page was requested that is either | ||
| 4 | # zero or negative number. You should decide how do deal with such errors in | ||
| 5 | # the controller. | ||
| 6 | # | ||
| 7 | # If you're using Rails 2, then this error will automatically get handled like | ||
| 8 | # 404 Not Found. The hook is in "will_paginate.rb": | ||
| 9 | # | ||
| 10 | # ActionController::Base.rescue_responses['WillPaginate::InvalidPage'] = :not_found | ||
| 11 | # | ||
| 12 | # If you don't like this, use your preffered method of rescuing exceptions in | ||
| 13 | # public from your controllers to handle this differently. The +rescue_from+ | ||
| 14 | # method is a nice addition to Rails 2. | ||
| 15 | # | ||
| 16 | # This error is *not* raised when a page further than the last page is | ||
| 17 | # requested. Use <tt>WillPaginate::Collection#out_of_bounds?</tt> method to | ||
| 18 | # check for those cases and manually deal with them as you see fit. | ||
| 19 | class InvalidPage < ArgumentError | ||
| 20 | def initialize(page, page_num) | ||
| 21 | super "#{page.inspect} given as value, which translates to '#{page_num}' as page number" | ||
| 22 | end | ||
| 23 | end | ||
| 24 | |||
| 25 | # = The key to pagination | ||
| 26 | # Arrays returned from paginating finds are, in fact, instances of this little | ||
| 27 | # class. You may think of WillPaginate::Collection as an ordinary array with | ||
| 28 | # some extra properties. Those properties are used by view helpers to generate | ||
| 29 | # correct page links. | ||
| 30 | # | ||
| 31 | # WillPaginate::Collection also assists in rolling out your own pagination | ||
| 32 | # solutions: see +create+. | ||
| 33 | # | ||
| 34 | # If you are writing a library that provides a collection which you would like | ||
| 35 | # to conform to this API, you don't have to copy these methods over; simply | ||
| 36 | # make your plugin/gem dependant on the "mislav-will_paginate" gem: | ||
| 37 | # | ||
| 38 | # gem 'mislav-will_paginate' | ||
| 39 | # require 'will_paginate/collection' | ||
| 40 | # | ||
| 41 | # # WillPaginate::Collection is now available for use | ||
| 42 | class Collection < Array | ||
| 43 | attr_reader :current_page, :per_page, :total_entries, :total_pages | ||
| 44 | |||
| 45 | # Arguments to the constructor are the current page number, per-page limit | ||
| 46 | # and the total number of entries. The last argument is optional because it | ||
| 47 | # is best to do lazy counting; in other words, count *conditionally* after | ||
| 48 | # populating the collection using the +replace+ method. | ||
| 49 | def initialize(page, per_page, total = nil) | ||
| 50 | @current_page = page.to_i | ||
| 51 | raise InvalidPage.new(page, @current_page) if @current_page < 1 | ||
| 52 | @per_page = per_page.to_i | ||
| 53 | raise ArgumentError, "`per_page` setting cannot be less than 1 (#{@per_page} given)" if @per_page < 1 | ||
| 54 | |||
| 55 | self.total_entries = total if total | ||
| 56 | end | ||
| 57 | |||
| 58 | # Just like +new+, but yields the object after instantiation and returns it | ||
| 59 | # afterwards. This is very useful for manual pagination: | ||
| 60 | # | ||
| 61 | # @entries = WillPaginate::Collection.create(1, 10) do |pager| | ||
| 62 | # result = Post.find(:all, :limit => pager.per_page, :offset => pager.offset) | ||
| 63 | # # inject the result array into the paginated collection: | ||
| 64 | # pager.replace(result) | ||
| 65 | # | ||
| 66 | # unless pager.total_entries | ||
| 67 | # # the pager didn't manage to guess the total count, do it manually | ||
| 68 | # pager.total_entries = Post.count | ||
| 69 | # end | ||
| 70 | # end | ||
| 71 | # | ||
| 72 | # The possibilities with this are endless. For another example, here is how | ||
| 73 | # WillPaginate used to define pagination for Array instances: | ||
| 74 | # | ||
| 75 | # Array.class_eval do | ||
| 76 | # def paginate(page = 1, per_page = 15) | ||
| 77 | # WillPaginate::Collection.create(page, per_page, size) do |pager| | ||
| 78 | # pager.replace self[pager.offset, pager.per_page].to_a | ||
| 79 | # end | ||
| 80 | # end | ||
| 81 | # end | ||
| 82 | # | ||
| 83 | # The Array#paginate API has since then changed, but this still serves as a | ||
| 84 | # fine example of WillPaginate::Collection usage. | ||
| 85 | def self.create(page, per_page, total = nil) | ||
| 86 | pager = new(page, per_page, total) | ||
| 87 | yield pager | ||
| 88 | pager | ||
| 89 | end | ||
| 90 | |||
| 91 | # Helper method that is true when someone tries to fetch a page with a | ||
| 92 | # larger number than the last page. Can be used in combination with flashes | ||
| 93 | # and redirecting. | ||
| 94 | def out_of_bounds? | ||
| 95 | current_page > total_pages | ||
| 96 | end | ||
| 97 | |||
| 98 | # Current offset of the paginated collection. If we're on the first page, | ||
| 99 | # it is always 0. If we're on the 2nd page and there are 30 entries per page, | ||
| 100 | # the offset is 30. This property is useful if you want to render ordinals | ||
| 101 | # side by side with records in the view: simply start with offset + 1. | ||
| 102 | def offset | ||
| 103 | (current_page - 1) * per_page | ||
| 104 | end | ||
| 105 | |||
| 106 | # current_page - 1 or nil if there is no previous page | ||
| 107 | def previous_page | ||
| 108 | current_page > 1 ? (current_page - 1) : nil | ||
| 109 | end | ||
| 110 | |||
| 111 | # current_page + 1 or nil if there is no next page | ||
| 112 | def next_page | ||
| 113 | current_page < total_pages ? (current_page + 1) : nil | ||
| 114 | end | ||
| 115 | |||
| 116 | # sets the <tt>total_entries</tt> property and calculates <tt>total_pages</tt> | ||
| 117 | def total_entries=(number) | ||
| 118 | @total_entries = number.to_i | ||
| 119 | @total_pages = (@total_entries / per_page.to_f).ceil | ||
| 120 | end | ||
| 121 | |||
| 122 | # This is a magic wrapper for the original Array#replace method. It serves | ||
| 123 | # for populating the paginated collection after initialization. | ||
| 124 | # | ||
| 125 | # Why magic? Because it tries to guess the total number of entries judging | ||
| 126 | # by the size of given array. If it is shorter than +per_page+ limit, then we | ||
| 127 | # know we're on the last page. This trick is very useful for avoiding | ||
| 128 | # unnecessary hits to the database to do the counting after we fetched the | ||
| 129 | # data for the current page. | ||
| 130 | # | ||
| 131 | # However, after using +replace+ you should always test the value of | ||
| 132 | # +total_entries+ and set it to a proper value if it's +nil+. See the example | ||
| 133 | # in +create+. | ||
| 134 | def replace(array) | ||
| 135 | result = super | ||
| 136 | |||
| 137 | # The collection is shorter then page limit? Rejoice, because | ||
| 138 | # then we know that we are on the last page! | ||
| 139 | if total_entries.nil? and length < per_page and (current_page == 1 or length > 0) | ||
| 140 | self.total_entries = offset + length | ||
| 141 | end | ||
| 142 | |||
| 143 | result | ||
| 144 | end | ||
| 145 | end | ||
| 146 | end | ||
diff --git a/vendor/plugins/will_paginate/lib/will_paginate/core_ext.rb b/vendor/plugins/will_paginate/lib/will_paginate/core_ext.rb deleted file mode 100644 index 32f10f5..0000000 --- a/vendor/plugins/will_paginate/lib/will_paginate/core_ext.rb +++ /dev/null | |||
| @@ -1,32 +0,0 @@ | |||
| 1 | require 'set' | ||
| 2 | require 'will_paginate/array' | ||
| 3 | |||
| 4 | unless Hash.instance_methods.include? 'except' | ||
| 5 | Hash.class_eval do | ||
| 6 | # Returns a new hash without the given keys. | ||
| 7 | def except(*keys) | ||
| 8 | rejected = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys) | ||
| 9 | reject { |key,| rejected.include?(key) } | ||
| 10 | end | ||
| 11 | |||
| 12 | # Replaces the hash without only the given keys. | ||
| 13 | def except!(*keys) | ||
| 14 | replace(except(*keys)) | ||
| 15 | end | ||
| 16 | end | ||
| 17 | end | ||
| 18 | |||
| 19 | unless Hash.instance_methods.include? 'slice' | ||
| 20 | Hash.class_eval do | ||
| 21 | # Returns a new hash with only the given keys. | ||
| 22 | def slice(*keys) | ||
| 23 | allowed = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys) | ||
| 24 | reject { |key,| !allowed.include?(key) } | ||
| 25 | end | ||
| 26 | |||
| 27 | # Replaces the hash with only the given keys. | ||
| 28 | def slice!(*keys) | ||
| 29 | replace(slice(*keys)) | ||
| 30 | end | ||
| 31 | end | ||
| 32 | end | ||
diff --git a/vendor/plugins/will_paginate/lib/will_paginate/finder.rb b/vendor/plugins/will_paginate/lib/will_paginate/finder.rb deleted file mode 100644 index d0e5668..0000000 --- a/vendor/plugins/will_paginate/lib/will_paginate/finder.rb +++ /dev/null | |||
| @@ -1,264 +0,0 @@ | |||
| 1 | require 'will_paginate/core_ext' | ||
| 2 | |||
| 3 | module WillPaginate | ||
| 4 | # A mixin for ActiveRecord::Base. Provides +per_page+ class method | ||
| 5 | # and hooks things up to provide paginating finders. | ||
| 6 | # | ||
| 7 | # Find out more in WillPaginate::Finder::ClassMethods | ||
| 8 | # | ||
| 9 | module Finder | ||
| 10 | def self.included(base) | ||
| 11 | base.extend ClassMethods | ||
| 12 | class << base | ||
| 13 | alias_method_chain :method_missing, :paginate | ||
| 14 | # alias_method_chain :find_every, :paginate | ||
| 15 | define_method(:per_page) { 30 } unless respond_to?(:per_page) | ||
| 16 | end | ||
| 17 | end | ||
| 18 | |||
| 19 | # = Paginating finders for ActiveRecord models | ||
| 20 | # | ||
| 21 | # WillPaginate adds +paginate+, +per_page+ and other methods to | ||
| 22 | # ActiveRecord::Base class methods and associations. It also hooks into | ||
| 23 | # +method_missing+ to intercept pagination calls to dynamic finders such as | ||
| 24 | # +paginate_by_user_id+ and translate them to ordinary finders | ||
| 25 | # (+find_all_by_user_id+ in this case). | ||
| 26 | # | ||
| 27 | # In short, paginating finders are equivalent to ActiveRecord finders; the | ||
| 28 | # only difference is that we start with "paginate" instead of "find" and | ||
| 29 | # that <tt>:page</tt> is required parameter: | ||
| 30 | # | ||
| 31 | # @posts = Post.paginate :all, :page => params[:page], :order => 'created_at DESC' | ||
| 32 | # | ||
| 33 | # In paginating finders, "all" is implicit. There is no sense in paginating | ||
| 34 | # a single record, right? So, you can drop the <tt>:all</tt> argument: | ||
| 35 | # | ||
| 36 | # Post.paginate(...) => Post.find :all | ||
| 37 | # Post.paginate_all_by_something => Post.find_all_by_something | ||
| 38 | # Post.paginate_by_something => Post.find_all_by_something | ||
| 39 | # | ||
| 40 | # == The importance of the <tt>:order</tt> parameter | ||
| 41 | # | ||
| 42 | # In ActiveRecord finders, <tt>:order</tt> parameter specifies columns for | ||
| 43 | # the <tt>ORDER BY</tt> clause in SQL. It is important to have it, since | ||
| 44 | # pagination only makes sense with ordered sets. Without the <tt>ORDER | ||
| 45 | # BY</tt> clause, databases aren't required to do consistent ordering when | ||
| 46 | # performing <tt>SELECT</tt> queries; this is especially true for | ||
| 47 | # PostgreSQL. | ||
| 48 | # | ||
| 49 | # Therefore, make sure you are doing ordering on a column that makes the | ||
| 50 | # most sense in the current context. Make that obvious to the user, also. | ||
| 51 | # For perfomance reasons you will also want to add an index to that column. | ||
| 52 | module ClassMethods | ||
| 53 | # This is the main paginating finder. | ||
| 54 | # | ||
| 55 | # == Special parameters for paginating finders | ||
| 56 | # * <tt>:page</tt> -- REQUIRED, but defaults to 1 if false or nil | ||
| 57 | # * <tt>:per_page</tt> -- defaults to <tt>CurrentModel.per_page</tt> (which is 30 if not overridden) | ||
| 58 | # * <tt>:total_entries</tt> -- use only if you manually count total entries | ||
| 59 | # * <tt>:count</tt> -- additional options that are passed on to +count+ | ||
| 60 | # * <tt>:finder</tt> -- name of the ActiveRecord finder used (default: "find") | ||
| 61 | # | ||
| 62 | # All other options (+conditions+, +order+, ...) are forwarded to +find+ | ||
| 63 | # and +count+ calls. | ||
| 64 | def paginate(*args) | ||
| 65 | options = args.pop | ||
| 66 | page, per_page, total_entries = wp_parse_options(options) | ||
| 67 | finder = (options[:finder] || 'find').to_s | ||
| 68 | |||
| 69 | if finder == 'find' | ||
| 70 | # an array of IDs may have been given: | ||
| 71 | total_entries ||= (Array === args.first and args.first.size) | ||
| 72 | # :all is implicit | ||
| 73 | args.unshift(:all) if args.empty? | ||
| 74 | end | ||
| 75 | |||
| 76 | WillPaginate::Collection.create(page, per_page, total_entries) do |pager| | ||
| 77 | count_options = options.except :page, :per_page, :total_entries, :finder | ||
| 78 | find_options = count_options.except(:count).update(:offset => pager.offset, :limit => pager.per_page) | ||
| 79 | |||
| 80 | args << find_options | ||
| 81 | # @options_from_last_find = nil | ||
| 82 | pager.replace(send(finder, *args) { |*a| yield(*a) if block_given? }) | ||
| 83 | |||
| 84 | # magic counting for user convenience: | ||
| 85 | pager.total_entries = wp_count(count_options, args, finder) unless pager.total_entries | ||
| 86 | end | ||
| 87 | end | ||
| 88 | |||
| 89 | # Iterates through all records by loading one page at a time. This is useful | ||
| 90 | # for migrations or any other use case where you don't want to load all the | ||
| 91 | # records in memory at once. | ||
| 92 | # | ||
| 93 | # It uses +paginate+ internally; therefore it accepts all of its options. | ||
| 94 | # You can specify a starting page with <tt>:page</tt> (default is 1). Default | ||
| 95 | # <tt>:order</tt> is <tt>"id"</tt>, override if necessary. | ||
| 96 | # | ||
| 97 | # See {Faking Cursors in ActiveRecord}[http://weblog.jamisbuck.org/2007/4/6/faking-cursors-in-activerecord] | ||
| 98 | # where Jamis Buck describes this and a more efficient way for MySQL. | ||
| 99 | def paginated_each(options = {}) | ||
| 100 | options = { :order => 'id', :page => 1 }.merge options | ||
| 101 | options[:page] = options[:page].to_i | ||
| 102 | options[:total_entries] = 0 # skip the individual count queries | ||
| 103 | total = 0 | ||
| 104 | |||
| 105 | begin | ||
| 106 | collection = paginate(options) | ||
| 107 | with_exclusive_scope(:find => {}) do | ||
| 108 | # using exclusive scope so that the block is yielded in scope-free context | ||
| 109 | total += collection.each { |item| yield item }.size | ||
| 110 | end | ||
| 111 | options[:page] += 1 | ||
| 112 | end until collection.size < collection.per_page | ||
| 113 | |||
| 114 | total | ||
| 115 | end | ||
| 116 | |||
| 117 | # Wraps +find_by_sql+ by simply adding LIMIT and OFFSET to your SQL string | ||
| 118 | # based on the params otherwise used by paginating finds: +page+ and | ||
| 119 | # +per_page+. | ||
| 120 | # | ||
| 121 | # Example: | ||
| 122 | # | ||
| 123 | # @developers = Developer.paginate_by_sql ['select * from developers where salary > ?', 80000], | ||
| 124 | # :page => params[:page], :per_page => 3 | ||
| 125 | # | ||
| 126 | # A query for counting rows will automatically be generated if you don't | ||
| 127 | # supply <tt>:total_entries</tt>. If you experience problems with this | ||
| 128 | # generated SQL, you might want to perform the count manually in your | ||
| 129 | # application. | ||
| 130 | # | ||
| 131 | def paginate_by_sql(sql, options) | ||
| 132 | WillPaginate::Collection.create(*wp_parse_options(options)) do |pager| | ||
| 133 | query = sanitize_sql(sql.dup) | ||
| 134 | original_query = query.dup | ||
| 135 | # add limit, offset | ||
| 136 | add_limit! query, :offset => pager.offset, :limit => pager.per_page | ||
| 137 | # perfom the find | ||
| 138 | pager.replace find_by_sql(query) | ||
| 139 | |||
| 140 | unless pager.total_entries | ||
| 141 | count_query = original_query.sub /\bORDER\s+BY\s+[\w`,\s]+$/mi, '' | ||
| 142 | count_query = "SELECT COUNT(*) FROM (#{count_query})" | ||
| 143 | |||
| 144 | unless ['oracle', 'oci'].include?(self.connection.adapter_name.downcase) | ||
| 145 | count_query << ' AS count_table' | ||
| 146 | end | ||
| 147 | # perform the count query | ||
| 148 | pager.total_entries = count_by_sql(count_query) | ||
| 149 | end | ||
| 150 | end | ||
| 151 | end | ||
| 152 | |||
| 153 | def respond_to?(method, include_priv = false) #:nodoc: | ||
| 154 | case method.to_sym | ||
| 155 | when :paginate, :paginate_by_sql | ||
| 156 | true | ||
| 157 | else | ||
| 158 | super(method.to_s.sub(/^paginate/, 'find'), include_priv) | ||
| 159 | end | ||
| 160 | end | ||
| 161 | |||
| 162 | protected | ||
| 163 | |||
| 164 | def method_missing_with_paginate(method, *args) #:nodoc: | ||
| 165 | # did somebody tried to paginate? if not, let them be | ||
| 166 | unless method.to_s.index('paginate') == 0 | ||
| 167 | if block_given? | ||
| 168 | return method_missing_without_paginate(method, *args) { |*a| yield(*a) } | ||
| 169 | else | ||
| 170 | return method_missing_without_paginate(method, *args) | ||
| 171 | end | ||
| 172 | end | ||
| 173 | |||
| 174 | # paginate finders are really just find_* with limit and offset | ||
| 175 | finder = method.to_s.sub('paginate', 'find') | ||
| 176 | finder.sub!('find', 'find_all') if finder.index('find_by_') == 0 | ||
| 177 | |||
| 178 | options = args.pop | ||
| 179 | raise ArgumentError, 'parameter hash expected' unless options.respond_to? :symbolize_keys | ||
| 180 | options = options.dup | ||
| 181 | options[:finder] = finder | ||
| 182 | args << options | ||
| 183 | |||
| 184 | paginate(*args) { |*a| yield(*a) if block_given? } | ||
| 185 | end | ||
| 186 | |||
| 187 | # Does the not-so-trivial job of finding out the total number of entries | ||
| 188 | # in the database. It relies on the ActiveRecord +count+ method. | ||
| 189 | def wp_count(options, args, finder) | ||
| 190 | excludees = [:count, :order, :limit, :offset, :readonly] | ||
| 191 | excludees << :from unless ActiveRecord::Calculations::CALCULATIONS_OPTIONS.include?(:from) | ||
| 192 | |||
| 193 | # we may be in a model or an association proxy | ||
| 194 | klass = (@owner and @reflection) ? @reflection.klass : self | ||
| 195 | |||
| 196 | # Use :select from scope if it isn't already present. | ||
| 197 | options[:select] = scope(:find, :select) unless options[:select] | ||
| 198 | |||
| 199 | if options[:select] and options[:select] =~ /^\s*DISTINCT\b/i | ||
| 200 | # Remove quoting and check for table_name.*-like statement. | ||
| 201 | if options[:select].gsub('`', '') =~ /\w+\.\*/ | ||
| 202 | options[:select] = "DISTINCT #{klass.table_name}.#{klass.primary_key}" | ||
| 203 | end | ||
| 204 | else | ||
| 205 | excludees << :select # only exclude the select param if it doesn't begin with DISTINCT | ||
| 206 | end | ||
| 207 | |||
| 208 | # count expects (almost) the same options as find | ||
| 209 | count_options = options.except *excludees | ||
| 210 | |||
| 211 | # merge the hash found in :count | ||
| 212 | # this allows you to specify :select, :order, or anything else just for the count query | ||
| 213 | count_options.update options[:count] if options[:count] | ||
| 214 | |||
| 215 | # forget about includes if they are irrelevant (Rails 2.1) | ||
| 216 | if count_options[:include] and | ||
| 217 | klass.private_methods.include?('references_eager_loaded_tables?') and | ||
| 218 | !klass.send(:references_eager_loaded_tables?, count_options) | ||
| 219 | count_options.delete :include | ||
| 220 | end | ||
| 221 | |||
| 222 | # we may have to scope ... | ||
| 223 | counter = Proc.new { count(count_options) } | ||
| 224 | |||
| 225 | count = if finder.index('find_') == 0 and klass.respond_to?(scoper = finder.sub('find', 'with')) | ||
| 226 | # scope_out adds a 'with_finder' method which acts like with_scope, if it's present | ||
| 227 | # then execute the count with the scoping provided by the with_finder | ||
| 228 | send(scoper, &counter) | ||
| 229 | elsif finder =~ /^find_(all_by|by)_([_a-zA-Z]\w*)$/ | ||
| 230 | # extract conditions from calls like "paginate_by_foo_and_bar" | ||
| 231 | attribute_names = $2.split('_and_') | ||
| 232 | conditions = construct_attributes_from_arguments(attribute_names, args) | ||
| 233 | with_scope(:find => { :conditions => conditions }, &counter) | ||
| 234 | else | ||
| 235 | counter.call | ||
| 236 | end | ||
| 237 | |||
| 238 | count.respond_to?(:length) ? count.length : count | ||
| 239 | end | ||
| 240 | |||
| 241 | def wp_parse_options(options) #:nodoc: | ||
| 242 | raise ArgumentError, 'parameter hash expected' unless options.respond_to? :symbolize_keys | ||
| 243 | options = options.symbolize_keys | ||
| 244 | raise ArgumentError, ':page parameter required' unless options.key? :page | ||
| 245 | |||
| 246 | if options[:count] and options[:total_entries] | ||
| 247 | raise ArgumentError, ':count and :total_entries are mutually exclusive' | ||
| 248 | end | ||
| 249 | |||
| 250 | page = options[:page] || 1 | ||
| 251 | per_page = options[:per_page] || self.per_page | ||
| 252 | total = options[:total_entries] | ||
| 253 | [page, per_page, total] | ||
| 254 | end | ||
| 255 | |||
| 256 | private | ||
| 257 | |||
| 258 | # def find_every_with_paginate(options) | ||
| 259 | # @options_from_last_find = options | ||
| 260 | # find_every_without_paginate(options) | ||
| 261 | # end | ||
| 262 | end | ||
| 263 | end | ||
| 264 | end | ||
diff --git a/vendor/plugins/will_paginate/lib/will_paginate/named_scope.rb b/vendor/plugins/will_paginate/lib/will_paginate/named_scope.rb deleted file mode 100644 index 5a743d7..0000000 --- a/vendor/plugins/will_paginate/lib/will_paginate/named_scope.rb +++ /dev/null | |||
| @@ -1,170 +0,0 @@ | |||
| 1 | module WillPaginate | ||
| 2 | # This is a feature backported from Rails 2.1 because of its usefullness not only with will_paginate, | ||
| 3 | # but in other aspects when managing complex conditions that you want to be reusable. | ||
| 4 | module NamedScope | ||
| 5 | # All subclasses of ActiveRecord::Base have two named_scopes: | ||
| 6 | # * <tt>all</tt>, which is similar to a <tt>find(:all)</tt> query, and | ||
| 7 | # * <tt>scoped</tt>, which allows for the creation of anonymous scopes, on the fly: <tt>Shirt.scoped(:conditions => {:color => 'red'}).scoped(:include => :washing_instructions)</tt> | ||
| 8 | # | ||
| 9 | # These anonymous scopes tend to be useful when procedurally generating complex queries, where passing | ||
| 10 | # intermediate values (scopes) around as first-class objects is convenient. | ||
| 11 | def self.included(base) | ||
| 12 | base.class_eval do | ||
| 13 | extend ClassMethods | ||
| 14 | named_scope :scoped, lambda { |scope| scope } | ||
| 15 | end | ||
| 16 | end | ||
| 17 | |||
| 18 | module ClassMethods | ||
| 19 | def scopes | ||
| 20 | read_inheritable_attribute(:scopes) || write_inheritable_attribute(:scopes, {}) | ||
| 21 | end | ||
| 22 | |||
| 23 | # Adds a class method for retrieving and querying objects. A scope represents a narrowing of a database query, | ||
| 24 | # such as <tt>:conditions => {:color => :red}, :select => 'shirts.*', :include => :washing_instructions</tt>. | ||
| 25 | # | ||
| 26 | # class Shirt < ActiveRecord::Base | ||
| 27 | # named_scope :red, :conditions => {:color => 'red'} | ||
| 28 | # named_scope :dry_clean_only, :joins => :washing_instructions, :conditions => ['washing_instructions.dry_clean_only = ?', true] | ||
| 29 | # end | ||
| 30 | # | ||
| 31 | # The above calls to <tt>named_scope</tt> define class methods <tt>Shirt.red</tt> and <tt>Shirt.dry_clean_only</tt>. <tt>Shirt.red</tt>, | ||
| 32 | # in effect, represents the query <tt>Shirt.find(:all, :conditions => {:color => 'red'})</tt>. | ||
| 33 | # | ||
| 34 | # Unlike Shirt.find(...), however, the object returned by <tt>Shirt.red</tt> is not an Array; it resembles the association object | ||
| 35 | # constructed by a <tt>has_many</tt> declaration. For instance, you can invoke <tt>Shirt.red.find(:first)</tt>, <tt>Shirt.red.count</tt>, | ||
| 36 | # <tt>Shirt.red.find(:all, :conditions => {:size => 'small'})</tt>. Also, just | ||
| 37 | # as with the association objects, name scopes acts like an Array, implementing Enumerable; <tt>Shirt.red.each(&block)</tt>, | ||
| 38 | # <tt>Shirt.red.first</tt>, and <tt>Shirt.red.inject(memo, &block)</tt> all behave as if Shirt.red really were an Array. | ||
| 39 | # | ||
| 40 | # These named scopes are composable. For instance, <tt>Shirt.red.dry_clean_only</tt> will produce all shirts that are both red and dry clean only. | ||
| 41 | # Nested finds and calculations also work with these compositions: <tt>Shirt.red.dry_clean_only.count</tt> returns the number of garments | ||
| 42 | # for which these criteria obtain. Similarly with <tt>Shirt.red.dry_clean_only.average(:thread_count)</tt>. | ||
| 43 | # | ||
| 44 | # All scopes are available as class methods on the ActiveRecord::Base descendent upon which the scopes were defined. But they are also available to | ||
| 45 | # <tt>has_many</tt> associations. If, | ||
| 46 | # | ||
| 47 | # class Person < ActiveRecord::Base | ||
| 48 | # has_many :shirts | ||
| 49 | # end | ||
| 50 | # | ||
| 51 | # then <tt>elton.shirts.red.dry_clean_only</tt> will return all of Elton's red, dry clean | ||
| 52 | # only shirts. | ||
| 53 | # | ||
| 54 | # Named scopes can also be procedural. | ||
| 55 | # | ||
| 56 | # class Shirt < ActiveRecord::Base | ||
| 57 | # named_scope :colored, lambda { |color| | ||
| 58 | # { :conditions => { :color => color } } | ||
| 59 | # } | ||
| 60 | # end | ||
| 61 | # | ||
| 62 | # In this example, <tt>Shirt.colored('puce')</tt> finds all puce shirts. | ||
| 63 | # | ||
| 64 | # Named scopes can also have extensions, just as with <tt>has_many</tt> declarations: | ||
| 65 | # | ||
| 66 | # class Shirt < ActiveRecord::Base | ||
| 67 | # named_scope :red, :conditions => {:color => 'red'} do | ||
| 68 | # def dom_id | ||
| 69 | # 'red_shirts' | ||
| 70 | # end | ||
| 71 | # end | ||
| 72 | # end | ||
| 73 | # | ||
| 74 | # | ||
| 75 | # For testing complex named scopes, you can examine the scoping options using the | ||
| 76 | # <tt>proxy_options</tt> method on the proxy itself. | ||
| 77 | # | ||
| 78 | # class Shirt < ActiveRecord::Base | ||
| 79 | # named_scope :colored, lambda { |color| | ||
| 80 | # { :conditions => { :color => color } } | ||
| 81 | # } | ||
| 82 | # end | ||
| 83 | # | ||
| 84 | # expected_options = { :conditions => { :colored => 'red' } } | ||
| 85 | # assert_equal expected_options, Shirt.colored('red').proxy_options | ||
| 86 | def named_scope(name, options = {}) | ||
| 87 | name = name.to_sym | ||
| 88 | scopes[name] = lambda do |parent_scope, *args| | ||
| 89 | Scope.new(parent_scope, case options | ||
| 90 | when Hash | ||
| 91 | options | ||
| 92 | when Proc | ||
| 93 | options.call(*args) | ||
| 94 | end) { |*a| yield(*a) if block_given? } | ||
| 95 | end | ||
| 96 | (class << self; self end).instance_eval do | ||
| 97 | define_method name do |*args| | ||
| 98 | scopes[name].call(self, *args) | ||
| 99 | end | ||
| 100 | end | ||
| 101 | end | ||
| 102 | end | ||
| 103 | |||
| 104 | class Scope | ||
| 105 | attr_reader :proxy_scope, :proxy_options | ||
| 106 | |||
| 107 | [].methods.each do |m| | ||
| 108 | unless m =~ /(^__|^nil\?|^send|^object_id$|class|extend|^find$|count|sum|average|maximum|minimum|paginate|first|last|empty\?|respond_to\?)/ | ||
| 109 | delegate m, :to => :proxy_found | ||
| 110 | end | ||
| 111 | end | ||
| 112 | |||
| 113 | delegate :scopes, :with_scope, :to => :proxy_scope | ||
| 114 | |||
| 115 | def initialize(proxy_scope, options) | ||
| 116 | [options[:extend]].flatten.each { |extension| extend extension } if options[:extend] | ||
| 117 | extend Module.new { |*args| yield(*args) } if block_given? | ||
| 118 | @proxy_scope, @proxy_options = proxy_scope, options.except(:extend) | ||
| 119 | end | ||
| 120 | |||
| 121 | def reload | ||
| 122 | load_found; self | ||
| 123 | end | ||
| 124 | |||
| 125 | def first(*args) | ||
| 126 | if args.first.kind_of?(Integer) || (@found && !args.first.kind_of?(Hash)) | ||
| 127 | proxy_found.first(*args) | ||
| 128 | else | ||
| 129 | find(:first, *args) | ||
| 130 | end | ||
| 131 | end | ||
| 132 | |||
| 133 | def last(*args) | ||
| 134 | if args.first.kind_of?(Integer) || (@found && !args.first.kind_of?(Hash)) | ||
| 135 | proxy_found.last(*args) | ||
| 136 | else | ||
| 137 | find(:last, *args) | ||
| 138 | end | ||
| 139 | end | ||
| 140 | |||
| 141 | def empty? | ||
| 142 | @found ? @found.empty? : count.zero? | ||
| 143 | end | ||
| 144 | |||
| 145 | def respond_to?(method, include_private = false) | ||
| 146 | super || @proxy_scope.respond_to?(method, include_private) | ||
| 147 | end | ||
| 148 | |||
| 149 | protected | ||
| 150 | def proxy_found | ||
| 151 | @found || load_found | ||
| 152 | end | ||
| 153 | |||
| 154 | private | ||
| 155 | def method_missing(method, *args) | ||
| 156 | if scopes.include?(method) | ||
| 157 | scopes[method].call(self, *args) | ||
| 158 | else | ||
| 159 | with_scope :find => proxy_options do | ||
| 160 | proxy_scope.send(method, *args) { |*a| yield(*a) if block_given? } | ||
| 161 | end | ||
| 162 | end | ||
| 163 | end | ||
| 164 | |||
| 165 | def load_found | ||
| 166 | @found = find(:all) | ||
| 167 | end | ||
| 168 | end | ||
| 169 | end | ||
| 170 | end | ||
diff --git a/vendor/plugins/will_paginate/lib/will_paginate/named_scope_patch.rb b/vendor/plugins/will_paginate/lib/will_paginate/named_scope_patch.rb deleted file mode 100644 index 7daff59..0000000 --- a/vendor/plugins/will_paginate/lib/will_paginate/named_scope_patch.rb +++ /dev/null | |||
| @@ -1,37 +0,0 @@ | |||
| 1 | ActiveRecord::Associations::AssociationProxy.class_eval do | ||
| 2 | protected | ||
| 3 | def with_scope(*args) | ||
| 4 | @reflection.klass.send(:with_scope, *args) { |*a| yield(*a) if block_given? } | ||
| 5 | end | ||
| 6 | end | ||
| 7 | |||
| 8 | [ ActiveRecord::Associations::AssociationCollection, | ||
| 9 | ActiveRecord::Associations::HasManyThroughAssociation ].each do |klass| | ||
| 10 | klass.class_eval do | ||
| 11 | protected | ||
| 12 | alias :method_missing_without_scopes :method_missing_without_paginate | ||
| 13 | def method_missing_without_paginate(method, *args) | ||
| 14 | if @reflection.klass.scopes.include?(method) | ||
| 15 | @reflection.klass.scopes[method].call(self, *args) { |*a| yield(*a) if block_given? } | ||
| 16 | else | ||
| 17 | method_missing_without_scopes(method, *args) { |*a| yield(*a) if block_given? } | ||
| 18 | end | ||
| 19 | end | ||
| 20 | end | ||
| 21 | end | ||
| 22 | |||
| 23 | # Rails 1.2.6 | ||
| 24 | ActiveRecord::Associations::HasAndBelongsToManyAssociation.class_eval do | ||
| 25 | protected | ||
| 26 | def method_missing(method, *args) | ||
| 27 | if @target.respond_to?(method) || (!@reflection.klass.respond_to?(method) && Class.respond_to?(method)) | ||
| 28 | super | ||
| 29 | elsif @reflection.klass.scopes.include?(method) | ||
| 30 | @reflection.klass.scopes[method].call(self, *args) | ||
| 31 | else | ||
| 32 | @reflection.klass.with_scope(:find => { :conditions => @finder_sql, :joins => @join_sql, :readonly => false }) do | ||
| 33 | @reflection.klass.send(method, *args) { |*a| yield(*a) if block_given? } | ||
| 34 | end | ||
| 35 | end | ||
| 36 | end | ||
| 37 | end if ActiveRecord::Base.respond_to? :find_first | ||
diff --git a/vendor/plugins/will_paginate/lib/will_paginate/version.rb b/vendor/plugins/will_paginate/lib/will_paginate/version.rb deleted file mode 100644 index 99f3238..0000000 --- a/vendor/plugins/will_paginate/lib/will_paginate/version.rb +++ /dev/null | |||
| @@ -1,9 +0,0 @@ | |||
| 1 | module WillPaginate | ||
| 2 | module VERSION | ||
| 3 | MAJOR = 2 | ||
| 4 | MINOR = 3 | ||
| 5 | TINY = 5 | ||
| 6 | |||
| 7 | STRING = [MAJOR, MINOR, TINY].join('.') | ||
| 8 | end | ||
| 9 | end | ||
diff --git a/vendor/plugins/will_paginate/lib/will_paginate/view_helpers.rb b/vendor/plugins/will_paginate/lib/will_paginate/view_helpers.rb deleted file mode 100644 index 5f7ae42..0000000 --- a/vendor/plugins/will_paginate/lib/will_paginate/view_helpers.rb +++ /dev/null | |||
| @@ -1,389 +0,0 @@ | |||
| 1 | require 'will_paginate/core_ext' | ||
| 2 | |||
| 3 | module WillPaginate | ||
| 4 | # = Will Paginate view helpers | ||
| 5 | # | ||
| 6 | # The main view helper, #will_paginate, renders | ||
| 7 | # pagination links for the given collection. The helper itself is lightweight | ||
| 8 | # and serves only as a wrapper around LinkRenderer instantiation; the | ||
| 9 | # renderer then does all the hard work of generating the HTML. | ||
| 10 | # | ||
| 11 | # == Global options for helpers | ||
| 12 | # | ||
| 13 | # Options for pagination helpers are optional and get their default values from the | ||
| 14 | # <tt>WillPaginate::ViewHelpers.pagination_options</tt> hash. You can write to this hash to | ||
| 15 | # override default options on the global level: | ||
| 16 | # | ||
| 17 | # WillPaginate::ViewHelpers.pagination_options[:previous_label] = 'Previous page' | ||
| 18 | # | ||
| 19 | # By putting this into "config/initializers/will_paginate.rb" (or simply environment.rb in | ||
| 20 | # older versions of Rails) you can easily translate link texts to previous | ||
| 21 | # and next pages, as well as override some other defaults to your liking. | ||
| 22 | module ViewHelpers | ||
| 23 | # default options that can be overridden on the global level | ||
| 24 | @@pagination_options = { | ||
| 25 | :class => 'pagination', | ||
| 26 | :previous_label => '« Previous', | ||
| 27 | :next_label => 'Next »', | ||
| 28 | :inner_window => 4, # links around the current page | ||
| 29 | :outer_window => 1, # links around beginning and end | ||
| 30 | :separator => ' ', # single space is friendly to spiders and non-graphic browsers | ||
| 31 | :param_name => :page, | ||
| 32 | :params => nil, | ||
| 33 | :renderer => 'WillPaginate::LinkRenderer', | ||
| 34 | :page_links => true, | ||
| 35 | :container => true | ||
| 36 | } | ||
| 37 | mattr_reader :pagination_options | ||
| 38 | |||
| 39 | # Renders Digg/Flickr-style pagination for a WillPaginate::Collection | ||
| 40 | # object. Nil is returned if there is only one page in total; no point in | ||
| 41 | # rendering the pagination in that case... | ||
| 42 | # | ||
| 43 | # ==== Options | ||
| 44 | # Display options: | ||
| 45 | # * <tt>:previous_label</tt> -- default: "« Previous" (this parameter is called <tt>:prev_label</tt> in versions <b>2.3.2</b> and older!) | ||
| 46 | # * <tt>:next_label</tt> -- default: "Next »" | ||
| 47 | # * <tt>:page_links</tt> -- when false, only previous/next links are rendered (default: true) | ||
| 48 | # * <tt>:inner_window</tt> -- how many links are shown around the current page (default: 4) | ||
| 49 | # * <tt>:outer_window</tt> -- how many links are around the first and the last page (default: 1) | ||
| 50 | # * <tt>:separator</tt> -- string separator for page HTML elements (default: single space) | ||
| 51 | # | ||
| 52 | # HTML options: | ||
| 53 | # * <tt>:class</tt> -- CSS class name for the generated DIV (default: "pagination") | ||
| 54 | # * <tt>:container</tt> -- toggles rendering of the DIV container for pagination links, set to | ||
| 55 | # false only when you are rendering your own pagination markup (default: true) | ||
| 56 | # * <tt>:id</tt> -- HTML ID for the container (default: nil). Pass +true+ to have the ID | ||
| 57 | # automatically generated from the class name of objects in collection: for example, paginating | ||
| 58 | # ArticleComment models would yield an ID of "article_comments_pagination". | ||
| 59 | # | ||
| 60 | # Advanced options: | ||
| 61 | # * <tt>:param_name</tt> -- parameter name for page number in URLs (default: <tt>:page</tt>) | ||
| 62 | # * <tt>:params</tt> -- additional parameters when generating pagination links | ||
| 63 | # (eg. <tt>:controller => "foo", :action => nil</tt>) | ||
| 64 | # * <tt>:renderer</tt> -- class name, class or instance of a link renderer (default: | ||
| 65 | # <tt>WillPaginate::LinkRenderer</tt>) | ||
| 66 | # | ||
| 67 | # All options not recognized by will_paginate will become HTML attributes on the container | ||
| 68 | # element for pagination links (the DIV). For example: | ||
| 69 | # | ||
| 70 | # <%= will_paginate @posts, :style => 'font-size: small' %> | ||
| 71 | # | ||
| 72 | # ... will result in: | ||
| 73 | # | ||
| 74 | # <div class="pagination" style="font-size: small"> ... </div> | ||
| 75 | # | ||
| 76 | # ==== Using the helper without arguments | ||
| 77 | # If the helper is called without passing in the collection object, it will | ||
| 78 | # try to read from the instance variable inferred by the controller name. | ||
| 79 | # For example, calling +will_paginate+ while the current controller is | ||
| 80 | # PostsController will result in trying to read from the <tt>@posts</tt> | ||
| 81 | # variable. Example: | ||
| 82 | # | ||
| 83 | # <%= will_paginate :id => true %> | ||
| 84 | # | ||
| 85 | # ... will result in <tt>@post</tt> collection getting paginated: | ||
| 86 | # | ||
| 87 | # <div class="pagination" id="posts_pagination"> ... </div> | ||
| 88 | # | ||
| 89 | def will_paginate(collection = nil, options = {}) | ||
| 90 | options, collection = collection, nil if collection.is_a? Hash | ||
| 91 | unless collection or !controller | ||
| 92 | collection_name = "@#{controller.controller_name}" | ||
| 93 | collection = instance_variable_get(collection_name) | ||
| 94 | raise ArgumentError, "The #{collection_name} variable appears to be empty. Did you " + | ||
| 95 | "forget to pass the collection object for will_paginate?" unless collection | ||
| 96 | end | ||
| 97 | # early exit if there is nothing to render | ||
| 98 | return nil unless WillPaginate::ViewHelpers.total_pages_for_collection(collection) > 1 | ||
| 99 | |||
| 100 | options = options.symbolize_keys.reverse_merge WillPaginate::ViewHelpers.pagination_options | ||
| 101 | if options[:prev_label] | ||
| 102 | WillPaginate::Deprecation::warn(":prev_label view parameter is now :previous_label; the old name has been deprecated", caller) | ||
| 103 | options[:previous_label] = options.delete(:prev_label) | ||
| 104 | end | ||
| 105 | |||
| 106 | # get the renderer instance | ||
| 107 | renderer = case options[:renderer] | ||
| 108 | when String | ||
| 109 | options[:renderer].to_s.constantize.new | ||
| 110 | when Class | ||
| 111 | options[:renderer].new | ||
| 112 | else | ||
| 113 | options[:renderer] | ||
| 114 | end | ||
| 115 | # render HTML for pagination | ||
| 116 | renderer.prepare collection, options, self | ||
| 117 | renderer.to_html | ||
| 118 | end | ||
| 119 | |||
| 120 | # Wrapper for rendering pagination links at both top and bottom of a block | ||
| 121 | # of content. | ||
| 122 | # | ||
| 123 | # <% paginated_section @posts do %> | ||
| 124 | # <ol id="posts"> | ||
| 125 | # <% for post in @posts %> | ||
| 126 | # <li> ... </li> | ||
| 127 | # <% end %> | ||
| 128 | # </ol> | ||
| 129 | # <% end %> | ||
| 130 | # | ||
| 131 | # will result in: | ||
| 132 | # | ||
| 133 | # <div class="pagination"> ... </div> | ||
| 134 | # <ol id="posts"> | ||
| 135 | # ... | ||
| 136 | # </ol> | ||
| 137 | # <div class="pagination"> ... </div> | ||
| 138 | # | ||
| 139 | # Arguments are passed to a <tt>will_paginate</tt> call, so the same options | ||
| 140 | # apply. Don't use the <tt>:id</tt> option; otherwise you'll finish with two | ||
| 141 | # blocks of pagination links sharing the same ID (which is invalid HTML). | ||
| 142 | def paginated_section(*args, &block) | ||
| 143 | pagination = will_paginate(*args).to_s | ||
| 144 | |||
| 145 | unless ActionView::Base.respond_to? :erb_variable | ||
| 146 | concat pagination | ||
| 147 | yield | ||
| 148 | concat pagination | ||
| 149 | else | ||
| 150 | content = pagination + capture(&block) + pagination | ||
| 151 | concat(content, block.binding) | ||
| 152 | end | ||
| 153 | end | ||
| 154 | |||
| 155 | # Renders a helpful message with numbers of displayed vs. total entries. | ||
| 156 | # You can use this as a blueprint for your own, similar helpers. | ||
| 157 | # | ||
| 158 | # <%= page_entries_info @posts %> | ||
| 159 | # #-> Displaying posts 6 - 10 of 26 in total | ||
| 160 | # | ||
| 161 | # By default, the message will use the humanized class name of objects | ||
| 162 | # in collection: for instance, "project types" for ProjectType models. | ||
| 163 | # Override this with the <tt>:entry_name</tt> parameter: | ||
| 164 | # | ||
| 165 | # <%= page_entries_info @posts, :entry_name => 'item' %> | ||
| 166 | # #-> Displaying items 6 - 10 of 26 in total | ||
| 167 | def page_entries_info(collection, options = {}) | ||
| 168 | entry_name = options[:entry_name] || | ||
| 169 | (collection.empty?? 'entry' : collection.first.class.name.underscore.sub('_', ' ')) | ||
| 170 | |||
| 171 | if collection.total_pages < 2 | ||
| 172 | case collection.size | ||
| 173 | when 0; "No #{entry_name.pluralize} found" | ||
| 174 | when 1; "Displaying <b>1</b> #{entry_name}" | ||
| 175 | else; "Displaying <b>all #{collection.size}</b> #{entry_name.pluralize}" | ||
| 176 | end | ||
| 177 | else | ||
| 178 | %{Displaying #{entry_name.pluralize} <b>%d - %d</b> of <b>%d</b> in total} % [ | ||
| 179 | collection.offset + 1, | ||
| 180 | collection.offset + collection.length, | ||
| 181 | collection.total_entries | ||
| 182 | ] | ||
| 183 | end | ||
| 184 | end | ||
| 185 | |||
| 186 | def self.total_pages_for_collection(collection) #:nodoc: | ||
| 187 | if collection.respond_to?('page_count') and !collection.respond_to?('total_pages') | ||
| 188 | WillPaginate::Deprecation.warn %{ | ||
| 189 | You are using a paginated collection of class #{collection.class.name} | ||
| 190 | which conforms to the old API of WillPaginate::Collection by using | ||
| 191 | `page_count`, while the current method name is `total_pages`. Please | ||
| 192 | upgrade yours or 3rd-party code that provides the paginated collection}, caller | ||
| 193 | class << collection | ||
| 194 | def total_pages; page_count; end | ||
| 195 | end | ||
| 196 | end | ||
| 197 | collection.total_pages | ||
| 198 | end | ||
| 199 | end | ||
| 200 | |||
| 201 | # This class does the heavy lifting of actually building the pagination | ||
| 202 | # links. It is used by the <tt>will_paginate</tt> helper internally. | ||
| 203 | class LinkRenderer | ||
| 204 | |||
| 205 | # The gap in page links is represented by: | ||
| 206 | # | ||
| 207 | # <span class="gap">…</span> | ||
| 208 | attr_accessor :gap_marker | ||
| 209 | |||
| 210 | def initialize | ||
| 211 | @gap_marker = '<span class="gap">…</span>' | ||
| 212 | end | ||
| 213 | |||
| 214 | # * +collection+ is a WillPaginate::Collection instance or any other object | ||
| 215 | # that conforms to that API | ||
| 216 | # * +options+ are forwarded from +will_paginate+ view helper | ||
| 217 | # * +template+ is the reference to the template being rendered | ||
| 218 | def prepare(collection, options, template) | ||
| 219 | @collection = collection | ||
| 220 | @options = options | ||
| 221 | @template = template | ||
| 222 | |||
| 223 | # reset values in case we're re-using this instance | ||
| 224 | @total_pages = @param_name = @url_string = nil | ||
| 225 | end | ||
| 226 | |||
| 227 | # Process it! This method returns the complete HTML string which contains | ||
| 228 | # pagination links. Feel free to subclass LinkRenderer and change this | ||
| 229 | # method as you see fit. | ||
| 230 | def to_html | ||
| 231 | links = @options[:page_links] ? windowed_links : [] | ||
| 232 | # previous/next buttons | ||
| 233 | links.unshift page_link_or_span(@collection.previous_page, 'disabled prev_page', @options[:previous_label]) | ||
| 234 | links.push page_link_or_span(@collection.next_page, 'disabled next_page', @options[:next_label]) | ||
| 235 | |||
| 236 | html = links.join(@options[:separator]) | ||
| 237 | @options[:container] ? @template.content_tag(:div, html, html_attributes) : html | ||
| 238 | end | ||
| 239 | |||
| 240 | # Returns the subset of +options+ this instance was initialized with that | ||
| 241 | # represent HTML attributes for the container element of pagination links. | ||
| 242 | def html_attributes | ||
| 243 | return @html_attributes if @html_attributes | ||
| 244 | @html_attributes = @options.except *(WillPaginate::ViewHelpers.pagination_options.keys - [:class]) | ||
| 245 | # pagination of Post models will have the ID of "posts_pagination" | ||
| 246 | if @options[:container] and @options[:id] === true | ||
| 247 | @html_attributes[:id] = @collection.first.class.name.underscore.pluralize + '_pagination' | ||
| 248 | end | ||
| 249 | @html_attributes | ||
| 250 | end | ||
| 251 | |||
| 252 | protected | ||
| 253 | |||
| 254 | # Collects link items for visible page numbers. | ||
| 255 | def windowed_links | ||
| 256 | prev = nil | ||
| 257 | |||
| 258 | visible_page_numbers.inject [] do |links, n| | ||
| 259 | # detect gaps: | ||
| 260 | links << gap_marker if prev and n > prev + 1 | ||
| 261 | links << page_link_or_span(n, 'current') | ||
| 262 | prev = n | ||
| 263 | links | ||
| 264 | end | ||
| 265 | end | ||
| 266 | |||
| 267 | # Calculates visible page numbers using the <tt>:inner_window</tt> and | ||
| 268 | # <tt>:outer_window</tt> options. | ||
| 269 | def visible_page_numbers | ||
| 270 | inner_window, outer_window = @options[:inner_window].to_i, @options[:outer_window].to_i | ||
| 271 | window_from = current_page - inner_window | ||
| 272 | window_to = current_page + inner_window | ||
| 273 | |||
| 274 | # adjust lower or upper limit if other is out of bounds | ||
| 275 | if window_to > total_pages | ||
| 276 | window_from -= window_to - total_pages | ||
| 277 | window_to = total_pages | ||
| 278 | end | ||
| 279 | if window_from < 1 | ||
| 280 | window_to += 1 - window_from | ||
| 281 | window_from = 1 | ||
| 282 | window_to = total_pages if window_to > total_pages | ||
| 283 | end | ||
| 284 | |||
| 285 | visible = (1..total_pages).to_a | ||
| 286 | left_gap = (2 + outer_window)...window_from | ||
| 287 | right_gap = (window_to + 1)...(total_pages - outer_window) | ||
| 288 | visible -= left_gap.to_a if left_gap.last - left_gap.first > 1 | ||
| 289 | visible -= right_gap.to_a if right_gap.last - right_gap.first > 1 | ||
| 290 | |||
| 291 | visible | ||
| 292 | end | ||
| 293 | |||
| 294 | def page_link_or_span(page, span_class, text = nil) | ||
| 295 | text ||= page.to_s | ||
| 296 | |||
| 297 | if page and page != current_page | ||
| 298 | classnames = span_class && span_class.index(' ') && span_class.split(' ', 2).last | ||
| 299 | page_link page, text, :rel => rel_value(page), :class => classnames | ||
| 300 | else | ||
| 301 | page_span page, text, :class => span_class | ||
| 302 | end | ||
| 303 | end | ||
| 304 | |||
| 305 | def page_link(page, text, attributes = {}) | ||
| 306 | @template.link_to text, url_for(page), attributes | ||
| 307 | end | ||
| 308 | |||
| 309 | def page_span(page, text, attributes = {}) | ||
| 310 | @template.content_tag :span, text, attributes | ||
| 311 | end | ||
| 312 | |||
| 313 | # Returns URL params for +page_link_or_span+, taking the current GET params | ||
| 314 | # and <tt>:params</tt> option into account. | ||
| 315 | def url_for(page) | ||
| 316 | page_one = page == 1 | ||
| 317 | unless @url_string and !page_one | ||
| 318 | @url_params = {} | ||
| 319 | # page links should preserve GET parameters | ||
| 320 | stringified_merge @url_params, @template.params if @template.request.get? | ||
| 321 | stringified_merge @url_params, @options[:params] if @options[:params] | ||
| 322 | |||
| 323 | if complex = param_name.index(/[^\w-]/) | ||
| 324 | page_param = (defined?(CGIMethods) ? CGIMethods : ActionController::AbstractRequest). | ||
| 325 | parse_query_parameters("#{param_name}=#{page}") | ||
| 326 | |||
| 327 | stringified_merge @url_params, page_param | ||
| 328 | else | ||
| 329 | @url_params[param_name] = page_one ? 1 : 2 | ||
| 330 | end | ||
| 331 | |||
| 332 | url = @template.url_for(@url_params) | ||
| 333 | return url if page_one | ||
| 334 | |||
| 335 | if complex | ||
| 336 | @url_string = url.sub(%r!((?:\?|&)#{CGI.escape param_name}=)#{page}!, '\1@') | ||
| 337 | return url | ||
| 338 | else | ||
| 339 | @url_string = url | ||
| 340 | @url_params[param_name] = 3 | ||
| 341 | @template.url_for(@url_params).split(//).each_with_index do |char, i| | ||
| 342 | if char == '3' and url[i, 1] == '2' | ||
| 343 | @url_string[i] = '@' | ||
| 344 | break | ||
| 345 | end | ||
| 346 | end | ||
| 347 | end | ||
| 348 | end | ||
| 349 | # finally! | ||
| 350 | @url_string.sub '@', page.to_s | ||
| 351 | end | ||
| 352 | |||
| 353 | private | ||
| 354 | |||
| 355 | def rel_value(page) | ||
| 356 | case page | ||
| 357 | when @collection.previous_page; 'prev' + (page == 1 ? ' start' : '') | ||
| 358 | when @collection.next_page; 'next' | ||
| 359 | when 1; 'start' | ||
| 360 | end | ||
| 361 | end | ||
| 362 | |||
| 363 | def current_page | ||
| 364 | @collection.current_page | ||
| 365 | end | ||
| 366 | |||
| 367 | def total_pages | ||
| 368 | @total_pages ||= WillPaginate::ViewHelpers.total_pages_for_collection(@collection) | ||
| 369 | end | ||
| 370 | |||
| 371 | def param_name | ||
| 372 | @param_name ||= @options[:param_name].to_s | ||
| 373 | end | ||
| 374 | |||
| 375 | # Recursively merge into target hash by using stringified keys from the other one | ||
| 376 | def stringified_merge(target, other) | ||
| 377 | other.each do |key, value| | ||
| 378 | key = key.to_s # this line is what it's all about! | ||
| 379 | existing = target[key] | ||
| 380 | |||
| 381 | if value.is_a?(Hash) and (existing.is_a?(Hash) or existing.nil?) | ||
| 382 | stringified_merge(existing || (target[key] = {}), value) | ||
| 383 | else | ||
| 384 | target[key] = value | ||
| 385 | end | ||
| 386 | end | ||
| 387 | end | ||
| 388 | end | ||
| 389 | end | ||
diff --git a/vendor/plugins/will_paginate/test/boot.rb b/vendor/plugins/will_paginate/test/boot.rb deleted file mode 100644 index 622fc93..0000000 --- a/vendor/plugins/will_paginate/test/boot.rb +++ /dev/null | |||
| @@ -1,21 +0,0 @@ | |||
| 1 | plugin_root = File.join(File.dirname(__FILE__), '..') | ||
| 2 | version = ENV['RAILS_VERSION'] | ||
| 3 | version = nil if version and version == "" | ||
| 4 | |||
| 5 | # first look for a symlink to a copy of the framework | ||
| 6 | if !version and framework_root = ["#{plugin_root}/rails", "#{plugin_root}/../../rails"].find { |p| File.directory? p } | ||
| 7 | puts "found framework root: #{framework_root}" | ||
| 8 | # this allows for a plugin to be tested outside of an app and without Rails gems | ||
| 9 | $:.unshift "#{framework_root}/activesupport/lib", "#{framework_root}/activerecord/lib", "#{framework_root}/actionpack/lib" | ||
| 10 | else | ||
| 11 | # simply use installed gems if available | ||
| 12 | puts "using Rails#{version ? ' ' + version : nil} gems" | ||
| 13 | require 'rubygems' | ||
| 14 | |||
| 15 | if version | ||
| 16 | gem 'rails', version | ||
| 17 | else | ||
| 18 | gem 'actionpack' | ||
| 19 | gem 'activerecord' | ||
| 20 | end | ||
| 21 | end | ||
diff --git a/vendor/plugins/will_paginate/test/collection_test.rb b/vendor/plugins/will_paginate/test/collection_test.rb deleted file mode 100644 index a9336bb..0000000 --- a/vendor/plugins/will_paginate/test/collection_test.rb +++ /dev/null | |||
| @@ -1,143 +0,0 @@ | |||
| 1 | require 'helper' | ||
| 2 | require 'will_paginate/array' | ||
| 3 | |||
| 4 | class ArrayPaginationTest < Test::Unit::TestCase | ||
| 5 | |||
| 6 | def setup ; end | ||
| 7 | |||
| 8 | def test_simple | ||
| 9 | collection = ('a'..'e').to_a | ||
| 10 | |||
| 11 | [{ :page => 1, :per_page => 3, :expected => %w( a b c ) }, | ||
| 12 | { :page => 2, :per_page => 3, :expected => %w( d e ) }, | ||
| 13 | { :page => 1, :per_page => 5, :expected => %w( a b c d e ) }, | ||
| 14 | { :page => 3, :per_page => 5, :expected => [] }, | ||
| 15 | ]. | ||
| 16 | each do |conditions| | ||
| 17 | expected = conditions.delete :expected | ||
| 18 | assert_equal expected, collection.paginate(conditions) | ||
| 19 | end | ||
| 20 | end | ||
| 21 | |||
| 22 | def test_defaults | ||
| 23 | result = (1..50).to_a.paginate | ||
| 24 | assert_equal 1, result.current_page | ||
| 25 | assert_equal 30, result.size | ||
| 26 | end | ||
| 27 | |||
| 28 | def test_deprecated_api | ||
| 29 | assert_raise(ArgumentError) { [].paginate(2) } | ||
| 30 | assert_raise(ArgumentError) { [].paginate(2, 10) } | ||
| 31 | end | ||
| 32 | |||
| 33 | def test_total_entries_has_precedence | ||
| 34 | result = %w(a b c).paginate :total_entries => 5 | ||
| 35 | assert_equal 5, result.total_entries | ||
| 36 | end | ||
| 37 | |||
| 38 | def test_argument_error_with_params_and_another_argument | ||
| 39 | assert_raise ArgumentError do | ||
| 40 | [].paginate({}, 5) | ||
| 41 | end | ||
| 42 | end | ||
| 43 | |||
| 44 | def test_paginated_collection | ||
| 45 | entries = %w(a b c) | ||
| 46 | collection = create(2, 3, 10) do |pager| | ||
| 47 | assert_equal entries, pager.replace(entries) | ||
| 48 | end | ||
| 49 | |||
| 50 | assert_equal entries, collection | ||
| 51 | assert_respond_to_all collection, %w(total_pages each offset size current_page per_page total_entries) | ||
| 52 | assert_kind_of Array, collection | ||
| 53 | assert_instance_of Array, collection.entries | ||
| 54 | assert_equal 3, collection.offset | ||
| 55 | assert_equal 4, collection.total_pages | ||
| 56 | assert !collection.out_of_bounds? | ||
| 57 | end | ||
| 58 | |||
| 59 | def test_previous_next_pages | ||
| 60 | collection = create(1, 1, 3) | ||
| 61 | assert_nil collection.previous_page | ||
| 62 | assert_equal 2, collection.next_page | ||
| 63 | |||
| 64 | collection = create(2, 1, 3) | ||
| 65 | assert_equal 1, collection.previous_page | ||
| 66 | assert_equal 3, collection.next_page | ||
| 67 | |||
| 68 | collection = create(3, 1, 3) | ||
| 69 | assert_equal 2, collection.previous_page | ||
| 70 | assert_nil collection.next_page | ||
| 71 | end | ||
| 72 | |||
| 73 | def test_out_of_bounds | ||
| 74 | entries = create(2, 3, 2){} | ||
| 75 | assert entries.out_of_bounds? | ||
| 76 | |||
| 77 | entries = create(1, 3, 2){} | ||
| 78 | assert !entries.out_of_bounds? | ||
| 79 | end | ||
| 80 | |||
| 81 | def test_guessing_total_count | ||
| 82 | entries = create do |pager| | ||
| 83 | # collection is shorter than limit | ||
| 84 | pager.replace array | ||
| 85 | end | ||
| 86 | assert_equal 8, entries.total_entries | ||
| 87 | |||
| 88 | entries = create(2, 5, 10) do |pager| | ||
| 89 | # collection is shorter than limit, but we have an explicit count | ||
| 90 | pager.replace array | ||
| 91 | end | ||
| 92 | assert_equal 10, entries.total_entries | ||
| 93 | |||
| 94 | entries = create do |pager| | ||
| 95 | # collection is the same as limit; we can't guess | ||
| 96 | pager.replace array(5) | ||
| 97 | end | ||
| 98 | assert_equal nil, entries.total_entries | ||
| 99 | |||
| 100 | entries = create do |pager| | ||
| 101 | # collection is empty; we can't guess | ||
| 102 | pager.replace array(0) | ||
| 103 | end | ||
| 104 | assert_equal nil, entries.total_entries | ||
| 105 | |||
| 106 | entries = create(1) do |pager| | ||
| 107 | # collection is empty and we're on page 1, | ||
| 108 | # so the whole thing must be empty, too | ||
| 109 | pager.replace array(0) | ||
| 110 | end | ||
| 111 | assert_equal 0, entries.total_entries | ||
| 112 | end | ||
| 113 | |||
| 114 | def test_invalid_page | ||
| 115 | bad_inputs = [0, -1, nil, '', 'Schnitzel'] | ||
| 116 | |||
| 117 | bad_inputs.each do |bad| | ||
| 118 | assert_raise(WillPaginate::InvalidPage) { create bad } | ||
| 119 | end | ||
| 120 | end | ||
| 121 | |||
| 122 | def test_invalid_per_page_setting | ||
| 123 | assert_raise(ArgumentError) { create(1, -1) } | ||
| 124 | end | ||
| 125 | |||
| 126 | def test_page_count_was_removed | ||
| 127 | assert_raise(NoMethodError) { create.page_count } | ||
| 128 | # It's `total_pages` now. | ||
| 129 | end | ||
| 130 | |||
| 131 | private | ||
| 132 | def create(page = 2, limit = 5, total = nil, &block) | ||
| 133 | if block_given? | ||
| 134 | WillPaginate::Collection.create(page, limit, total, &block) | ||
| 135 | else | ||
| 136 | WillPaginate::Collection.new(page, limit, total) | ||
| 137 | end | ||
| 138 | end | ||
| 139 | |||
| 140 | def array(size = 3) | ||
| 141 | Array.new(size) | ||
| 142 | end | ||
| 143 | end | ||
diff --git a/vendor/plugins/will_paginate/test/console b/vendor/plugins/will_paginate/test/console deleted file mode 100755 index 3f282f1..0000000 --- a/vendor/plugins/will_paginate/test/console +++ /dev/null | |||
| @@ -1,8 +0,0 @@ | |||
| 1 | #!/usr/bin/env ruby | ||
| 2 | irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb' | ||
| 3 | libs = [] | ||
| 4 | |||
| 5 | libs << 'irb/completion' | ||
| 6 | libs << File.join('lib', 'load_fixtures') | ||
| 7 | |||
| 8 | exec "#{irb} -Ilib:test#{libs.map{ |l| " -r #{l}" }.join} --simple-prompt" | ||
diff --git a/vendor/plugins/will_paginate/test/finder_test.rb b/vendor/plugins/will_paginate/test/finder_test.rb deleted file mode 100644 index 38ef565..0000000 --- a/vendor/plugins/will_paginate/test/finder_test.rb +++ /dev/null | |||
| @@ -1,476 +0,0 @@ | |||
| 1 | require 'helper' | ||
| 2 | require 'lib/activerecord_test_case' | ||
| 3 | |||
| 4 | require 'will_paginate' | ||
| 5 | WillPaginate.enable_activerecord | ||
| 6 | WillPaginate.enable_named_scope | ||
| 7 | |||
| 8 | class FinderTest < ActiveRecordTestCase | ||
| 9 | fixtures :topics, :replies, :users, :projects, :developers_projects | ||
| 10 | |||
| 11 | def test_new_methods_presence | ||
| 12 | assert_respond_to_all Topic, %w(per_page paginate paginate_by_sql) | ||
| 13 | end | ||
| 14 | |||
| 15 | def test_simple_paginate | ||
| 16 | assert_queries(1) do | ||
| 17 | entries = Topic.paginate :page => nil | ||
| 18 | assert_equal 1, entries.current_page | ||
| 19 | assert_equal 1, entries.total_pages | ||
| 20 | assert_equal 4, entries.size | ||
| 21 | end | ||
| 22 | |||
| 23 | assert_queries(2) do | ||
| 24 | entries = Topic.paginate :page => 2 | ||
| 25 | assert_equal 1, entries.total_pages | ||
| 26 | assert entries.empty? | ||
| 27 | end | ||
| 28 | end | ||
| 29 | |||
| 30 | def test_parameter_api | ||
| 31 | # :page parameter in options is required! | ||
| 32 | assert_raise(ArgumentError){ Topic.paginate } | ||
| 33 | assert_raise(ArgumentError){ Topic.paginate({}) } | ||
| 34 | |||
| 35 | # explicit :all should not break anything | ||
| 36 | assert_equal Topic.paginate(:page => nil), Topic.paginate(:all, :page => 1) | ||
| 37 | |||
| 38 | # :count could be nil and we should still not cry | ||
| 39 | assert_nothing_raised { Topic.paginate :page => 1, :count => nil } | ||
| 40 | end | ||
| 41 | |||
| 42 | def test_paginate_with_per_page | ||
| 43 | entries = Topic.paginate :page => 1, :per_page => 1 | ||
| 44 | assert_equal 1, entries.size | ||
| 45 | assert_equal 4, entries.total_pages | ||
| 46 | |||
| 47 | # Developer class has explicit per_page at 10 | ||
| 48 | entries = Developer.paginate :page => 1 | ||
| 49 | assert_equal 10, entries.size | ||
| 50 | assert_equal 2, entries.total_pages | ||
| 51 | |||
| 52 | entries = Developer.paginate :page => 1, :per_page => 5 | ||
| 53 | assert_equal 11, entries.total_entries | ||
| 54 | assert_equal 5, entries.size | ||
| 55 | assert_equal 3, entries.total_pages | ||
| 56 | end | ||
| 57 | |||
| 58 | def test_paginate_with_order | ||
| 59 | entries = Topic.paginate :page => 1, :order => 'created_at desc' | ||
| 60 | expected = [topics(:futurama), topics(:harvey_birdman), topics(:rails), topics(:ar)].reverse | ||
| 61 | assert_equal expected, entries.to_a | ||
| 62 | assert_equal 1, entries.total_pages | ||
| 63 | end | ||
| 64 | |||
| 65 | def test_paginate_with_conditions | ||
| 66 | entries = Topic.paginate :page => 1, :conditions => ["created_at > ?", 30.minutes.ago] | ||
| 67 | expected = [topics(:rails), topics(:ar)] | ||
| 68 | assert_equal expected, entries.to_a | ||
| 69 | assert_equal 1, entries.total_pages | ||
| 70 | end | ||
| 71 | |||
| 72 | def test_paginate_with_include_and_conditions | ||
| 73 | entries = Topic.paginate \ | ||
| 74 | :page => 1, | ||
| 75 | :include => :replies, | ||
| 76 | :conditions => "replies.content LIKE 'Bird%' ", | ||
| 77 | :per_page => 10 | ||
| 78 | |||
| 79 | expected = Topic.find :all, | ||
| 80 | :include => 'replies', | ||
| 81 | :conditions => "replies.content LIKE 'Bird%' ", | ||
| 82 | :limit => 10 | ||
| 83 | |||
| 84 | assert_equal expected, entries.to_a | ||
| 85 | assert_equal 1, entries.total_entries | ||
| 86 | end | ||
| 87 | |||
| 88 | def test_paginate_with_include_and_order | ||
| 89 | entries = nil | ||
| 90 | assert_queries(2) do | ||
| 91 | entries = Topic.paginate \ | ||
| 92 | :page => 1, | ||
| 93 | :include => :replies, | ||
| 94 | :order => 'replies.created_at asc, topics.created_at asc', | ||
| 95 | :per_page => 10 | ||
| 96 | end | ||
| 97 | |||
| 98 | expected = Topic.find :all, | ||
| 99 | :include => 'replies', | ||
| 100 | :order => 'replies.created_at asc, topics.created_at asc', | ||
| 101 | :limit => 10 | ||
| 102 | |||
| 103 | assert_equal expected, entries.to_a | ||
| 104 | assert_equal 4, entries.total_entries | ||
| 105 | end | ||
| 106 | |||
| 107 | def test_paginate_associations_with_include | ||
| 108 | entries, project = nil, projects(:active_record) | ||
| 109 | |||
| 110 | assert_nothing_raised "THIS IS A BUG in Rails 1.2.3 that was fixed in [7326]. " + | ||
| 111 | "Please upgrade to a newer version of Rails." do | ||
| 112 | entries = project.topics.paginate \ | ||
| 113 | :page => 1, | ||
| 114 | :include => :replies, | ||
| 115 | :conditions => "replies.content LIKE 'Nice%' ", | ||
| 116 | :per_page => 10 | ||
| 117 | end | ||
| 118 | |||
| 119 | expected = Topic.find :all, | ||
| 120 | :include => 'replies', | ||
| 121 | :conditions => "project_id = #{project.id} AND replies.content LIKE 'Nice%' ", | ||
| 122 | :limit => 10 | ||
| 123 | |||
| 124 | assert_equal expected, entries.to_a | ||
| 125 | end | ||
| 126 | |||
| 127 | def test_paginate_associations | ||
| 128 | dhh = users :david | ||
| 129 | expected_name_ordered = [projects(:action_controller), projects(:active_record)] | ||
| 130 | expected_id_ordered = [projects(:active_record), projects(:action_controller)] | ||
| 131 | |||
| 132 | assert_queries(2) do | ||
| 133 | # with association-specified order | ||
| 134 | entries = dhh.projects.paginate(:page => 1) | ||
| 135 | assert_equal expected_name_ordered, entries | ||
| 136 | assert_equal 2, entries.total_entries | ||
| 137 | end | ||
| 138 | |||
| 139 | # with explicit order | ||
| 140 | entries = dhh.projects.paginate(:page => 1, :order => 'projects.id') | ||
| 141 | assert_equal expected_id_ordered, entries | ||
| 142 | assert_equal 2, entries.total_entries | ||
| 143 | |||
| 144 | assert_nothing_raised { dhh.projects.find(:all, :order => 'projects.id', :limit => 4) } | ||
| 145 | entries = dhh.projects.paginate(:page => 1, :order => 'projects.id', :per_page => 4) | ||
| 146 | assert_equal expected_id_ordered, entries | ||
| 147 | |||
| 148 | # has_many with implicit order | ||
| 149 | topic = Topic.find(1) | ||
| 150 | expected = [replies(:spam), replies(:witty_retort)] | ||
| 151 | assert_equal expected.map(&:id).sort, topic.replies.paginate(:page => 1).map(&:id).sort | ||
| 152 | assert_equal expected.reverse, topic.replies.paginate(:page => 1, :order => 'replies.id ASC') | ||
| 153 | end | ||
| 154 | |||
| 155 | def test_paginate_association_extension | ||
| 156 | project = Project.find(:first) | ||
| 157 | |||
| 158 | assert_queries(2) do | ||
| 159 | entries = project.replies.paginate_recent :page => 1 | ||
| 160 | assert_equal [replies(:brave)], entries | ||
| 161 | end | ||
| 162 | end | ||
| 163 | |||
| 164 | def test_paginate_with_joins | ||
| 165 | entries = nil | ||
| 166 | |||
| 167 | assert_queries(1) do | ||
| 168 | entries = Developer.paginate :page => 1, | ||
| 169 | :joins => 'LEFT JOIN developers_projects ON users.id = developers_projects.developer_id', | ||
| 170 | :conditions => 'project_id = 1' | ||
| 171 | assert_equal 2, entries.size | ||
| 172 | developer_names = entries.map &:name | ||
| 173 | assert developer_names.include?('David') | ||
| 174 | assert developer_names.include?('Jamis') | ||
| 175 | end | ||
| 176 | |||
| 177 | assert_queries(1) do | ||
| 178 | expected = entries.to_a | ||
| 179 | entries = Developer.paginate :page => 1, | ||
| 180 | :joins => 'LEFT JOIN developers_projects ON users.id = developers_projects.developer_id', | ||
| 181 | :conditions => 'project_id = 1', :count => { :select => "users.id" } | ||
| 182 | assert_equal expected, entries.to_a | ||
| 183 | assert_equal 2, entries.total_entries | ||
| 184 | end | ||
| 185 | end | ||
| 186 | |||
| 187 | def test_paginate_with_group | ||
| 188 | entries = nil | ||
| 189 | assert_queries(1) do | ||
| 190 | entries = Developer.paginate :page => 1, :per_page => 10, | ||
| 191 | :group => 'salary', :select => 'salary', :order => 'salary' | ||
| 192 | end | ||
| 193 | |||
| 194 | expected = [ users(:david), users(:jamis), users(:dev_10), users(:poor_jamis) ].map(&:salary).sort | ||
| 195 | assert_equal expected, entries.map(&:salary) | ||
| 196 | end | ||
| 197 | |||
| 198 | def test_paginate_with_dynamic_finder | ||
| 199 | expected = [replies(:witty_retort), replies(:spam)] | ||
| 200 | assert_equal expected, Reply.paginate_by_topic_id(1, :page => 1) | ||
| 201 | |||
| 202 | entries = Developer.paginate :conditions => { :salary => 100000 }, :page => 1, :per_page => 5 | ||
| 203 | assert_equal 8, entries.total_entries | ||
| 204 | assert_equal entries, Developer.paginate_by_salary(100000, :page => 1, :per_page => 5) | ||
| 205 | |||
| 206 | # dynamic finder + conditions | ||
| 207 | entries = Developer.paginate_by_salary(100000, :page => 1, | ||
| 208 | :conditions => ['id > ?', 6]) | ||
| 209 | assert_equal 4, entries.total_entries | ||
| 210 | assert_equal (7..10).to_a, entries.map(&:id) | ||
| 211 | |||
| 212 | assert_raises NoMethodError do | ||
| 213 | Developer.paginate_by_inexistent_attribute 100000, :page => 1 | ||
| 214 | end | ||
| 215 | end | ||
| 216 | |||
| 217 | def test_scoped_paginate | ||
| 218 | entries = Developer.with_poor_ones { Developer.paginate :page => 1 } | ||
| 219 | |||
| 220 | assert_equal 2, entries.size | ||
| 221 | assert_equal 2, entries.total_entries | ||
| 222 | end | ||
| 223 | |||
| 224 | ## named_scope ## | ||
| 225 | |||
| 226 | def test_paginate_in_named_scope | ||
| 227 | entries = Developer.poor.paginate :page => 1, :per_page => 1 | ||
| 228 | |||
| 229 | assert_equal 1, entries.size | ||
| 230 | assert_equal 2, entries.total_entries | ||
| 231 | end | ||
| 232 | |||
| 233 | def test_paginate_in_named_scope_on_habtm_association | ||
| 234 | project = projects(:active_record) | ||
| 235 | assert_queries(2) do | ||
| 236 | entries = project.developers.poor.paginate :page => 1, :per_page => 1 | ||
| 237 | |||
| 238 | assert_equal 1, entries.size, 'one developer should be found' | ||
| 239 | assert_equal 1, entries.total_entries, 'only one developer should be found' | ||
| 240 | end | ||
| 241 | end | ||
| 242 | |||
| 243 | def test_paginate_in_named_scope_on_hmt_association | ||
| 244 | project = projects(:active_record) | ||
| 245 | expected = [replies(:brave)] | ||
| 246 | |||
| 247 | assert_queries(2) do | ||
| 248 | entries = project.replies.recent.paginate :page => 1, :per_page => 1 | ||
| 249 | assert_equal expected, entries | ||
| 250 | assert_equal 1, entries.total_entries, 'only one reply should be found' | ||
| 251 | end | ||
| 252 | end | ||
| 253 | |||
| 254 | def test_paginate_in_named_scope_on_has_many_association | ||
| 255 | project = projects(:active_record) | ||
| 256 | expected = [topics(:ar)] | ||
| 257 | |||
| 258 | assert_queries(2) do | ||
| 259 | entries = project.topics.mentions_activerecord.paginate :page => 1, :per_page => 1 | ||
| 260 | assert_equal expected, entries | ||
| 261 | assert_equal 1, entries.total_entries, 'only one topic should be found' | ||
| 262 | end | ||
| 263 | end | ||
| 264 | |||
| 265 | def test_named_scope_with_include | ||
| 266 | project = projects(:active_record) | ||
| 267 | entries = project.topics.with_replies_starting_with('AR ').paginate(:page => 1, :per_page => 1) | ||
| 268 | assert_equal 1, entries.size | ||
| 269 | end | ||
| 270 | |||
| 271 | ## misc ## | ||
| 272 | |||
| 273 | def test_count_and_total_entries_options_are_mutually_exclusive | ||
| 274 | e = assert_raise ArgumentError do | ||
| 275 | Developer.paginate :page => 1, :count => {}, :total_entries => 1 | ||
| 276 | end | ||
| 277 | assert_match /exclusive/, e.to_s | ||
| 278 | end | ||
| 279 | |||
| 280 | def test_readonly | ||
| 281 | assert_nothing_raised { Developer.paginate :readonly => true, :page => 1 } | ||
| 282 | end | ||
| 283 | |||
| 284 | # this functionality is temporarily removed | ||
| 285 | def xtest_pagination_defines_method | ||
| 286 | pager = "paginate_by_created_at" | ||
| 287 | assert !User.methods.include?(pager), "User methods should not include `#{pager}` method" | ||
| 288 | # paginate! | ||
| 289 | assert 0, User.send(pager, nil, :page => 1).total_entries | ||
| 290 | # the paging finder should now be defined | ||
| 291 | assert User.methods.include?(pager), "`#{pager}` method should be defined on User" | ||
| 292 | end | ||
| 293 | |||
| 294 | # Is this Rails 2.0? Find out by testing find_all which was removed in [6998] | ||
| 295 | unless ActiveRecord::Base.respond_to? :find_all | ||
| 296 | def test_paginate_array_of_ids | ||
| 297 | # AR finders also accept arrays of IDs | ||
| 298 | # (this was broken in Rails before [6912]) | ||
| 299 | assert_queries(1) do | ||
| 300 | entries = Developer.paginate((1..8).to_a, :per_page => 3, :page => 2, :order => 'id') | ||
| 301 | assert_equal (4..6).to_a, entries.map(&:id) | ||
| 302 | assert_equal 8, entries.total_entries | ||
| 303 | end | ||
| 304 | end | ||
| 305 | end | ||
| 306 | |||
| 307 | uses_mocha 'internals' do | ||
| 308 | def test_implicit_all_with_dynamic_finders | ||
| 309 | Topic.expects(:find_all_by_foo).returns([]) | ||
| 310 | Topic.expects(:count).returns(0) | ||
| 311 | Topic.paginate_by_foo :page => 2 | ||
| 312 | end | ||
| 313 | |||
| 314 | def test_guessing_the_total_count | ||
| 315 | Topic.expects(:find).returns(Array.new(2)) | ||
| 316 | Topic.expects(:count).never | ||
| 317 | |||
| 318 | entries = Topic.paginate :page => 2, :per_page => 4 | ||
| 319 | assert_equal 6, entries.total_entries | ||
| 320 | end | ||
| 321 | |||
| 322 | def test_guessing_that_there_are_no_records | ||
| 323 | Topic.expects(:find).returns([]) | ||
| 324 | Topic.expects(:count).never | ||
| 325 | |||
| 326 | entries = Topic.paginate :page => 1, :per_page => 4 | ||
| 327 | assert_equal 0, entries.total_entries | ||
| 328 | end | ||
| 329 | |||
| 330 | def test_extra_parameters_stay_untouched | ||
| 331 | Topic.expects(:find).with(:all, {:foo => 'bar', :limit => 4, :offset => 0 }).returns(Array.new(5)) | ||
| 332 | Topic.expects(:count).with({:foo => 'bar'}).returns(1) | ||
| 333 | |||
| 334 | Topic.paginate :foo => 'bar', :page => 1, :per_page => 4 | ||
| 335 | end | ||
| 336 | |||
| 337 | def test_count_skips_select | ||
| 338 | Developer.stubs(:find).returns([]) | ||
| 339 | Developer.expects(:count).with({}).returns(0) | ||
| 340 | Developer.paginate :select => 'salary', :page => 2 | ||
| 341 | end | ||
| 342 | |||
| 343 | def test_count_select_when_distinct | ||
| 344 | Developer.stubs(:find).returns([]) | ||
| 345 | Developer.expects(:count).with(:select => 'DISTINCT salary').returns(0) | ||
| 346 | Developer.paginate :select => 'DISTINCT salary', :page => 2 | ||
| 347 | end | ||
| 348 | |||
| 349 | def test_count_with_scoped_select_when_distinct | ||
| 350 | Developer.stubs(:find).returns([]) | ||
| 351 | Developer.expects(:count).with(:select => 'DISTINCT users.id').returns(0) | ||
| 352 | Developer.distinct.paginate :page => 2 | ||
| 353 | end | ||
| 354 | |||
| 355 | def test_should_use_scoped_finders_if_present | ||
| 356 | # scope-out compatibility | ||
| 357 | Topic.expects(:find_best).returns(Array.new(5)) | ||
| 358 | Topic.expects(:with_best).returns(1) | ||
| 359 | |||
| 360 | Topic.paginate_best :page => 1, :per_page => 4 | ||
| 361 | end | ||
| 362 | |||
| 363 | def test_paginate_by_sql | ||
| 364 | assert_respond_to Developer, :paginate_by_sql | ||
| 365 | Developer.expects(:find_by_sql).with(regexp_matches(/sql LIMIT 3(,| OFFSET) 3/)).returns([]) | ||
| 366 | Developer.expects(:count_by_sql).with('SELECT COUNT(*) FROM (sql) AS count_table').returns(0) | ||
| 367 | |||
| 368 | entries = Developer.paginate_by_sql 'sql', :page => 2, :per_page => 3 | ||
| 369 | end | ||
| 370 | |||
| 371 | def test_paginate_by_sql_respects_total_entries_setting | ||
| 372 | Developer.expects(:find_by_sql).returns([]) | ||
| 373 | Developer.expects(:count_by_sql).never | ||
| 374 | |||
| 375 | entries = Developer.paginate_by_sql 'sql', :page => 1, :total_entries => 999 | ||
| 376 | assert_equal 999, entries.total_entries | ||
| 377 | end | ||
| 378 | |||
| 379 | def test_paginate_by_sql_strips_order_by_when_counting | ||
| 380 | Developer.expects(:find_by_sql).returns([]) | ||
| 381 | Developer.expects(:count_by_sql).with("SELECT COUNT(*) FROM (sql\n ) AS count_table").returns(0) | ||
| 382 | |||
| 383 | Developer.paginate_by_sql "sql\n ORDER\nby foo, bar, `baz` ASC", :page => 2 | ||
| 384 | end | ||
| 385 | |||
| 386 | # TODO: counts are still wrong | ||
| 387 | def test_ability_to_use_with_custom_finders | ||
| 388 | # acts_as_taggable defines find_tagged_with(tag, options) | ||
| 389 | Topic.expects(:find_tagged_with).with('will_paginate', :offset => 5, :limit => 5).returns([]) | ||
| 390 | Topic.expects(:count).with({}).returns(0) | ||
| 391 | |||
| 392 | Topic.paginate_tagged_with 'will_paginate', :page => 2, :per_page => 5 | ||
| 393 | end | ||
| 394 | |||
| 395 | def test_array_argument_doesnt_eliminate_count | ||
| 396 | ids = (1..8).to_a | ||
| 397 | Developer.expects(:find_all_by_id).returns([]) | ||
| 398 | Developer.expects(:count).returns(0) | ||
| 399 | |||
| 400 | Developer.paginate_by_id(ids, :per_page => 3, :page => 2, :order => 'id') | ||
| 401 | end | ||
| 402 | |||
| 403 | def test_paginating_finder_doesnt_mangle_options | ||
| 404 | Developer.expects(:find).returns([]) | ||
| 405 | options = { :page => 1, :per_page => 2, :foo => 'bar' } | ||
| 406 | options_before = options.dup | ||
| 407 | |||
| 408 | Developer.paginate(options) | ||
| 409 | assert_equal options_before, options | ||
| 410 | end | ||
| 411 | |||
| 412 | def test_paginate_by_sql_doesnt_change_original_query | ||
| 413 | query = 'SQL QUERY' | ||
| 414 | original_query = query.dup | ||
| 415 | Developer.expects(:find_by_sql).returns([]) | ||
| 416 | |||
| 417 | Developer.paginate_by_sql query, :page => 1 | ||
| 418 | assert_equal original_query, query | ||
| 419 | end | ||
| 420 | |||
| 421 | def test_paginated_each | ||
| 422 | collection = stub('collection', :size => 5, :empty? => false, :per_page => 5) | ||
| 423 | collection.expects(:each).times(2).returns(collection) | ||
| 424 | last_collection = stub('collection', :size => 4, :empty? => false, :per_page => 5) | ||
| 425 | last_collection.expects(:each).returns(last_collection) | ||
| 426 | |||
| 427 | params = { :order => 'id', :total_entries => 0 } | ||
| 428 | |||
| 429 | Developer.expects(:paginate).with(params.merge(:page => 2)).returns(collection) | ||
| 430 | Developer.expects(:paginate).with(params.merge(:page => 3)).returns(collection) | ||
| 431 | Developer.expects(:paginate).with(params.merge(:page => 4)).returns(last_collection) | ||
| 432 | |||
| 433 | assert_equal 14, Developer.paginated_each(:page => '2') { } | ||
| 434 | end | ||
| 435 | |||
| 436 | def test_paginated_each_with_named_scope | ||
| 437 | assert_equal 2, Developer.poor.paginated_each(:per_page => 1) { | ||
| 438 | assert_equal 11, Developer.count | ||
| 439 | } | ||
| 440 | end | ||
| 441 | |||
| 442 | # detect ActiveRecord 2.1 | ||
| 443 | if ActiveRecord::Base.private_methods.include?('references_eager_loaded_tables?') | ||
| 444 | def test_removes_irrelevant_includes_in_count | ||
| 445 | Developer.expects(:find).returns([1]) | ||
| 446 | Developer.expects(:count).with({}).returns(0) | ||
| 447 | |||
| 448 | Developer.paginate :page => 1, :per_page => 1, :include => :projects | ||
| 449 | end | ||
| 450 | |||
| 451 | def test_doesnt_remove_referenced_includes_in_count | ||
| 452 | Developer.expects(:find).returns([1]) | ||
| 453 | Developer.expects(:count).with({ :include => :projects, :conditions => 'projects.id > 2' }).returns(0) | ||
| 454 | |||
| 455 | Developer.paginate :page => 1, :per_page => 1, | ||
| 456 | :include => :projects, :conditions => 'projects.id > 2' | ||
| 457 | end | ||
| 458 | end | ||
| 459 | |||
| 460 | def test_paginate_from | ||
| 461 | result = Developer.paginate(:from => 'users', :page => 1, :per_page => 1) | ||
| 462 | assert_equal 1, result.size | ||
| 463 | end | ||
| 464 | |||
| 465 | def test_hmt_with_include | ||
| 466 | # ticket #220 | ||
| 467 | reply = projects(:active_record).replies.find(:first, :order => 'replies.id') | ||
| 468 | assert_equal replies(:decisive), reply | ||
| 469 | |||
| 470 | # ticket #223 | ||
| 471 | Project.find(1, :include => :replies) | ||
| 472 | |||
| 473 | # I cannot reproduce any of the failures from those reports :( | ||
| 474 | end | ||
| 475 | end | ||
| 476 | end | ||
diff --git a/vendor/plugins/will_paginate/test/fixtures/admin.rb b/vendor/plugins/will_paginate/test/fixtures/admin.rb deleted file mode 100644 index 1d5e7f3..0000000 --- a/vendor/plugins/will_paginate/test/fixtures/admin.rb +++ /dev/null | |||
| @@ -1,3 +0,0 @@ | |||
| 1 | class Admin < User | ||
| 2 | has_many :companies, :finder_sql => 'SELECT * FROM companies' | ||
| 3 | end | ||
diff --git a/vendor/plugins/will_paginate/test/fixtures/developer.rb b/vendor/plugins/will_paginate/test/fixtures/developer.rb deleted file mode 100644 index 0224f4b..0000000 --- a/vendor/plugins/will_paginate/test/fixtures/developer.rb +++ /dev/null | |||
| @@ -1,14 +0,0 @@ | |||
| 1 | class Developer < User | ||
| 2 | has_and_belongs_to_many :projects, :include => :topics, :order => 'projects.name' | ||
| 3 | |||
| 4 | def self.with_poor_ones(&block) | ||
| 5 | with_scope :find => { :conditions => ['salary <= ?', 80000], :order => 'salary' } do | ||
| 6 | yield | ||
| 7 | end | ||
| 8 | end | ||
| 9 | |||
| 10 | named_scope :distinct, :select => 'DISTINCT `users`.*' | ||
| 11 | named_scope :poor, :conditions => ['salary <= ?', 80000], :order => 'salary' | ||
| 12 | |||
| 13 | def self.per_page() 10 end | ||
| 14 | end | ||
diff --git a/vendor/plugins/will_paginate/test/fixtures/developers_projects.yml b/vendor/plugins/will_paginate/test/fixtures/developers_projects.yml deleted file mode 100644 index cee359c..0000000 --- a/vendor/plugins/will_paginate/test/fixtures/developers_projects.yml +++ /dev/null | |||
| @@ -1,13 +0,0 @@ | |||
| 1 | david_action_controller: | ||
| 2 | developer_id: 1 | ||
| 3 | project_id: 2 | ||
| 4 | joined_on: 2004-10-10 | ||
| 5 | |||
| 6 | david_active_record: | ||
| 7 | developer_id: 1 | ||
| 8 | project_id: 1 | ||
| 9 | joined_on: 2004-10-10 | ||
| 10 | |||
| 11 | jamis_active_record: | ||
| 12 | developer_id: 2 | ||
| 13 | project_id: 1 \ No newline at end of file | ||
diff --git a/vendor/plugins/will_paginate/test/fixtures/project.rb b/vendor/plugins/will_paginate/test/fixtures/project.rb deleted file mode 100644 index 0f85ef5..0000000 --- a/vendor/plugins/will_paginate/test/fixtures/project.rb +++ /dev/null | |||
| @@ -1,15 +0,0 @@ | |||
| 1 | class Project < ActiveRecord::Base | ||
| 2 | has_and_belongs_to_many :developers, :uniq => true | ||
| 3 | |||
| 4 | has_many :topics | ||
| 5 | # :finder_sql => 'SELECT * FROM topics WHERE (topics.project_id = #{id})', | ||
| 6 | # :counter_sql => 'SELECT COUNT(*) FROM topics WHERE (topics.project_id = #{id})' | ||
| 7 | |||
| 8 | has_many :replies, :through => :topics do | ||
| 9 | def find_recent(params = {}) | ||
| 10 | with_scope :find => { :conditions => ['replies.created_at > ?', 15.minutes.ago] } do | ||
| 11 | find :all, params | ||
| 12 | end | ||
| 13 | end | ||
| 14 | end | ||
| 15 | end | ||
diff --git a/vendor/plugins/will_paginate/test/fixtures/projects.yml b/vendor/plugins/will_paginate/test/fixtures/projects.yml deleted file mode 100644 index 74f3c32..0000000 --- a/vendor/plugins/will_paginate/test/fixtures/projects.yml +++ /dev/null | |||
| @@ -1,6 +0,0 @@ | |||
| 1 | active_record: | ||
| 2 | id: 1 | ||
| 3 | name: Active Record | ||
| 4 | action_controller: | ||
| 5 | id: 2 | ||
| 6 | name: Active Controller | ||
diff --git a/vendor/plugins/will_paginate/test/fixtures/replies.yml b/vendor/plugins/will_paginate/test/fixtures/replies.yml deleted file mode 100644 index 9a83c00..0000000 --- a/vendor/plugins/will_paginate/test/fixtures/replies.yml +++ /dev/null | |||
| @@ -1,29 +0,0 @@ | |||
| 1 | witty_retort: | ||
| 2 | id: 1 | ||
| 3 | topic_id: 1 | ||
| 4 | content: Birdman is better! | ||
| 5 | created_at: <%= 6.hours.ago.to_s(:db) %> | ||
| 6 | |||
| 7 | another: | ||
| 8 | id: 2 | ||
| 9 | topic_id: 2 | ||
| 10 | content: Nuh uh! | ||
| 11 | created_at: <%= 1.hour.ago.to_s(:db) %> | ||
| 12 | |||
| 13 | spam: | ||
| 14 | id: 3 | ||
| 15 | topic_id: 1 | ||
| 16 | content: Nice site! | ||
| 17 | created_at: <%= 1.hour.ago.to_s(:db) %> | ||
| 18 | |||
| 19 | decisive: | ||
| 20 | id: 4 | ||
| 21 | topic_id: 4 | ||
| 22 | content: "I'm getting to the bottom of this" | ||
| 23 | created_at: <%= 30.minutes.ago.to_s(:db) %> | ||
| 24 | |||
| 25 | brave: | ||
| 26 | id: 5 | ||
| 27 | topic_id: 4 | ||
| 28 | content: "AR doesn't scare me a bit" | ||
| 29 | created_at: <%= 10.minutes.ago.to_s(:db) %> | ||
diff --git a/vendor/plugins/will_paginate/test/fixtures/reply.rb b/vendor/plugins/will_paginate/test/fixtures/reply.rb deleted file mode 100644 index ecaf3c1..0000000 --- a/vendor/plugins/will_paginate/test/fixtures/reply.rb +++ /dev/null | |||
| @@ -1,7 +0,0 @@ | |||
| 1 | class Reply < ActiveRecord::Base | ||
| 2 | belongs_to :topic, :include => [:replies] | ||
| 3 | |||
| 4 | named_scope :recent, :conditions => ['replies.created_at > ?', 15.minutes.ago] | ||
| 5 | |||
| 6 | validates_presence_of :content | ||
| 7 | end | ||
diff --git a/vendor/plugins/will_paginate/test/fixtures/topic.rb b/vendor/plugins/will_paginate/test/fixtures/topic.rb deleted file mode 100644 index 2c2ce72..0000000 --- a/vendor/plugins/will_paginate/test/fixtures/topic.rb +++ /dev/null | |||
| @@ -1,10 +0,0 @@ | |||
| 1 | class Topic < ActiveRecord::Base | ||
| 2 | has_many :replies, :dependent => :destroy, :order => 'replies.created_at DESC' | ||
| 3 | belongs_to :project | ||
| 4 | |||
| 5 | named_scope :mentions_activerecord, :conditions => ['topics.title LIKE ?', '%ActiveRecord%'] | ||
| 6 | |||
| 7 | named_scope :with_replies_starting_with, lambda { |text| | ||
| 8 | { :conditions => "replies.content LIKE '#{text}%' ", :include => :replies } | ||
| 9 | } | ||
| 10 | end | ||
diff --git a/vendor/plugins/will_paginate/test/fixtures/topics.yml b/vendor/plugins/will_paginate/test/fixtures/topics.yml deleted file mode 100644 index 0a26904..0000000 --- a/vendor/plugins/will_paginate/test/fixtures/topics.yml +++ /dev/null | |||
| @@ -1,30 +0,0 @@ | |||
| 1 | futurama: | ||
| 2 | id: 1 | ||
| 3 | title: Isnt futurama awesome? | ||
| 4 | subtitle: It really is, isnt it. | ||
| 5 | content: I like futurama | ||
| 6 | created_at: <%= 1.day.ago.to_s(:db) %> | ||
| 7 | updated_at: | ||
| 8 | |||
| 9 | harvey_birdman: | ||
| 10 | id: 2 | ||
| 11 | title: Harvey Birdman is the king of all men | ||
| 12 | subtitle: yup | ||
| 13 | content: He really is | ||
| 14 | created_at: <%= 2.hours.ago.to_s(:db) %> | ||
| 15 | updated_at: | ||
| 16 | |||
| 17 | rails: | ||
| 18 | id: 3 | ||
| 19 | project_id: 1 | ||
| 20 | title: Rails is nice | ||
| 21 | subtitle: It makes me happy | ||
| 22 | content: except when I have to hack internals to fix pagination. even then really. | ||
| 23 | created_at: <%= 20.minutes.ago.to_s(:db) %> | ||
| 24 | |||
| 25 | ar: | ||
| 26 | id: 4 | ||
| 27 | project_id: 1 | ||
| 28 | title: ActiveRecord sometimes freaks me out | ||
| 29 | content: "I mean, what's the deal with eager loading?" | ||
| 30 | created_at: <%= 15.minutes.ago.to_s(:db) %> | ||
diff --git a/vendor/plugins/will_paginate/test/fixtures/user.rb b/vendor/plugins/will_paginate/test/fixtures/user.rb deleted file mode 100644 index 4a57cf0..0000000 --- a/vendor/plugins/will_paginate/test/fixtures/user.rb +++ /dev/null | |||
| @@ -1,2 +0,0 @@ | |||
| 1 | class User < ActiveRecord::Base | ||
| 2 | end | ||
diff --git a/vendor/plugins/will_paginate/test/fixtures/users.yml b/vendor/plugins/will_paginate/test/fixtures/users.yml deleted file mode 100644 index ed2c03a..0000000 --- a/vendor/plugins/will_paginate/test/fixtures/users.yml +++ /dev/null | |||
| @@ -1,35 +0,0 @@ | |||
| 1 | david: | ||
| 2 | id: 1 | ||
| 3 | name: David | ||
| 4 | salary: 80000 | ||
| 5 | type: Developer | ||
| 6 | |||
| 7 | jamis: | ||
| 8 | id: 2 | ||
| 9 | name: Jamis | ||
| 10 | salary: 150000 | ||
| 11 | type: Developer | ||
| 12 | |||
| 13 | <% for digit in 3..10 %> | ||
| 14 | dev_<%= digit %>: | ||
| 15 | id: <%= digit %> | ||
| 16 | name: fixture_<%= digit %> | ||
| 17 | salary: 100000 | ||
| 18 | type: Developer | ||
| 19 | <% end %> | ||
| 20 | |||
| 21 | poor_jamis: | ||
| 22 | id: 11 | ||
| 23 | name: Jamis | ||
| 24 | salary: 9000 | ||
| 25 | type: Developer | ||
| 26 | |||
| 27 | admin: | ||
| 28 | id: 12 | ||
| 29 | name: admin | ||
| 30 | type: Admin | ||
| 31 | |||
| 32 | goofy: | ||
| 33 | id: 13 | ||
| 34 | name: Goofy | ||
| 35 | type: Admin | ||
diff --git a/vendor/plugins/will_paginate/test/helper.rb b/vendor/plugins/will_paginate/test/helper.rb deleted file mode 100644 index ad52b1b..0000000 --- a/vendor/plugins/will_paginate/test/helper.rb +++ /dev/null | |||
| @@ -1,37 +0,0 @@ | |||
| 1 | require 'test/unit' | ||
| 2 | require 'rubygems' | ||
| 3 | |||
| 4 | # gem install redgreen for colored test output | ||
| 5 | begin require 'redgreen'; rescue LoadError; end | ||
| 6 | |||
| 7 | require 'boot' unless defined?(ActiveRecord) | ||
| 8 | |||
| 9 | class Test::Unit::TestCase | ||
| 10 | protected | ||
| 11 | def assert_respond_to_all object, methods | ||
| 12 | methods.each do |method| | ||
| 13 | [method.to_s, method.to_sym].each { |m| assert_respond_to object, m } | ||
| 14 | end | ||
| 15 | end | ||
| 16 | |||
| 17 | def collect_deprecations | ||
| 18 | old_behavior = WillPaginate::Deprecation.behavior | ||
| 19 | deprecations = [] | ||
| 20 | WillPaginate::Deprecation.behavior = Proc.new do |message, callstack| | ||
| 21 | deprecations << message | ||
| 22 | end | ||
| 23 | result = yield | ||
| 24 | [result, deprecations] | ||
| 25 | ensure | ||
| 26 | WillPaginate::Deprecation.behavior = old_behavior | ||
| 27 | end | ||
| 28 | end | ||
| 29 | |||
| 30 | # Wrap tests that use Mocha and skip if unavailable. | ||
| 31 | def uses_mocha(test_name) | ||
| 32 | require 'mocha' unless Object.const_defined?(:Mocha) | ||
| 33 | rescue LoadError => load_error | ||
| 34 | $stderr.puts "Skipping #{test_name} tests. `gem install mocha` and try again." | ||
| 35 | else | ||
| 36 | yield | ||
| 37 | end | ||
diff --git a/vendor/plugins/will_paginate/test/lib/activerecord_test_case.rb b/vendor/plugins/will_paginate/test/lib/activerecord_test_case.rb deleted file mode 100644 index 8f66ebe..0000000 --- a/vendor/plugins/will_paginate/test/lib/activerecord_test_case.rb +++ /dev/null | |||
| @@ -1,36 +0,0 @@ | |||
| 1 | require 'lib/activerecord_test_connector' | ||
| 2 | |||
| 3 | class ActiveRecordTestCase < Test::Unit::TestCase | ||
| 4 | # Set our fixture path | ||
| 5 | if ActiveRecordTestConnector.able_to_connect | ||
| 6 | self.fixture_path = File.join(File.dirname(__FILE__), '..', 'fixtures') | ||
| 7 | self.use_transactional_fixtures = true | ||
| 8 | end | ||
| 9 | |||
| 10 | def self.fixtures(*args) | ||
| 11 | super if ActiveRecordTestConnector.connected | ||
| 12 | end | ||
| 13 | |||
| 14 | def run(*args) | ||
| 15 | super if ActiveRecordTestConnector.connected | ||
| 16 | end | ||
| 17 | |||
| 18 | # Default so Test::Unit::TestCase doesn't complain | ||
| 19 | def test_truth | ||
| 20 | end | ||
| 21 | |||
| 22 | protected | ||
| 23 | |||
| 24 | def assert_queries(num = 1) | ||
| 25 | $query_count = 0 | ||
| 26 | yield | ||
| 27 | ensure | ||
| 28 | assert_equal num, $query_count, "#{$query_count} instead of #{num} queries were executed." | ||
| 29 | end | ||
| 30 | |||
| 31 | def assert_no_queries(&block) | ||
| 32 | assert_queries(0, &block) | ||
| 33 | end | ||
| 34 | end | ||
| 35 | |||
| 36 | ActiveRecordTestConnector.setup | ||
diff --git a/vendor/plugins/will_paginate/test/lib/activerecord_test_connector.rb b/vendor/plugins/will_paginate/test/lib/activerecord_test_connector.rb deleted file mode 100644 index 1130cf5..0000000 --- a/vendor/plugins/will_paginate/test/lib/activerecord_test_connector.rb +++ /dev/null | |||
| @@ -1,75 +0,0 @@ | |||
| 1 | require 'active_record' | ||
| 2 | require 'active_record/version' | ||
| 3 | require 'active_record/fixtures' | ||
| 4 | |||
| 5 | class ActiveRecordTestConnector | ||
| 6 | cattr_accessor :able_to_connect | ||
| 7 | cattr_accessor :connected | ||
| 8 | |||
| 9 | FIXTURES_PATH = File.join(File.dirname(__FILE__), '..', 'fixtures') | ||
| 10 | |||
| 11 | # Set our defaults | ||
| 12 | self.connected = false | ||
| 13 | self.able_to_connect = true | ||
| 14 | |||
| 15 | def self.setup | ||
| 16 | unless self.connected || !self.able_to_connect | ||
| 17 | setup_connection | ||
| 18 | load_schema | ||
| 19 | add_load_path FIXTURES_PATH | ||
| 20 | self.connected = true | ||
| 21 | end | ||
| 22 | rescue Exception => e # errors from ActiveRecord setup | ||
| 23 | $stderr.puts "\nSkipping ActiveRecord tests: #{e}\n\n" | ||
| 24 | self.able_to_connect = false | ||
| 25 | end | ||
| 26 | |||
| 27 | private | ||
| 28 | |||
| 29 | def self.add_load_path(path) | ||
| 30 | dep = defined?(ActiveSupport::Dependencies) ? ActiveSupport::Dependencies : ::Dependencies | ||
| 31 | dep.load_paths.unshift path | ||
| 32 | end | ||
| 33 | |||
| 34 | def self.setup_connection | ||
| 35 | db = ENV['DB'].blank?? 'sqlite3' : ENV['DB'] | ||
| 36 | |||
| 37 | configurations = YAML.load_file(File.join(File.dirname(__FILE__), '..', 'database.yml')) | ||
| 38 | raise "no configuration for '#{db}'" unless configurations.key? db | ||
| 39 | configuration = configurations[db] | ||
| 40 | |||
| 41 | ActiveRecord::Base.logger = Logger.new(STDOUT) if $0 == 'irb' | ||
| 42 | puts "using #{configuration['adapter']} adapter" unless ENV['DB'].blank? | ||
| 43 | |||
| 44 | gem 'sqlite3-ruby' if 'sqlite3' == db | ||
| 45 | |||
| 46 | ActiveRecord::Base.establish_connection(configuration) | ||
| 47 | ActiveRecord::Base.configurations = { db => configuration } | ||
| 48 | prepare ActiveRecord::Base.connection | ||
| 49 | |||
| 50 | unless Object.const_defined?(:QUOTED_TYPE) | ||
| 51 | Object.send :const_set, :QUOTED_TYPE, ActiveRecord::Base.connection.quote_column_name('type') | ||
| 52 | end | ||
| 53 | end | ||
| 54 | |||
| 55 | def self.load_schema | ||
| 56 | ActiveRecord::Base.silence do | ||
| 57 | ActiveRecord::Migration.verbose = false | ||
| 58 | load File.join(FIXTURES_PATH, 'schema.rb') | ||
| 59 | end | ||
| 60 | end | ||
| 61 | |||
| 62 | def self.prepare(conn) | ||
| 63 | class << conn | ||
| 64 | IGNORED_SQL = [/^PRAGMA/, /^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/, /^SELECT @@ROWCOUNT/, /^SHOW FIELDS /] | ||
| 65 | |||
| 66 | def execute_with_counting(sql, name = nil, &block) | ||
| 67 | $query_count ||= 0 | ||
| 68 | $query_count += 1 unless IGNORED_SQL.any? { |r| sql =~ r } | ||
| 69 | execute_without_counting(sql, name, &block) | ||
| 70 | end | ||
| 71 | |||
| 72 | alias_method_chain :execute, :counting | ||
| 73 | end | ||
| 74 | end | ||
| 75 | end | ||
diff --git a/vendor/plugins/will_paginate/test/lib/load_fixtures.rb b/vendor/plugins/will_paginate/test/lib/load_fixtures.rb deleted file mode 100644 index 10d6f42..0000000 --- a/vendor/plugins/will_paginate/test/lib/load_fixtures.rb +++ /dev/null | |||
| @@ -1,11 +0,0 @@ | |||
| 1 | require 'boot' | ||
| 2 | require 'lib/activerecord_test_connector' | ||
| 3 | |||
| 4 | # setup the connection | ||
| 5 | ActiveRecordTestConnector.setup | ||
| 6 | |||
| 7 | # load all fixtures | ||
| 8 | Fixtures.create_fixtures(ActiveRecordTestConnector::FIXTURES_PATH, ActiveRecord::Base.connection.tables) | ||
| 9 | |||
| 10 | require 'will_paginate' | ||
| 11 | WillPaginate.enable_activerecord | ||
diff --git a/vendor/plugins/will_paginate/test/lib/view_test_process.rb b/vendor/plugins/will_paginate/test/lib/view_test_process.rb deleted file mode 100644 index 508411e..0000000 --- a/vendor/plugins/will_paginate/test/lib/view_test_process.rb +++ /dev/null | |||
| @@ -1,171 +0,0 @@ | |||
| 1 | require 'action_controller' | ||
| 2 | require 'action_controller/test_process' | ||
| 3 | |||
| 4 | require 'will_paginate' | ||
| 5 | WillPaginate.enable_actionpack | ||
| 6 | |||
| 7 | ActionController::Routing::Routes.draw do |map| | ||
| 8 | map.connect 'dummy/page/:page', :controller => 'dummy' | ||
| 9 | map.connect 'dummy/dots/page.:page', :controller => 'dummy', :action => 'dots' | ||
| 10 | map.connect 'ibocorp/:page', :controller => 'ibocorp', | ||
| 11 | :requirements => { :page => /\d+/ }, | ||
| 12 | :defaults => { :page => 1 } | ||
| 13 | |||
| 14 | map.connect ':controller/:action/:id' | ||
| 15 | end | ||
| 16 | |||
| 17 | ActionController::Base.perform_caching = false | ||
| 18 | |||
| 19 | class WillPaginate::ViewTestCase < Test::Unit::TestCase | ||
| 20 | def setup | ||
| 21 | super | ||
| 22 | @controller = DummyController.new | ||
| 23 | @request = @controller.request | ||
| 24 | @html_result = nil | ||
| 25 | @template = '<%= will_paginate collection, options %>' | ||
| 26 | |||
| 27 | @view = ActionView::Base.new | ||
| 28 | @view.assigns['controller'] = @controller | ||
| 29 | @view.assigns['_request'] = @request | ||
| 30 | @view.assigns['_params'] = @request.params | ||
| 31 | end | ||
| 32 | |||
| 33 | def test_no_complain; end | ||
| 34 | |||
| 35 | protected | ||
| 36 | |||
| 37 | def paginate(collection = {}, options = {}, &block) | ||
| 38 | if collection.instance_of? Hash | ||
| 39 | page_options = { :page => 1, :total_entries => 11, :per_page => 4 }.merge(collection) | ||
| 40 | collection = [1].paginate(page_options) | ||
| 41 | end | ||
| 42 | |||
| 43 | locals = { :collection => collection, :options => options } | ||
| 44 | |||
| 45 | unless @view.respond_to? :render_template | ||
| 46 | # Rails 2.2 | ||
| 47 | @html_result = ActionView::InlineTemplate.new(@template).render(@view, locals) | ||
| 48 | else | ||
| 49 | if defined? ActionView::InlineTemplate | ||
| 50 | # Rails 2.1 | ||
| 51 | args = [ ActionView::InlineTemplate.new(@view, @template, locals) ] | ||
| 52 | else | ||
| 53 | # older Rails versions | ||
| 54 | args = [nil, @template, nil, locals] | ||
| 55 | end | ||
| 56 | |||
| 57 | @html_result = @view.render_template(*args) | ||
| 58 | end | ||
| 59 | |||
| 60 | @html_document = HTML::Document.new(@html_result, true, false) | ||
| 61 | |||
| 62 | if block_given? | ||
| 63 | classname = options[:class] || WillPaginate::ViewHelpers.pagination_options[:class] | ||
| 64 | assert_select("div.#{classname}", 1, 'no main DIV', &block) | ||
| 65 | end | ||
| 66 | end | ||
| 67 | |||
| 68 | def response_from_page_or_rjs | ||
| 69 | @html_document.root | ||
| 70 | end | ||
| 71 | |||
| 72 | def validate_page_numbers expected, links, param_name = :page | ||
| 73 | param_pattern = /\W#{CGI.escape(param_name.to_s)}=([^&]*)/ | ||
| 74 | |||
| 75 | assert_equal(expected, links.map { |e| | ||
| 76 | e['href'] =~ param_pattern | ||
| 77 | $1 ? $1.to_i : $1 | ||
| 78 | }) | ||
| 79 | end | ||
| 80 | |||
| 81 | def assert_links_match pattern, links = nil, numbers = nil | ||
| 82 | links ||= assert_select 'div.pagination a[href]' do |elements| | ||
| 83 | elements | ||
| 84 | end | ||
| 85 | |||
| 86 | pages = [] if numbers | ||
| 87 | |||
| 88 | links.each do |el| | ||
| 89 | assert_match pattern, el['href'] | ||
| 90 | if numbers | ||
| 91 | el['href'] =~ pattern | ||
| 92 | pages << ($1.nil?? nil : $1.to_i) | ||
| 93 | end | ||
| 94 | end | ||
| 95 | |||
| 96 | assert_equal numbers, pages, "page numbers don't match" if numbers | ||
| 97 | end | ||
| 98 | |||
| 99 | def assert_no_links_match pattern | ||
| 100 | assert_select 'div.pagination a[href]' do |elements| | ||
| 101 | elements.each do |el| | ||
| 102 | assert_no_match pattern, el['href'] | ||
| 103 | end | ||
| 104 | end | ||
| 105 | end | ||
| 106 | end | ||
| 107 | |||
| 108 | class DummyRequest | ||
| 109 | attr_accessor :symbolized_path_parameters | ||
| 110 | |||
| 111 | def initialize | ||
| 112 | @get = true | ||
| 113 | @params = {} | ||
| 114 | @symbolized_path_parameters = { :controller => 'foo', :action => 'bar' } | ||
| 115 | end | ||
| 116 | |||
| 117 | def get? | ||
| 118 | @get | ||
| 119 | end | ||
| 120 | |||
| 121 | def post | ||
| 122 | @get = false | ||
| 123 | end | ||
| 124 | |||
| 125 | def relative_url_root | ||
| 126 | '' | ||
| 127 | end | ||
| 128 | |||
| 129 | def params(more = nil) | ||
| 130 | @params.update(more) if more | ||
| 131 | @params | ||
| 132 | end | ||
| 133 | end | ||
| 134 | |||
| 135 | class DummyController | ||
| 136 | attr_reader :request | ||
| 137 | attr_accessor :controller_name | ||
| 138 | |||
| 139 | def initialize | ||
| 140 | @request = DummyRequest.new | ||
| 141 | @url = ActionController::UrlRewriter.new(@request, @request.params) | ||
| 142 | end | ||
| 143 | |||
| 144 | def params | ||
| 145 | @request.params | ||
| 146 | end | ||
| 147 | |||
| 148 | def url_for(params) | ||
| 149 | @url.rewrite(params) | ||
| 150 | end | ||
| 151 | end | ||
| 152 | |||
| 153 | module HTML | ||
| 154 | Node.class_eval do | ||
| 155 | def inner_text | ||
| 156 | children.map(&:inner_text).join('') | ||
| 157 | end | ||
| 158 | end | ||
| 159 | |||
| 160 | Text.class_eval do | ||
| 161 | def inner_text | ||
| 162 | self.to_s | ||
| 163 | end | ||
| 164 | end | ||
| 165 | |||
| 166 | Tag.class_eval do | ||
| 167 | def inner_text | ||
| 168 | childless?? '' : super | ||
| 169 | end | ||
| 170 | end | ||
| 171 | end | ||
diff --git a/vendor/plugins/will_paginate/test/tasks.rake b/vendor/plugins/will_paginate/test/tasks.rake deleted file mode 100644 index 59f2f94..0000000 --- a/vendor/plugins/will_paginate/test/tasks.rake +++ /dev/null | |||
| @@ -1,59 +0,0 @@ | |||
| 1 | require 'rake/testtask' | ||
| 2 | |||
| 3 | desc 'Test the will_paginate plugin.' | ||
| 4 | Rake::TestTask.new(:test) do |t| | ||
| 5 | t.pattern = 'test/**/*_test.rb' | ||
| 6 | t.verbose = true | ||
| 7 | t.libs << 'test' | ||
| 8 | end | ||
| 9 | |||
| 10 | # I want to specify environment variables at call time | ||
| 11 | class EnvTestTask < Rake::TestTask | ||
| 12 | attr_accessor :env | ||
| 13 | |||
| 14 | def ruby(*args) | ||
| 15 | env.each { |key, value| ENV[key] = value } if env | ||
| 16 | super | ||
| 17 | env.keys.each { |key| ENV.delete key } if env | ||
| 18 | end | ||
| 19 | end | ||
| 20 | |||
| 21 | for configuration in %w( sqlite3 mysql postgres ) | ||
| 22 | EnvTestTask.new("test_#{configuration}") do |t| | ||
| 23 | t.pattern = 'test/finder_test.rb' | ||
| 24 | t.verbose = true | ||
| 25 | t.env = { 'DB' => configuration } | ||
| 26 | t.libs << 'test' | ||
| 27 | end | ||
| 28 | end | ||
| 29 | |||
| 30 | task :test_databases => %w(test_mysql test_sqlite3 test_postgres) | ||
| 31 | |||
| 32 | desc %{Test everything on SQLite3, MySQL and PostgreSQL} | ||
| 33 | task :test_full => %w(test test_mysql test_postgres) | ||
| 34 | |||
| 35 | desc %{Test everything with Rails 2.1.x, 2.0.x & 1.2.x gems} | ||
| 36 | task :test_all do | ||
| 37 | all = Rake::Task['test_full'] | ||
| 38 | versions = %w(2.1.0 2.0.4 1.2.6) | ||
| 39 | versions.each do |version| | ||
| 40 | ENV['RAILS_VERSION'] = "~> #{version}" | ||
| 41 | all.invoke | ||
| 42 | reset_invoked unless version == versions.last | ||
| 43 | end | ||
| 44 | end | ||
| 45 | |||
| 46 | def reset_invoked | ||
| 47 | %w( test_full test test_mysql test_postgres ).each do |name| | ||
| 48 | Rake::Task[name].instance_variable_set '@already_invoked', false | ||
| 49 | end | ||
| 50 | end | ||
| 51 | |||
| 52 | task :rcov do | ||
| 53 | excludes = %w( lib/will_paginate/named_scope* | ||
| 54 | lib/will_paginate/core_ext.rb | ||
| 55 | lib/will_paginate.rb | ||
| 56 | rails* ) | ||
| 57 | |||
| 58 | system %[rcov -Itest:lib test/*.rb -x #{excludes.join(',')}] | ||
| 59 | end | ||
diff --git a/vendor/plugins/will_paginate/test/view_test.rb b/vendor/plugins/will_paginate/test/view_test.rb deleted file mode 100644 index 3ada457..0000000 --- a/vendor/plugins/will_paginate/test/view_test.rb +++ /dev/null | |||
| @@ -1,365 +0,0 @@ | |||
| 1 | require 'helper' | ||
| 2 | require 'lib/view_test_process' | ||
| 3 | |||
| 4 | class AdditionalLinkAttributesRenderer < WillPaginate::LinkRenderer | ||
| 5 | def initialize(link_attributes = nil) | ||
| 6 | super() | ||
| 7 | @additional_link_attributes = link_attributes || { :default => 'true' } | ||
| 8 | end | ||
| 9 | |||
| 10 | def page_link(page, text, attributes = {}) | ||
| 11 | @template.link_to text, url_for(page), attributes.merge(@additional_link_attributes) | ||
| 12 | end | ||
| 13 | end | ||
| 14 | |||
| 15 | class ViewTest < WillPaginate::ViewTestCase | ||
| 16 | |||
| 17 | ## basic pagination ## | ||
| 18 | |||
| 19 | def test_will_paginate | ||
| 20 | paginate do |pagination| | ||
| 21 | assert_select 'a[href]', 3 do |elements| | ||
| 22 | validate_page_numbers [2,3,2], elements | ||
| 23 | assert_select elements.last, ':last-child', "Next »" | ||
| 24 | end | ||
| 25 | assert_select 'span', 2 | ||
| 26 | assert_select 'span.disabled:first-child', '« Previous' | ||
| 27 | assert_select 'span.current', '1' | ||
| 28 | assert_equal '« Previous 1 2 3 Next »', pagination.first.inner_text | ||
| 29 | end | ||
| 30 | end | ||
| 31 | |||
| 32 | def test_no_pagination_when_page_count_is_one | ||
| 33 | paginate :per_page => 30 | ||
| 34 | assert_equal '', @html_result | ||
| 35 | end | ||
| 36 | |||
| 37 | def test_will_paginate_with_options | ||
| 38 | paginate({ :page => 2 }, | ||
| 39 | :class => 'will_paginate', :previous_label => 'Prev', :next_label => 'Next') do | ||
| 40 | assert_select 'a[href]', 4 do |elements| | ||
| 41 | validate_page_numbers [1,1,3,3], elements | ||
| 42 | # test rel attribute values: | ||
| 43 | assert_select elements[1], 'a', '1' do |link| | ||
| 44 | assert_equal 'prev start', link.first['rel'] | ||
| 45 | end | ||
| 46 | assert_select elements.first, 'a', "Prev" do |link| | ||
| 47 | assert_equal 'prev start', link.first['rel'] | ||
| 48 | end | ||
| 49 | assert_select elements.last, 'a', "Next" do |link| | ||
| 50 | assert_equal 'next', link.first['rel'] | ||
| 51 | end | ||
| 52 | end | ||
| 53 | assert_select 'span.current', '2' | ||
| 54 | end | ||
| 55 | end | ||
| 56 | |||
| 57 | def test_will_paginate_using_renderer_class | ||
| 58 | paginate({}, :renderer => AdditionalLinkAttributesRenderer) do | ||
| 59 | assert_select 'a[default=true]', 3 | ||
| 60 | end | ||
| 61 | end | ||
| 62 | |||
| 63 | def test_will_paginate_using_renderer_instance | ||
| 64 | renderer = WillPaginate::LinkRenderer.new | ||
| 65 | renderer.gap_marker = '<span class="my-gap">~~</span>' | ||
| 66 | |||
| 67 | paginate({ :per_page => 2 }, :inner_window => 0, :outer_window => 0, :renderer => renderer) do | ||
| 68 | assert_select 'span.my-gap', '~~' | ||
| 69 | end | ||
| 70 | |||
| 71 | renderer = AdditionalLinkAttributesRenderer.new(:title => 'rendered') | ||
| 72 | paginate({}, :renderer => renderer) do | ||
| 73 | assert_select 'a[title=rendered]', 3 | ||
| 74 | end | ||
| 75 | end | ||
| 76 | |||
| 77 | def test_prev_next_links_have_classnames | ||
| 78 | paginate do |pagination| | ||
| 79 | assert_select 'span.disabled.prev_page:first-child' | ||
| 80 | assert_select 'a.next_page[href]:last-child' | ||
| 81 | end | ||
| 82 | end | ||
| 83 | |||
| 84 | def test_prev_label_deprecated | ||
| 85 | assert_deprecated ':previous_label' do | ||
| 86 | paginate({ :page => 2 }, :prev_label => 'Deprecated') do | ||
| 87 | assert_select 'a[href]:first-child', 'Deprecated' | ||
| 88 | end | ||
| 89 | end | ||
| 90 | end | ||
| 91 | |||
| 92 | def test_full_output | ||
| 93 | paginate | ||
| 94 | expected = <<-HTML | ||
| 95 | <div class="pagination"><span class="disabled prev_page">« Previous</span> | ||
| 96 | <span class="current">1</span> | ||
| 97 | <a href="/foo/bar?page=2" rel="next">2</a> | ||
| 98 | <a href="/foo/bar?page=3">3</a> | ||
| 99 | <a href="/foo/bar?page=2" class="next_page" rel="next">Next »</a></div> | ||
| 100 | HTML | ||
| 101 | expected.strip!.gsub!(/\s{2,}/, ' ') | ||
| 102 | |||
| 103 | assert_dom_equal expected, @html_result | ||
| 104 | end | ||
| 105 | |||
| 106 | def test_escaping_of_urls | ||
| 107 | paginate({:page => 1, :per_page => 1, :total_entries => 2}, | ||
| 108 | :page_links => false, :params => { :tag => '<br>' }) | ||
| 109 | |||
| 110 | assert_select 'a[href]', 1 do |links| | ||
| 111 | query = links.first['href'].split('?', 2)[1] | ||
| 112 | assert_equal %w(page=2 tag=%3Cbr%3E), query.split('&').sort | ||
| 113 | end | ||
| 114 | end | ||
| 115 | |||
| 116 | ## advanced options for pagination ## | ||
| 117 | |||
| 118 | def test_will_paginate_without_container | ||
| 119 | paginate({}, :container => false) | ||
| 120 | assert_select 'div.pagination', 0, 'main DIV present when it shouldn\'t' | ||
| 121 | assert_select 'a[href]', 3 | ||
| 122 | end | ||
| 123 | |||
| 124 | def test_will_paginate_without_page_links | ||
| 125 | paginate({ :page => 2 }, :page_links => false) do | ||
| 126 | assert_select 'a[href]', 2 do |elements| | ||
| 127 | validate_page_numbers [1,3], elements | ||
| 128 | end | ||
| 129 | end | ||
| 130 | end | ||
| 131 | |||
| 132 | def test_will_paginate_windows | ||
| 133 | paginate({ :page => 6, :per_page => 1 }, :inner_window => 1) do |pagination| | ||
| 134 | assert_select 'a[href]', 8 do |elements| | ||
| 135 | validate_page_numbers [5,1,2,5,7,10,11,7], elements | ||
| 136 | assert_select elements.first, 'a', '« Previous' | ||
| 137 | assert_select elements.last, 'a', 'Next »' | ||
| 138 | end | ||
| 139 | assert_select 'span.current', '6' | ||
| 140 | assert_equal '« Previous 1 2 … 5 6 7 … 10 11 Next »', pagination.first.inner_text | ||
| 141 | end | ||
| 142 | end | ||
| 143 | |||
| 144 | def test_will_paginate_eliminates_small_gaps | ||
| 145 | paginate({ :page => 6, :per_page => 1 }, :inner_window => 2) do | ||
| 146 | assert_select 'a[href]', 12 do |elements| | ||
| 147 | validate_page_numbers [5,1,2,3,4,5,7,8,9,10,11,7], elements | ||
| 148 | end | ||
| 149 | end | ||
| 150 | end | ||
| 151 | |||
| 152 | def test_container_id | ||
| 153 | paginate do |div| | ||
| 154 | assert_nil div.first['id'] | ||
| 155 | end | ||
| 156 | |||
| 157 | # magic ID | ||
| 158 | paginate({}, :id => true) do |div| | ||
| 159 | assert_equal 'fixnums_pagination', div.first['id'] | ||
| 160 | end | ||
| 161 | |||
| 162 | # explicit ID | ||
| 163 | paginate({}, :id => 'custom_id') do |div| | ||
| 164 | assert_equal 'custom_id', div.first['id'] | ||
| 165 | end | ||
| 166 | end | ||
| 167 | |||
| 168 | ## other helpers ## | ||
| 169 | |||
| 170 | def test_paginated_section | ||
| 171 | @template = <<-ERB | ||
| 172 | <% paginated_section collection, options do %> | ||
| 173 | <%= content_tag :div, '', :id => "developers" %> | ||
| 174 | <% end %> | ||
| 175 | ERB | ||
| 176 | |||
| 177 | paginate | ||
| 178 | assert_select 'div.pagination', 2 | ||
| 179 | assert_select 'div.pagination + div#developers', 1 | ||
| 180 | end | ||
| 181 | |||
| 182 | def test_page_entries_info | ||
| 183 | @template = '<%= page_entries_info collection %>' | ||
| 184 | array = ('a'..'z').to_a | ||
| 185 | |||
| 186 | paginate array.paginate(:page => 2, :per_page => 5) | ||
| 187 | assert_equal %{Displaying strings <b>6 - 10</b> of <b>26</b> in total}, | ||
| 188 | @html_result | ||
| 189 | |||
| 190 | paginate array.paginate(:page => 7, :per_page => 4) | ||
| 191 | assert_equal %{Displaying strings <b>25 - 26</b> of <b>26</b> in total}, | ||
| 192 | @html_result | ||
| 193 | end | ||
| 194 | |||
| 195 | uses_mocha 'class name' do | ||
| 196 | def test_page_entries_info_with_longer_class_name | ||
| 197 | @template = '<%= page_entries_info collection %>' | ||
| 198 | collection = ('a'..'z').to_a.paginate | ||
| 199 | collection.first.stubs(:class).returns(mock('class', :name => 'ProjectType')) | ||
| 200 | |||
| 201 | paginate collection | ||
| 202 | assert @html_result.index('project types'), "expected <#{@html_result.inspect}> to mention 'project types'" | ||
| 203 | end | ||
| 204 | end | ||
| 205 | |||
| 206 | def test_page_entries_info_with_single_page_collection | ||
| 207 | @template = '<%= page_entries_info collection %>' | ||
| 208 | |||
| 209 | paginate(('a'..'d').to_a.paginate(:page => 1, :per_page => 5)) | ||
| 210 | assert_equal %{Displaying <b>all 4</b> strings}, @html_result | ||
| 211 | |||
| 212 | paginate(['a'].paginate(:page => 1, :per_page => 5)) | ||
| 213 | assert_equal %{Displaying <b>1</b> string}, @html_result | ||
| 214 | |||
| 215 | paginate([].paginate(:page => 1, :per_page => 5)) | ||
| 216 | assert_equal %{No entries found}, @html_result | ||
| 217 | end | ||
| 218 | |||
| 219 | def test_page_entries_info_with_custom_entry_name | ||
| 220 | @template = '<%= page_entries_info collection, :entry_name => "author" %>' | ||
| 221 | |||
| 222 | entries = (1..20).to_a | ||
| 223 | |||
| 224 | paginate(entries.paginate(:page => 1, :per_page => 5)) | ||
| 225 | assert_equal %{Displaying authors <b>1 - 5</b> of <b>20</b> in total}, @html_result | ||
| 226 | |||
| 227 | paginate(entries.paginate(:page => 1, :per_page => 20)) | ||
| 228 | assert_equal %{Displaying <b>all 20</b> authors}, @html_result | ||
| 229 | |||
| 230 | paginate(['a'].paginate(:page => 1, :per_page => 5)) | ||
| 231 | assert_equal %{Displaying <b>1</b> author}, @html_result | ||
| 232 | |||
| 233 | paginate([].paginate(:page => 1, :per_page => 5)) | ||
| 234 | assert_equal %{No authors found}, @html_result | ||
| 235 | end | ||
| 236 | |||
| 237 | ## parameter handling in page links ## | ||
| 238 | |||
| 239 | def test_will_paginate_preserves_parameters_on_get | ||
| 240 | @request.params :foo => { :bar => 'baz' } | ||
| 241 | paginate | ||
| 242 | assert_links_match /foo%5Bbar%5D=baz/ | ||
| 243 | end | ||
| 244 | |||
| 245 | def test_will_paginate_doesnt_preserve_parameters_on_post | ||
| 246 | @request.post | ||
| 247 | @request.params :foo => 'bar' | ||
| 248 | paginate | ||
| 249 | assert_no_links_match /foo=bar/ | ||
| 250 | end | ||
| 251 | |||
| 252 | def test_adding_additional_parameters | ||
| 253 | paginate({}, :params => { :foo => 'bar' }) | ||
| 254 | assert_links_match /foo=bar/ | ||
| 255 | end | ||
| 256 | |||
| 257 | def test_adding_anchor_parameter | ||
| 258 | paginate({}, :params => { :anchor => 'anchor' }) | ||
| 259 | assert_links_match /#anchor$/ | ||
| 260 | end | ||
| 261 | |||
| 262 | def test_removing_arbitrary_parameters | ||
| 263 | @request.params :foo => 'bar' | ||
| 264 | paginate({}, :params => { :foo => nil }) | ||
| 265 | assert_no_links_match /foo=bar/ | ||
| 266 | end | ||
| 267 | |||
| 268 | def test_adding_additional_route_parameters | ||
| 269 | paginate({}, :params => { :controller => 'baz', :action => 'list' }) | ||
| 270 | assert_links_match %r{\Wbaz/list\W} | ||
| 271 | end | ||
| 272 | |||
| 273 | def test_will_paginate_with_custom_page_param | ||
| 274 | paginate({ :page => 2 }, :param_name => :developers_page) do | ||
| 275 | assert_select 'a[href]', 4 do |elements| | ||
| 276 | validate_page_numbers [1,1,3,3], elements, :developers_page | ||
| 277 | end | ||
| 278 | end | ||
| 279 | end | ||
| 280 | |||
| 281 | def test_complex_custom_page_param | ||
| 282 | @request.params :developers => { :page => 2 } | ||
| 283 | |||
| 284 | paginate({ :page => 2 }, :param_name => 'developers[page]') do | ||
| 285 | assert_select 'a[href]', 4 do |links| | ||
| 286 | assert_links_match /\?developers%5Bpage%5D=\d+$/, links | ||
| 287 | validate_page_numbers [1,1,3,3], links, 'developers[page]' | ||
| 288 | end | ||
| 289 | end | ||
| 290 | end | ||
| 291 | |||
| 292 | def test_custom_routing_page_param | ||
| 293 | @request.symbolized_path_parameters.update :controller => 'dummy', :action => nil | ||
| 294 | paginate :per_page => 2 do | ||
| 295 | assert_select 'a[href]', 6 do |links| | ||
| 296 | assert_links_match %r{/page/(\d+)$}, links, [2, 3, 4, 5, 6, 2] | ||
| 297 | end | ||
| 298 | end | ||
| 299 | end | ||
| 300 | |||
| 301 | def test_custom_routing_page_param_with_dot_separator | ||
| 302 | @request.symbolized_path_parameters.update :controller => 'dummy', :action => 'dots' | ||
| 303 | paginate :per_page => 2 do | ||
| 304 | assert_select 'a[href]', 6 do |links| | ||
| 305 | assert_links_match %r{/page\.(\d+)$}, links, [2, 3, 4, 5, 6, 2] | ||
| 306 | end | ||
| 307 | end | ||
| 308 | end | ||
| 309 | |||
| 310 | def test_custom_routing_with_first_page_hidden | ||
| 311 | @request.symbolized_path_parameters.update :controller => 'ibocorp', :action => nil | ||
| 312 | paginate :page => 2, :per_page => 2 do | ||
| 313 | assert_select 'a[href]', 7 do |links| | ||
| 314 | assert_links_match %r{/ibocorp(?:/(\d+))?$}, links, [nil, nil, 3, 4, 5, 6, 3] | ||
| 315 | end | ||
| 316 | end | ||
| 317 | end | ||
| 318 | |||
| 319 | ## internal hardcore stuff ## | ||
| 320 | |||
| 321 | class LegacyCollection < WillPaginate::Collection | ||
| 322 | alias :page_count :total_pages | ||
| 323 | undef :total_pages | ||
| 324 | end | ||
| 325 | |||
| 326 | def test_deprecation_notices_with_page_count | ||
| 327 | collection = LegacyCollection.new(1, 1, 2) | ||
| 328 | |||
| 329 | assert_deprecated collection.class.name do | ||
| 330 | paginate collection | ||
| 331 | end | ||
| 332 | end | ||
| 333 | |||
| 334 | uses_mocha 'view internals' do | ||
| 335 | def test_collection_name_can_be_guessed | ||
| 336 | collection = mock | ||
| 337 | collection.expects(:total_pages).returns(1) | ||
| 338 | |||
| 339 | @template = '<%= will_paginate options %>' | ||
| 340 | @controller.controller_name = 'developers' | ||
| 341 | @view.assigns['developers'] = collection | ||
| 342 | |||
| 343 | paginate(nil) | ||
| 344 | end | ||
| 345 | end | ||
| 346 | |||
| 347 | def test_inferred_collection_name_raises_error_when_nil | ||
| 348 | @template = '<%= will_paginate options %>' | ||
| 349 | @controller.controller_name = 'developers' | ||
| 350 | |||
| 351 | e = assert_raise ArgumentError do | ||
| 352 | paginate(nil) | ||
| 353 | end | ||
| 354 | assert e.message.include?('@developers') | ||
| 355 | end | ||
| 356 | |||
| 357 | if ActionController::Base.respond_to? :rescue_responses | ||
| 358 | # only on Rails 2 | ||
| 359 | def test_rescue_response_hook_presence | ||
| 360 | assert_equal :not_found, | ||
| 361 | ActionController::Base.rescue_responses['WillPaginate::InvalidPage'] | ||
| 362 | end | ||
| 363 | end | ||
| 364 | |||
| 365 | end | ||
diff --git a/vendor/plugins/will_paginate/will_paginate.gemspec b/vendor/plugins/will_paginate/will_paginate.gemspec deleted file mode 100644 index 1072c3a..0000000 --- a/vendor/plugins/will_paginate/will_paginate.gemspec +++ /dev/null | |||
| @@ -1,20 +0,0 @@ | |||
| 1 | Gem::Specification.new do |s| | ||
| 2 | s.name = 'will_paginate' | ||
| 3 | s.version = '2.3.7' | ||
| 4 | s.date = '2009-02-10' | ||
| 5 | |||
| 6 | s.summary = "Most awesome pagination solution for Rails" | ||
| 7 | s.description = "The will_paginate library provides a simple, yet powerful and extensible API for ActiveRecord pagination and rendering of pagination links in ActionView templates." | ||
| 8 | |||
| 9 | s.authors = ['Mislav Marohnić', 'PJ Hyett'] | ||
| 10 | s.email = 'mislav.marohnic@gmail.com' | ||
| 11 | s.homepage = 'http://github.com/mislav/will_paginate/wikis' | ||
| 12 | |||
| 13 | s.has_rdoc = true | ||
| 14 | s.rdoc_options = ['--main', 'README.rdoc'] | ||
| 15 | s.rdoc_options << '--inline-source' << '--charset=UTF-8' | ||
| 16 | s.extra_rdoc_files = ['README.rdoc', 'LICENSE', 'CHANGELOG.rdoc'] | ||
| 17 | |||
| 18 | s.files = %w(CHANGELOG.rdoc LICENSE README.rdoc Rakefile examples examples/apple-circle.gif examples/index.haml examples/index.html examples/pagination.css examples/pagination.sass init.rb lib lib/will_paginate lib/will_paginate.rb lib/will_paginate/array.rb lib/will_paginate/collection.rb lib/will_paginate/core_ext.rb lib/will_paginate/finder.rb lib/will_paginate/named_scope.rb lib/will_paginate/named_scope_patch.rb lib/will_paginate/version.rb lib/will_paginate/view_helpers.rb test test/boot.rb test/collection_test.rb test/console test/database.yml test/finder_test.rb test/fixtures test/fixtures/admin.rb test/fixtures/developer.rb test/fixtures/developers_projects.yml test/fixtures/project.rb test/fixtures/projects.yml test/fixtures/replies.yml test/fixtures/reply.rb test/fixtures/schema.rb test/fixtures/topic.rb test/fixtures/topics.yml test/fixtures/user.rb test/fixtures/users.yml test/helper.rb test/lib test/lib/activerecord_test_case.rb test/lib/activerecord_test_connector.rb test/lib/load_fixtures.rb test/lib/view_test_process.rb test/tasks.rake test/view_test.rb) | ||
| 19 | s.test_files = %w(test/boot.rb test/collection_test.rb test/console test/database.yml test/finder_test.rb test/fixtures test/fixtures/admin.rb test/fixtures/developer.rb test/fixtures/developers_projects.yml test/fixtures/project.rb test/fixtures/projects.yml test/fixtures/replies.yml test/fixtures/reply.rb test/fixtures/schema.rb test/fixtures/topic.rb test/fixtures/topics.yml test/fixtures/user.rb test/fixtures/users.yml test/helper.rb test/lib test/lib/activerecord_test_case.rb test/lib/activerecord_test_connector.rb test/lib/load_fixtures.rb test/lib/view_test_process.rb test/tasks.rake test/view_test.rb) | ||
| 20 | end | ||
