aslakjo-comatose 2.0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. data/CHANGELOG +195 -0
  2. data/INSTALL +20 -0
  3. data/LICENSE +20 -0
  4. data/MANIFEST +91 -0
  5. data/README.markdown +159 -0
  6. data/Rakefile +176 -0
  7. data/SPECS +61 -0
  8. data/about.yml +7 -0
  9. data/bin/comatose +112 -0
  10. data/comatose.gemspec +113 -0
  11. data/generators/comatose_migration/USAGE +15 -0
  12. data/generators/comatose_migration/comatose_migration_generator.rb +74 -0
  13. data/generators/comatose_migration/templates/migration.rb +35 -0
  14. data/generators/comatose_migration/templates/v4_upgrade.rb +15 -0
  15. data/generators/comatose_migration/templates/v6_upgrade.rb +23 -0
  16. data/generators/comatose_migration/templates/v7_upgrade.rb +22 -0
  17. data/init.rb +2 -0
  18. data/install.rb +18 -0
  19. data/lib/acts_as_versioned.rb +543 -0
  20. data/lib/comatose/comatose_drop.rb +79 -0
  21. data/lib/comatose/configuration.rb +69 -0
  22. data/lib/comatose/page_wrapper.rb +119 -0
  23. data/lib/comatose/processing_context.rb +69 -0
  24. data/lib/comatose/tasks/admin.rb +60 -0
  25. data/lib/comatose/tasks/data.rb +82 -0
  26. data/lib/comatose/tasks/setup.rb +52 -0
  27. data/lib/comatose/version.rb +4 -0
  28. data/lib/comatose.rb +33 -0
  29. data/lib/comatose_admin_controller.rb +395 -0
  30. data/lib/comatose_admin_helper.rb +37 -0
  31. data/lib/comatose_controller.rb +138 -0
  32. data/lib/comatose_helper.rb +3 -0
  33. data/lib/comatose_page.rb +141 -0
  34. data/lib/liquid/block.rb +96 -0
  35. data/lib/liquid/context.rb +190 -0
  36. data/lib/liquid/document.rb +17 -0
  37. data/lib/liquid/drop.rb +48 -0
  38. data/lib/liquid/errors.rb +7 -0
  39. data/lib/liquid/extensions.rb +53 -0
  40. data/lib/liquid/file_system.rb +62 -0
  41. data/lib/liquid/htmltags.rb +64 -0
  42. data/lib/liquid/standardfilters.rb +111 -0
  43. data/lib/liquid/standardtags.rb +399 -0
  44. data/lib/liquid/strainer.rb +42 -0
  45. data/lib/liquid/tag.rb +25 -0
  46. data/lib/liquid/template.rb +88 -0
  47. data/lib/liquid/variable.rb +39 -0
  48. data/lib/liquid.rb +52 -0
  49. data/lib/redcloth.rb +1129 -0
  50. data/lib/support/class_options.rb +36 -0
  51. data/lib/support/inline_rendering.rb +48 -0
  52. data/lib/support/route_mapper.rb +50 -0
  53. data/lib/text_filters/markdown.rb +14 -0
  54. data/lib/text_filters/markdown_smartypants.rb +15 -0
  55. data/lib/text_filters/none.rb +8 -0
  56. data/lib/text_filters/rdoc.rb +13 -0
  57. data/lib/text_filters/simple.rb +8 -0
  58. data/lib/text_filters/textile.rb +15 -0
  59. data/lib/text_filters.rb +140 -0
  60. data/rails/init.rb +3 -0
  61. data/resources/layouts/comatose_admin_template.html.erb +28 -0
  62. data/resources/public/images/collapsed.gif +0 -0
  63. data/resources/public/images/expanded.gif +0 -0
  64. data/resources/public/images/no-children.gif +0 -0
  65. data/resources/public/images/page.gif +0 -0
  66. data/resources/public/images/spinner.gif +0 -0
  67. data/resources/public/images/title-hover-bg.gif +0 -0
  68. data/resources/public/javascripts/comatose_admin.js +401 -0
  69. data/resources/public/stylesheets/comatose_admin.css +404 -0
  70. data/tasks/comatose.rake +9 -0
  71. data/test/behaviors.rb +106 -0
  72. data/test/fixtures/comatose_pages.yml +96 -0
  73. data/test/functional/comatose_admin_controller_test.rb +114 -0
  74. data/test/functional/comatose_controller_test.rb +44 -0
  75. data/test/javascripts/test.html +26 -0
  76. data/test/javascripts/test_runner.js +307 -0
  77. data/test/test_helper.rb +55 -0
  78. data/test/unit/class_options_test.rb +52 -0
  79. data/test/unit/comatose_page_test.rb +136 -0
  80. data/test/unit/processing_context_test.rb +108 -0
  81. data/test/unit/text_filters_test.rb +52 -0
  82. data/views/comatose_admin/_form.html.erb +96 -0
  83. data/views/comatose_admin/_page_list_item.html.erb +60 -0
  84. data/views/comatose_admin/delete.html.erb +18 -0
  85. data/views/comatose_admin/edit.html.erb +5 -0
  86. data/views/comatose_admin/index.html.erb +29 -0
  87. data/views/comatose_admin/new.html.erb +5 -0
  88. data/views/comatose_admin/reorder.html.erb +30 -0
  89. data/views/comatose_admin/versions.html.erb +40 -0
  90. data/views/layouts/comatose_admin.html.erb +837 -0
  91. data/views/layouts/comatose_admin_customize.html.erb +28 -0
  92. data/views/layouts/comatose_content.html.erb +17 -0
  93. metadata +148 -0
