staugaard-comatose 2.0.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 +176 -0
  2. data/INSTALL +19 -0
  3. data/LICENSE +20 -0
  4. data/MANIFEST +91 -0
  5. data/README.rdoc +148 -0
  6. data/Rakefile +122 -0
  7. data/SPECS +61 -0
  8. data/about.yml +7 -0
  9. data/bin/comatose +109 -0
  10. data/comatose.gemspec +113 -0
  11. data/generators/comatose_migration/USAGE +15 -0
  12. data/generators/comatose_migration/comatose_migration_generator.rb +59 -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 +16 -0
  19. data/lib/acts_as_versioned.rb +543 -0
  20. data/lib/comatose.rb +33 -0
  21. data/lib/comatose/comatose_drop.rb +79 -0
  22. data/lib/comatose/configuration.rb +68 -0
  23. data/lib/comatose/page_wrapper.rb +119 -0
  24. data/lib/comatose/processing_context.rb +69 -0
  25. data/lib/comatose/tasks/admin.rb +60 -0
  26. data/lib/comatose/tasks/data.rb +82 -0
  27. data/lib/comatose/tasks/setup.rb +52 -0
  28. data/lib/comatose/version.rb +4 -0
  29. data/lib/comatose_admin_controller.rb +349 -0
  30. data/lib/comatose_admin_helper.rb +37 -0
  31. data/lib/comatose_controller.rb +142 -0
  32. data/lib/comatose_helper.rb +3 -0
  33. data/lib/comatose_page.rb +141 -0
  34. data/lib/liquid.rb +52 -0
  35. data/lib/liquid/block.rb +96 -0
  36. data/lib/liquid/context.rb +190 -0
  37. data/lib/liquid/document.rb +17 -0
  38. data/lib/liquid/drop.rb +48 -0
  39. data/lib/liquid/errors.rb +7 -0
  40. data/lib/liquid/extensions.rb +53 -0
  41. data/lib/liquid/file_system.rb +62 -0
  42. data/lib/liquid/htmltags.rb +64 -0
  43. data/lib/liquid/standardfilters.rb +111 -0
  44. data/lib/liquid/standardtags.rb +399 -0
  45. data/lib/liquid/strainer.rb +42 -0
  46. data/lib/liquid/tag.rb +25 -0
  47. data/lib/liquid/template.rb +88 -0
  48. data/lib/liquid/variable.rb +39 -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.rb +138 -0
  54. data/lib/text_filters/markdown.rb +14 -0
  55. data/lib/text_filters/markdown_smartypants.rb +15 -0
  56. data/lib/text_filters/none.rb +8 -0
  57. data/lib/text_filters/rdoc.rb +13 -0
  58. data/lib/text_filters/simple.rb +8 -0
  59. data/lib/text_filters/textile.rb +15 -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 +381 -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 +112 -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 +43 -0
  78. data/test/unit/class_options_test.rb +52 -0
  79. data/test/unit/comatose_page_test.rb +128 -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 +18 -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 +814 -0
  91. data/views/layouts/comatose_admin_customize.html.erb +28 -0
  92. data/views/layouts/comatose_content.html.erb +17 -0
  93. metadata +147 -0