@@ -0,0 +1,543 @@
1
+ # Copyright (c) 2005 Rick Olson
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.
21
+
22
+ # Updated with: http://github.com/codafoo/acts_as_versioned/tree/master/lib
23
+
24
+ module ActiveRecord #:nodoc:
25
+ module Acts #:nodoc:
26
+ # Specify this act if you want to save a copy of the row in a versioned table. This assumes there is a
27
+ # versioned table ready and that your model has a version field. This works with optimistic locking if the lock_version
28
+ # column is present as well.
29
+ #
30
+ # The class for the versioned model is derived the first time it is seen. Therefore, if you change your database schema you have to restart
31
+ # your container for the changes to be reflected. In development mode this usually means restarting WEBrick.
32
+ #
33
+ # class Page < ActiveRecord::Base
34
+ # # assumes pages_versions table
35
+ # acts_as_versioned
36
+ # end
37
+ #
38
+ # Example:
39
+ #
40
+ # page = Page.create(:title => 'hello world!')
41
+ # page.version # => 1
42
+ #
43
+ # page.title = 'hello world'
44
+ # page.save
45
+ # page.version # => 2
46
+ # page.versions.size # => 2
47
+ #
48
+ # page.revert_to(1) # using version number
49
+ # page.title # => 'hello world!'
50
+ #
51
+ # page.revert_to(page.versions.last) # using versioned instance
52
+ # page.title # => 'hello world'
53
+ #
54
+ # page.versions.earliest # efficient query to find the first version
55
+ # page.versions.latest # efficient query to find the most recently created version
56
+ #
57
+ #
58
+ # Simple Queries to page between versions
59
+ #
60
+ # page.versions.before(version)
61
+ # page.versions.after(version)
62
+ #
63
+ # Access the previous/next versions from the versioned model itself
64
+ #
65
+ # version = page.versions.latest
66
+ # version.previous # go back one version
67
+ # version.next # go forward one version
68
+ #
69
+ # See ActiveRecord::Acts::Versioned::ClassMethods#acts_as_versioned for configuration options
70
+ module Versioned
71
+ CALLBACKS = [:set_new_version, :save_version_on_create, :save_version?]
72
+ def self.included(base) # :nodoc:
73
+ base.extend ClassMethods
74
+ end
75
+
76
+ module ClassMethods
77
+ # == Configuration options
78
+ #
79
+ # * <tt>class_name</tt> - versioned model class name (default: PageVersion in the above example)
80
+ # * <tt>table_name</tt> - versioned model table name (default: page_versions in the above example)
81
+ # * <tt>foreign_key</tt> - foreign key used to relate the versioned model to the original model (default: page_id in the above example)
82
+ # * <tt>inheritance_column</tt> - name of the column to save the model's inheritance_column value for STI. (default: versioned_type)
83
+ # * <tt>version_column</tt> - name of the column in the model that keeps the version number (default: version)
84
+ # * <tt>sequence_name</tt> - name of the custom sequence to be used by the versioned model.
85
+ # * <tt>limit</tt> - number of revisions to keep, defaults to unlimited
86
+ # * <tt>if</tt> - symbol of method to check before saving a new version. If this method returns false, a new version is not saved.
87
+ # For finer control, pass either a Proc or modify Model#version_condition_met?
88
+ #
89
+ # acts_as_versioned :if => Proc.new { |auction| !auction.expired? }
90
+ #
91
+ # or...
92
+ #
93
+ # class Auction
94
+ # def version_condition_met? # totally bypasses the <tt>:if</tt> option
95
+ # !expired?
96
+ # end
97
+ # end
98
+ #
99
+ # * <tt>if_changed</tt> - Simple way of specifying attributes that are required to be changed before saving a model. This takes
100
+ # either a symbol or array of symbols. WARNING - This will attempt to overwrite any attribute setters you may have.
101
+ # Use this instead if you want to write your own attribute setters (and ignore if_changed):
102
+ #
103
+ # def name=(new_name)
104
+ # write_changed_attribute :name, new_name
105
+ # end
106
+ #
107
+ # * <tt>extend</tt> - Lets you specify a module to be mixed in both the original and versioned models. You can also just pass a block
108
+ # to create an anonymous mixin:
109
+ #
110
+ # class Auction
111
+ # acts_as_versioned do
112
+ # def started?
113
+ # !started_at.nil?
114
+ # end
115
+ # end
116
+ # end
117
+ #
118
+ # or...
119
+ #
120
+ # module AuctionExtension
121
+ # def started?
122
+ # !started_at.nil?
123
+ # end
124
+ # end
125
+ # class Auction
126
+ # acts_as_versioned :extend => AuctionExtension
127
+ # end
128
+ #
129
+ # Example code:
130
+ #
131
+ # @auction = Auction.find(1)
132
+ # @auction.started?
133
+ # @auction.versions.first.started?
134
+ #
135
+ # == Database Schema
136
+ #
137
+ # The model that you're versioning needs to have a 'version' attribute. The model is versioned
138
+ # into a table called #{model}_versions where the model name is singlular. The _versions table should
139
+ # contain all the fields you want versioned, the same version column, and a #{model}_id foreign key field.
140
+ #
141
+ # A lock_version field is also accepted if your model uses Optimistic Locking. If your table uses Single Table inheritance,
142
+ # then that field is reflected in the versioned model as 'versioned_type' by default.
143
+ #
144
+ # Acts_as_versioned comes prepared with the ActiveRecord::Acts::Versioned::ActMethods::ClassMethods#create_versioned_table
145
+ # method, perfect for a migration. It will also create the version column if the main model does not already have it.
146
+ #
147
+ # class AddVersions < ActiveRecord::Migration
148
+ # def self.up
149
+ # # create_versioned_table takes the same options hash
150
+ # # that create_table does
151
+ # Post.create_versioned_table
152
+ # end
153
+ #
154
+ # def self.down
155
+ # Post.drop_versioned_table
156
+ # end
157
+ # end
158
+ #
159
+ # == Changing What Fields Are Versioned
160
+ #
161
+ # By default, acts_as_versioned will version all but these fields:
162
+ #
163
+ # [self.primary_key, inheritance_column, 'version', 'lock_version', versioned_inheritance_column]
164
+ #
165
+ # You can add or change those by modifying #non_versioned_columns. Note that this takes strings and not symbols.
166
+ #
167
+ # class Post < ActiveRecord::Base
168
+ # acts_as_versioned
169
+ # self.non_versioned_columns << 'comments_count'
170
+ # end
171
+ #
172
+ def acts_as_versioned(options = {}, &extension)
173
+ # don't allow multiple calls
174
+ return if self.included_modules.include?(ActiveRecord::Acts::Versioned::ActMethods)
175
+
176
+ send :include, ActiveRecord::Acts::Versioned::ActMethods
177
+
178
+ cattr_accessor :versioned_class_name, :versioned_foreign_key, :versioned_table_name, :versioned_inheritance_column,
179
+ :version_column, :max_version_limit, :track_changed_attributes, :version_condition, :version_sequence_name, :non_versioned_columns,
180
+ :version_association_options, :tracked_attributes
181
+
182
+ # legacy
183
+ alias_method :non_versioned_fields, :non_versioned_columns
184
+ alias_method :non_versioned_fields=, :non_versioned_columns=
185
+
186
+ class << self
187
+ alias_method :non_versioned_fields, :non_versioned_columns
188
+ alias_method :non_versioned_fields=, :non_versioned_columns=
189
+ end
190
+
191
+ self.versioned_class_name = options[:class_name] || "Version"
192
+ self.versioned_foreign_key = options[:foreign_key] || self.to_s.foreign_key
193
+ self.versioned_table_name = options[:table_name] || "#{table_name_prefix}#{base_class.name.demodulize.underscore}_versions#{table_name_suffix}"
194
+ self.versioned_inheritance_column = options[:inheritance_column] || "versioned_#{inheritance_column}"
195
+ self.version_column = options[:version_column] || 'version'
196
+ self.version_sequence_name = options[:sequence_name]
197
+ self.max_version_limit = options[:limit].to_i
198
+ self.version_condition = options[:if] || true
199
+ self.non_versioned_columns = [self.primary_key, inheritance_column, 'version', 'lock_version', versioned_inheritance_column]
200
+ self.version_association_options = {
201
+ :class_name => "#{self.to_s}::#{versioned_class_name}",
202
+ :foreign_key => versioned_foreign_key,
203
+ :order => 'version',
204
+ :dependent => :delete_all
205
+ }.merge(options[:association_options] || {})
206
+
207
+ if block_given?
208
+ extension_module_name = "#{versioned_class_name}Extension"
209
+ silence_warnings do
210
+ self.const_set(extension_module_name, Module.new(&extension))
211
+ end
212
+
213
+ options[:extend] = self.const_get(extension_module_name)
214
+ end
215
+
216
+ class_eval do
217
+ has_many :versions, version_association_options do
218
+ # finds earliest version of this record
219
+ def earliest
220
+ @earliest ||= find(:first)
221
+ end
222
+
223
+ # find latest version of this record
224
+ def latest
225
+ @latest ||= find(:first, :order => 'version desc')
226
+ end
227
+ end
228
+ before_save :set_new_version
229
+ after_create :save_version_on_create
230
+ after_update :save_version
231
+ after_save :clear_old_versions
232
+
233
+ unless options[:if_changed].nil?
234
+ self.track_changed_attributes = true
235
+ options[:if_changed] = [options[:if_changed]] unless options[:if_changed].is_a?(Array)
236
+ #convert to string because that is what dirty objects use for the return array in changed
237
+ self.tracked_attributes = options[:if_changed].map {|x| x.to_s}
238
+ end
239
+
240
+ include options[:extend] if options[:extend].is_a?(Module)
241
+ end
242
+
243
+ # create the dynamic versioned model
244
+ const_set(versioned_class_name, Class.new(ActiveRecord::Base)).class_eval do
245
+ def self.reloadable? ; false ; end
246
+ # find first version before the given version
247
+ def self.before(version)
248
+ find :first, :order => 'version desc',
249
+ :conditions => ["#{original_class.versioned_foreign_key} = ? and version < ?", version.send(original_class.versioned_foreign_key), version.version]
250
+ end
251
+
252
+ # find first version after the given version.
253
+ def self.after(version)
254
+ find :first, :order => 'version',
255
+ :conditions => ["#{original_class.versioned_foreign_key} = ? and version > ?", version.send(original_class.versioned_foreign_key), version.version]
256
+ end
257
+
258
+ def previous
259
+ self.class.before(self)
260
+ end
261
+
262
+ def next
263
+ self.class.after(self)
264
+ end
265
+
266
+ def versions_count
267
+ page.version
268
+ end
269
+ end
270
+
271
+ versioned_class.cattr_accessor :original_class
272
+ versioned_class.original_class = self
273
+ versioned_class.set_table_name versioned_table_name
274
+ versioned_class.belongs_to self.to_s.demodulize.underscore.to_sym,
275
+ :class_name => "::#{self.to_s}",
276
+ :foreign_key => versioned_foreign_key
277
+ versioned_class.send :include, options[:extend] if options[:extend].is_a?(Module)
278
+ versioned_class.set_sequence_name version_sequence_name if version_sequence_name
279
+ end
280
+ end
281
+
282
+ module ActMethods
283
+ def self.included(base) # :nodoc:
284
+ base.extend ClassMethods
285
+ end
286
+
287
+ # Finds a specific version of this record
288
+ def find_version(version = nil)
289
+ self.class.find_version(id, version)
290
+ end
291
+
292
+ # Saves a version of the model if applicable
293
+ def save_version
294
+ save_version_on_create if save_version?
295
+ end
296
+
297
+ # Saves a version of the model in the versioned table. This is called in the after_save callback by default
298
+ def save_version_on_create
299
+ rev = self.class.versioned_class.new
300
+ self.clone_versioned_model(self, rev)
301
+ rev.version = send(self.class.version_column)
302
+ rev.send("#{self.class.versioned_foreign_key}=", self.id)
303
+ rev.save
304
+ end
305
+
306
+ # Clears old revisions if a limit is set with the :limit option in <tt>acts_as_versioned</tt>.
307
+ # Override this method to set your own criteria for clearing old versions.
308
+ def clear_old_versions
309
+ return if self.class.max_version_limit == 0
310
+ excess_baggage = send(self.class.version_column).to_i - self.class.max_version_limit
311
+ if excess_baggage > 0
312
+ sql = "DELETE FROM #{self.class.versioned_table_name} WHERE version <= #{excess_baggage} AND #{self.class.versioned_foreign_key} = #{self.id}"
313
+ self.class.versioned_class.connection.execute sql
314
+ end
315
+ end
316
+
317
+ def versions_count
318
+ version
319
+ end
320
+
321
+ # Reverts a model to a given version. Takes either a version number or an instance of the versioned model
322
+ def revert_to(version)
323
+ if version.is_a?(self.class.versioned_class)
324
+ return false unless version.send(self.class.versioned_foreign_key) == self.id and !version.new_record?
325
+ else
326
+ return false unless version = versions.find_by_version(version)
327
+ end
328
+ self.clone_versioned_model(version, self)
329
+ self.send("#{self.class.version_column}=", version.version)
330
+ true
331
+ end
332
+
333
+ # Reverts a model to a given version and saves the model.
334
+ # Takes either a version number or an instance of the versioned model
335
+ def revert_to!(version)
336
+ revert_to(version) ? save_without_revision : false
337
+ end
338
+
339
+ # Temporarily turns off Optimistic Locking while saving. Used when reverting so that a new version is not created.
340
+ def save_without_revision
341
+ save_without_revision!
342
+ true
343
+ rescue
344
+ false
345
+ end
346
+
347
+ def save_without_revision!
348
+ without_locking do
349
+ without_revision do
350
+ save!
351
+ end
352
+ end
353
+ end
354
+
355
+ # Returns an array of attribute keys that are versioned. See non_versioned_columns
356
+ def versioned_attributes
357
+ self.attributes.keys.select { |k| !self.class.non_versioned_columns.include?(k) }
358
+ end
359
+
360
+ # If called with no parameters, gets whether the current model has changed and needs to be versioned.
361
+ def should_version?
362
+ (!self.class.track_changed_attributes || (tracked_attributes & self.changed).length > 0 )
363
+ end
364
+
365
+ # Clones a model. Used when saving a new version or reverting a model's version.
366
+ def clone_versioned_model(orig_model, new_model)
367
+ self.versioned_attributes.each do |key|
368
+ new_model.send("#{key}=", orig_model.send(key)) if orig_model.has_attribute?(key)
369
+ end
370
+
371
+ if orig_model.is_a?(self.class.versioned_class)
372
+ new_model[new_model.class.inheritance_column] = orig_model[self.class.versioned_inheritance_column]
373
+ elsif new_model.is_a?(self.class.versioned_class)
374
+ new_model[self.class.versioned_inheritance_column] = orig_model[orig_model.class.inheritance_column]
375
+ end
376
+ end
377
+
378
+ # Checks whether a new version shall be saved or not. Calls <tt>version_condition_met?</tt> and <tt>changed?</tt>.
379
+ def save_version?
380
+ version_condition_met? && should_version?
381
+ end
382
+
383
+ # Checks condition set in the :if option to check whether a revision should be created or not. Override this for
384
+ # custom version condition checking.
385
+ def version_condition_met?
386
+ case
387
+ when version_condition.is_a?(Symbol)
388
+ send(version_condition)
389
+ when version_condition.respond_to?(:call) && (version_condition.arity == 1 || version_condition.arity == -1)
390
+ version_condition.call(self)
391
+ else
392
+ version_condition
393
+ end
394
+ end
395
+
396
+ # Executes the block with the versioning callbacks disabled.
397
+ #
398
+ # @foo.without_revision do
399
+ # @foo.save
400
+ # end
401
+ #
402
+ def without_revision(&block)
403
+ self.class.without_revision(&block)
404
+ end
405
+
406
+ # Turns off optimistic locking for the duration of the block
407
+ #
408
+ # @foo.without_locking do
409
+ # @foo.save
410
+ # end
411
+ #
412
+ def without_locking(&block)
413
+ self.class.without_locking(&block)
414
+ end
415
+
416
+ def empty_callback() end #:nodoc:
417
+
418
+ protected
419
+ # sets the new version before saving, unless you're using optimistic locking. In that case, let it take care of the version.
420
+ def set_new_version
421
+ self.send("#{self.class.version_column}=", self.next_version) if new_record? || (!locking_enabled? && save_version?)
422
+ end
423
+
424
+ # Gets the next available version for the current record, or 1 for a new record
425
+ def next_version
426
+ return 1 if new_record?
427
+ (versions.calculate(:max, :version) || 0) + 1
428
+ end
429
+
430
+ module ClassMethods
431
+ # Finds a specific version of a specific row of this model
432
+ def find_version(id, version = nil)
433
+ return find(id) unless version
434
+
435
+ conditions = ["#{versioned_foreign_key} = ? AND version = ?", id, version]
436
+ options = { :conditions => conditions, :limit => 1 }
437
+
438
+ if result = find_versions(id, options).first
439
+ result
440
+ else
441
+ raise RecordNotFound, "Couldn't find #{name} with ID=#{id} and VERSION=#{version}"
442
+ end
443
+ end
444
+
445
+ # Finds versions of a specific model. Takes an options hash like <tt>find</tt>
446
+ def find_versions(id, options = {})
447
+ versioned_class.find :all, {
448
+ :conditions => ["#{versioned_foreign_key} = ?", id],
449
+ :order => 'version' }.merge(options)
450
+ end
451
+
452
+ # Returns an array of columns that are versioned. See non_versioned_columns
453
+ def versioned_columns
454
+ self.columns.select { |c| !non_versioned_columns.include?(c.name) }
455
+ end
456
+
457
+ # Returns an instance of the dynamic versioned model
458
+ def versioned_class
459
+ const_get versioned_class_name
460
+ end
461
+
462
+ # Rake migration task to create the versioned table using options passed to acts_as_versioned
463
+ def create_versioned_table(create_table_options = {})
464
+ # create version column in main table if it does not exist
465
+ if !self.content_columns.find { |c| %w(version lock_version).include? c.name }
466
+ self.connection.add_column table_name, :version, :integer
467
+ end
468
+
469
+ self.connection.create_table(versioned_table_name, create_table_options) do |t|
470
+ t.column versioned_foreign_key, :integer
471
+ t.column :version, :integer
472
+ end
473
+
474
+ updated_col = nil
475
+ self.versioned_columns.each do |col|
476
+ updated_col = col if !updated_col && %(updated_at updated_on).include?(col.name)
477
+ self.connection.add_column versioned_table_name, col.name, col.type,
478
+ :limit => col.limit,
479
+ :default => col.default,
480
+ :scale => col.scale,
481
+ :precision => col.precision
482
+ end
483
+
484
+ if type_col = self.columns_hash[inheritance_column]
485
+ self.connection.add_column versioned_table_name, versioned_inheritance_column, type_col.type,
486
+ :limit => type_col.limit,
487
+ :default => type_col.default,
488
+ :scale => type_col.scale,
489
+ :precision => type_col.precision
490
+ end
491
+
492
+ if updated_col.nil?
493
+ self.connection.add_column versioned_table_name, :updated_at, :timestamp
494
+ end
495
+ end
496
+
497
+ # Rake migration task to drop the versioned table
498
+ def drop_versioned_table
499
+ self.connection.drop_table versioned_table_name
500
+ end
501
+
502
+ # Executes the block with the versioning callbacks disabled.
503
+ #
504
+ # Foo.without_revision do
505
+ # @foo.save
506
+ # end
507
+ #
508
+ def without_revision(&block)
509
+ class_eval do
510
+ CALLBACKS.each do |attr_name|
511
+ alias_method "orig_#{attr_name}".to_sym, attr_name
512
+ alias_method attr_name, :empty_callback
513
+ end
514
+ end
515
+ block.call
516
+ ensure
517
+ class_eval do
518
+ CALLBACKS.each do |attr_name|
519
+ alias_method attr_name, "orig_#{attr_name}".to_sym
520
+ end
521
+ end
522
+ end
523
+
524
+ # Turns off optimistic locking for the duration of the block
525
+ #
526
+ # Foo.without_locking do
527
+ # @foo.save
528
+ # end
529
+ #
530
+ def without_locking(&block)
531
+ current = ActiveRecord::Base.lock_optimistically
532
+ ActiveRecord::Base.lock_optimistically = false if current
533
+ result = block.call
534
+ ActiveRecord::Base.lock_optimistically = true if current
535
+ result
536
+ end
537
+ end
538
+ end
539
+ end
540
+ end
541
+ end
542
+
543
+ ActiveRecord::Base.send :include, ActiveRecord::Acts::Versioned
@@ -0,0 +1,79 @@
1
+ module Comatose
2
+
3
+ class ComatoseDrop < ::Liquid::Drop
4
+
5
+ private :initialize
6
+
7
+ def before_method(method)
8
+ self.send(method.to_sym)
9
+ rescue
10
+ ComatoseController.logger.debug "Error calling #{method}: #{$!}"
11
+ raise $!
12
+ end
13
+
14
+ class << self
15
+ # Define a new ComatoseDrop by name
16
+ def define( name, &block )
17
+ d = ComatoseDrop.new
18
+ d.instance_eval(&block)
19
+ Comatose.registered_drops[name] = d
20
+ rescue
21
+ ComatoseController.logger.debug "Drop '#{name}' was not included: #{$!}"
22
+ end
23
+ end
24
+ end
25
+
26
+ class << self
27
+
28
+ # Returns/initializes a hash for storing ComatoseDrops
29
+ def registered_drops
30
+ @registered_drops ||= {}
31
+ end
32
+
33
+ # Simple wrapper around the ProcessingContext.define method
34
+ # I think Comatose.define_drop is probably simpler to remember too
35
+ def define_drop(name, &block)
36
+ ComatoseDrop.define(name, &block)
37
+ end
38
+
39
+ # Registers a 'filter' for Liquid use
40
+ def register_filter(module_name)
41
+ Liquid::Template.register_filter(module_name)
42
+ end
43
+
44
+ end
45
+ end
46
+
47
+
48
+ #
49
+ # Some Default Filters/Drops
50
+ #
51
+
52
+ module IncludeFilter
53
+ def include(input)
54
+ page = ComatosePage.find_by_path(input)
55
+ params = @context['params']
56
+ # TODO: Add more of the context into the included page's context...
57
+ page.to_html( { 'params' => params } )
58
+ rescue
59
+ "Page at <tt>#{input}</tt> could not be found. <pre>#{$!}</pre>"
60
+ end
61
+ end
62
+
63
+ Comatose.register_filter IncludeFilter
64
+
65
+
66
+ module TimeagoFilter
67
+ class Helpers
68
+ extend ActionView::Helpers::DateHelper
69
+ end
70
+
71
+ def time_ago(input)
72
+ TimeagoFilter::Helpers.distance_of_time_in_words_to_now( input, true )
73
+ rescue
74
+ #puts "Oops! -- #{$!}"
75
+ input
76
+ end
77
+ end
78
+
79
+ Comatose.register_filter TimeagoFilter
@@ -0,0 +1,69 @@
1
+ module Comatose
2
+
3
+ def self.config
4
+ @@config ||= Configuration.new
5
+ end
6
+
7
+ def self.configure(&block)
8
+ raise "#configure must be sent a block" unless block_given?
9
+ yield config
10
+ config.validate!
11
+ end
12
+
13
+ # All of the 'mount' points for Comatose
14
+ def self.mount_points
15
+ @@mount_points ||= []
16
+ end
17
+
18
+ # Adds a 'mount' point to the list of known roots...
19
+ def self.add_mount_point(path, info={:index=>''})
20
+ path = "/#{path}" unless path.starts_with? '/'
21
+ info[:root]=path
22
+ mount_points << info
23
+ end
24
+
25
+ class Configuration
26
+
27
+ attr_accessor_with_default :admin_title, 'Comatose'
28
+ attr_accessor_with_default :admin_includes, []
29
+ attr_accessor_with_default :admin_helpers, []
30
+ attr_accessor_with_default :admin_sub_title, 'The Micro CMS'
31
+ attr_accessor_with_default :content_type, 'utf-8'
32
+ attr_accessor_with_default :default_filter, 'Textile'
33
+ attr_accessor_with_default :default_processor, :liquid
34
+ attr_accessor_with_default :default_tree_level, 2
35
+ attr_accessor_with_default :disable_caching, false
36
+ attr_accessor_with_default :hidden_meta_fields, []
37
+ attr_accessor_with_default :helpers, []
38
+ attr_accessor_with_default :includes, []
39
+ attr_accessor_with_default :allow_import_export, true
40
+
41
+ # 'Blockable' setters
42
+ blockable_attr_accessor :authorization
43
+ blockable_attr_accessor :admin_authorization
44
+ blockable_attr_accessor :admin_get_author
45
+ blockable_attr_accessor :admin_get_root_page
46
+ blockable_attr_accessor :after_setup
47
+
48
+ def initialize
49
+ # Default procs for blockable attrs....
50
+ @authorization = Proc.new { true }
51
+ @admin_authorization = Proc.new { true }
52
+ @admin_get_author = Proc.new { request.env['REMOTE_ADDR'] }
53
+ @admin_get_root_page = Proc.new { ComatosePage.root }
54
+ @after_setup = Proc.new { true }
55
+ end
56
+
57
+ def validate!
58
+ # Rips through the config and validates it's, er, valid
59
+ raise ConfigurationError.new( "admin_get_author must be a Proc or Symbol" ) unless @admin_get_author.is_a? Proc or @admin_get_author.is_a? Symbol
60
+ raise ConfigurationError.new( "admin_authorization must be a Proc or Symbol" ) unless @admin_authorization.is_a? Proc or @admin_authorization.is_a? Symbol
61
+ raise ConfigurationError.new( "authorization must be a Proc or Symbol" ) unless @authorization.is_a? Proc or @authorization.is_a? Symbol
62
+ true
63
+ end
64
+
65
+ class ConfigurationError < StandardError; end
66
+
67
+ end
68
+
69
+ end