data/lib/comatose.rb ADDED
@@ -0,0 +1,33 @@
1
+
2
+ module Comatose
3
+
4
+ # DEPRECATED
5
+ # Loads extensions from RAILS_ROOT/lib/comatose/*.rb
6
+ def self.load_extensions
7
+ Dir[File.join(RAILS_ROOT, 'lib', 'comatose', '*.rb')].each do |path|
8
+ require "comatose/#{File.basename(path)}"
9
+ end
10
+ end
11
+
12
+ end
13
+
14
+ require 'acts_as_versioned'
15
+ require 'redcloth' unless defined?(RedCloth)
16
+ require 'liquid' unless defined?(Liquid)
17
+
18
+ require 'support/class_options'
19
+ require 'text_filters'
20
+
21
+ require 'comatose/configuration'
22
+ require 'comatose/comatose_drop'
23
+ require 'comatose/processing_context'
24
+ require 'comatose/page_wrapper'
25
+ require 'comatose/version'
26
+
27
+ require 'support/inline_rendering'
28
+ require 'support/route_mapper'
29
+
30
+ require 'dispatcher' unless defined?(::Dispatcher)
31
+ ::Dispatcher.to_prepare :comatose do
32
+ Comatose.config.after_setup.call
33
+ end
@@ -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,68 @@
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
+
40
+ # 'Blockable' setters
41
+ blockable_attr_accessor :authorization
42
+ blockable_attr_accessor :admin_authorization
43
+ blockable_attr_accessor :admin_get_author
44
+ blockable_attr_accessor :admin_get_root_page
45
+ blockable_attr_accessor :after_setup
46
+
47
+ def initialize
48
+ # Default procs for blockable attrs....
49
+ @authorization = Proc.new { true }
50
+ @admin_authorization = Proc.new { true }
51
+ @admin_get_author = Proc.new { request.env['REMOTE_ADDR'] }
52
+ @admin_get_root_page = Proc.new { ComatosePage.root }
53
+ @after_setup = Proc.new { true }
54
+ end
55
+
56
+ def validate!
57
+ # Rips through the config and validates it's, er, valid
58
+ 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
59
+ raise ConfigurationError.new( "admin_authorization must be a Proc or Symbol" ) unless @admin_authorization.is_a? Proc or @admin_authorization.is_a? Symbol
60
+ raise ConfigurationError.new( "authorization must be a Proc or Symbol" ) unless @authorization.is_a? Proc or @authorization.is_a? Symbol
61
+ true
62
+ end
63
+
64
+ class ConfigurationError < StandardError; end
65
+
66
+ end
67
+
68
+ end
@@ -0,0 +1,119 @@
1
+ # Giving direct access to the AR model is disconcerting, so this wraps the AR
2
+ # Model to prevent access to certain, destructive behavior
3
+ class Comatose::PageWrapper
4
+
5
+ @@allowed_methods = %w(id full_path uri slug keywords title to_html filter_type author updated_on created_on)
6
+ @@custom_methods = %w(link content parent next previous children rchildren first_child last_child has_keyword)
7
+
8
+ attr_accessor :page
9
+ private :page
10
+
11
+ def initialize( page, locals={} )
12
+ @page = page
13
+ @keyword_lst = []
14
+ @keyword_hsh = {}
15
+ unless page.nil?
16
+ @keyword_lst = (page.keywords || '').downcase.split(',').map {|k| k.strip }
17
+ @keyword_lst.each {|kw| @keyword_hsh[kw] = true}
18
+ end
19
+ @locals = locals
20
+ end
21
+
22
+ def has_keyword?(keyword)
23
+ @page.has_keyword?(keyword)
24
+ end
25
+
26
+ def has_keyword
27
+ @keyword_hsh
28
+ end
29
+
30
+ def next
31
+ @next_page ||= begin
32
+ if @page.lower_item.nil?
33
+ nil
34
+ else
35
+ Comatose::PageWrapper.new( @page.lower_item )
36
+ end
37
+ end
38
+ end
39
+
40
+ def previous
41
+ @prev_page ||= begin
42
+ if @page.higher_item.nil?
43
+ nil
44
+ else
45
+ Comatose::PageWrapper.new( @page.higher_item )
46
+ end
47
+ end
48
+ end
49
+
50
+ def first_child
51
+ children.first
52
+ end
53
+
54
+ def def last_child
55
+ children.last
56
+ end
57
+
58
+ # Generates a link to this page... You can pass in the link text,
59
+ # otherwise it will default to the page title.
60
+ def link( title=nil )
61
+ title = @page.title if title.nil?
62
+ TextFilters[@page.filter_type].create_link(title, @page.uri)
63
+ end
64
+
65
+ def content
66
+ @page.to_html( @locals )
67
+ end
68
+
69
+ def parent
70
+ @parent ||= begin
71
+ if @page.parent.nil?
72
+ nil
73
+ else
74
+ Comatose::PageWrapper.new( @page.parent )
75
+ end
76
+ end
77
+ end
78
+
79
+ def children
80
+ # Cache the results so that you can have multiple calls to #children without a penalty
81
+ @children ||= @page.children.to_a.collect {|child| Comatose::PageWrapper.new( child, @locals )}
82
+ end
83
+
84
+ # Children, in reverse order
85
+ def rchildren
86
+ children.reverse
87
+ end
88
+
89
+ def [](key)
90
+ if @@allowed_methods.include? key.to_s #or page.attributes.has_key? key.to_s
91
+ page.send( key )
92
+ elsif @@custom_methods.include? key
93
+ self.send(key.to_sym)
94
+ end
95
+ end
96
+
97
+ def has_key?(key)
98
+ @@allowed_methods.include? key or @@custom_methods.include? key
99
+ end
100
+
101
+ def to_s
102
+ @page.title
103
+ end
104
+
105
+ def to_liquid
106
+ self
107
+ end
108
+
109
+ def method_missing(method_id, *args)
110
+ #STDERR.puts "Looking for method: #{method_id} (#{method_id.class.to_s}) in [#{@@allowed_methods.join(', ')}] or [#{page.attributes.keys.join(', ')}]"
111
+ if @@allowed_methods.include? method_id.to_s or page.attributes.has_key? method_id.to_s
112
+ page.send( method_id, *args)
113
+ else
114
+ # Access nazi says: NO ACCESS FOR YOU!!
115
+ # but he says it silently...
116
+ end
117
+ end
118
+
119
+ end
@@ -0,0 +1,69 @@
1
+ # This is the rendering context object you have access to in text processing...
2
+ class Comatose::ProcessingContext
3
+ @@supported_methods = %w(page include)
4
+
5
+ def initialize( page, locals={} )
6
+ @locals = locals.stringify_keys if locals.respond_to? :stringify_keys
7
+ @page = Comatose::PageWrapper.new(page, @locals)
8
+ end
9
+
10
+ def page
11
+ @page
12
+ end
13
+
14
+ def include(path, locals={})
15
+ begin
16
+ page = ComatosePage.find_by_path(path)
17
+ page.to_html( @locals.merge(locals) )
18
+ rescue
19
+ "<p>Page at <tt>#{path}</tt> could not be found.</p>"
20
+ end
21
+ end
22
+
23
+ def find_by_path(path)
24
+ begin
25
+ page = ComatosePage.find_by_path(path)
26
+ Comatose::PageWrapper.new(page, @locals)
27
+ rescue
28
+ "<p>Page at <tt>#{path}</tt> could not be found.</p>"
29
+ end
30
+ end
31
+
32
+ def [](key)
33
+ if key.to_s.downcase == 'page'
34
+ @page
35
+ elsif @locals.has_key? key
36
+ @locals[key]
37
+ elsif Comatose.registered_drops.has_key? key
38
+ Comatose.registered_drops[key]
39
+ end
40
+ end
41
+
42
+ def has_key?(key)
43
+ @@supported_methods.include?(key) or @locals.has_key?(key) or Comatose.registered_drops.has_key?(key)
44
+ end
45
+
46
+ def to_liquid
47
+ self
48
+ end
49
+
50
+ def get_binding
51
+ binding
52
+ end
53
+
54
+ def method_missing(method_id, *args)
55
+ method_name = method_id.to_s
56
+ if @locals.has_key? method_name
57
+ @locals[method_name]
58
+ elsif Comatose.registered_drops.has_key? method_name
59
+ Comatose.registered_drops[method_name].context = self
60
+ Comatose.registered_drops[method_name]
61
+ else
62
+ "<!-- ProcessingContext: Couldn't find #{method_id} -->"
63
+ end
64
+ end
65
+
66
+ end
67
+
68
+
69
+
@@ -0,0 +1,60 @@
1
+ require 'rake'
2
+ require 'rake/tasklib'
3
+
4
+ namespace :comatose do
5
+ #
6
+ # Customization Tasks
7
+ #
8
+ namespace :admin do
9
+
10
+ desc "Create Comatose views, layouts, and public files..."
11
+ task :customize do
12
+ puts "Copying public files..."
13
+ plugin_dir = File.join(File.dirname(__FILE__), '../../..')
14
+ FileUtils.cp(
15
+ Dir[File.join(plugin_dir, 'resources', 'public', 'stylesheets', '*.css')],
16
+ File.join(RAILS_ROOT, 'public', 'stylesheets'),
17
+ :verbose => true
18
+ )
19
+ FileUtils.cp(
20
+ Dir[File.join(plugin_dir, 'resources', 'public', 'javascripts', '*.js')],
21
+ File.join(RAILS_ROOT, 'public', 'javascripts'),
22
+ :verbose => true
23
+ )
24
+ puts "Copying application views..."
25
+ FileUtils.mkdir_p(File.join(RAILS_ROOT, 'app', 'views', 'comatose_admin'))
26
+ FileUtils.cp(
27
+ Dir[File.join(plugin_dir, 'views', 'comatose_admin', '*.html.erb')],
28
+ File.join(RAILS_ROOT, 'app', 'views', 'comatose_admin'),
29
+ :verbose => true
30
+ )
31
+ puts "Copying application layout..."
32
+ FileUtils.cp(
33
+ File.join(plugin_dir, 'views', 'layouts', 'comatose_admin_customize.html.erb'),
34
+ File.join(RAILS_ROOT, 'app', 'views', 'layouts', 'comatose_admin.html.erb'),
35
+ :verbose => true
36
+ )
37
+ puts "Finished."
38
+ end
39
+
40
+
41
+ desc "Removes the customized files... It doesn't ask for any confirmation, nor is it Subversion-safe -- so be warned!"
42
+ task :teardown do
43
+ puts "Removing public files..."
44
+ FileUtils.rm(
45
+ File.join(RAILS_ROOT, 'public', 'stylesheets', 'comatose_admin.css')
46
+ )
47
+ FileUtils.rm(
48
+ File.join(RAILS_ROOT, 'public', 'javascripts', 'comatose_admin.js')
49
+ )
50
+
51
+ puts "Removing application views..."
52
+ FileUtils.rm_rf(
53
+ File.join(RAILS_ROOT, 'app', 'views', 'comatose_admin')
54
+ )
55
+ FileUtils.rm(
56
+ File.join(RAILS_ROOT, 'app', 'views', 'layouts', 'comatose_admin.html.erb')
57
+ )
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,82 @@
1
+ require 'rake'
2
+ require 'rake/tasklib'
3
+
4
+ namespace :comatose do
5
+ #
6
+ # Data Migration Tasks
7
+ #
8
+ namespace :data do
9
+
10
+ def page_to_hash(page)
11
+ data = page.attributes.clone
12
+ # Pull out the specific, or unnecessary fields
13
+ %w(id parent_id updated_on author position version created_on full_path).each {|key| data.delete(key)}
14
+ if !page.children.empty?
15
+ data['children'] = []
16
+ page.children.each do |child|
17
+ data['children'] << page_to_hash(child)
18
+ end
19
+ end
20
+ data
21
+ end
22
+
23
+ def hash_to_page_tree(hsh, page)
24
+ child_ary = hsh.delete 'children'
25
+ page.update_attributes(hsh)
26
+ page.save
27
+ child_ary.each do |child_hsh|
28
+ if child_pg = page.children.find_by_slug( child_hsh['slug'] )
29
+ hash_to_page_tree( child_hsh, child_pg )
30
+ else
31
+ hash_to_page_tree( child_hsh, page.children.create )
32
+ end
33
+ end if child_ary
34
+ end
35
+
36
+ desc "Saves a page tree from page FROM or '' to file TO_FILE or db/comatose-pages.yml"
37
+ task :export do
38
+ require "#{RAILS_ROOT}/config/environment"
39
+
40
+ root = ENV['FROM'] || ''
41
+ target = ENV['TO_FILE'] || 'db/comatose-pages.yml'
42
+ # Nested hash of the page tree...
43
+ from = ComatosePage.find_by_path(root)
44
+ if from
45
+ data = page_to_hash( from )
46
+ File.open(target, 'w') {|f| f.write data.to_yaml }
47
+ else
48
+ puts "Could not find the page at '#{root}', export aborted!"
49
+ end
50
+
51
+ puts "Finished."
52
+ end
53
+
54
+ desc "Loads page tree data FROM_FILE or db/comatose-pages.yml in to TO or ComatosePage.root"
55
+ task :import do
56
+ require "#{RAILS_ROOT}/config/environment"
57
+
58
+ src = ENV['FROM_FILE'] || 'db/comatose-pages.yml'
59
+ root = ENV['TO'] || ''
60
+ target = (root == '') ? ComatosePage.root : ComatosePage.find_by_path(root)
61
+ data = YAML::load( File.open(src) )
62
+ #hash_to_page(data, target)
63
+ if target
64
+ if root == ''
65
+ hash_to_page_tree(data, target)
66
+ else
67
+ if page = target.children.find_by_slug(data['slug'])
68
+ hash_to_page_tree(data, page)
69
+ else
70
+ hash_to_page_tree(data, target.children.create)
71
+ end
72
+ end
73
+ else
74
+ puts "Could not find the page at '#{root}', import aborted!"
75
+ # TODO: Ask to create the specified path if it doesn't exist?
76
+ end
77
+ puts "Finished."
78
+ end
79
+
80
+ end
81
+
82
+ end