zen 0.2.3 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/CHANGELOG.md +12 -2
  2. data/MANIFEST +17 -10
  3. data/ROADMAP.md +8 -4
  4. data/bin/zen +2 -3
  5. data/lib/zen.rb +20 -14
  6. data/lib/zen/bin/{zen_binary.rb → base.rb} +0 -0
  7. data/lib/zen/controller/main_controller.rb +7 -4
  8. data/lib/zen/{base/database.rb → database.rb} +3 -2
  9. data/lib/zen/error/language_error.rb +10 -0
  10. data/lib/zen/error/package_error.rb +10 -0
  11. data/lib/zen/error/plugin_error.rb +10 -0
  12. data/lib/zen/error/theme_error.rb +10 -0
  13. data/lib/zen/helper/acl.rb +11 -4
  14. data/lib/zen/{base/language.rb → language.rb} +11 -3
  15. data/lib/zen/layout/admin.xhtml +21 -12
  16. data/lib/zen/layout/login.xhtml +17 -11
  17. data/lib/zen/liquid/general.rb +1 -27
  18. data/lib/zen/{base/logger.rb → logger.rb} +0 -0
  19. data/lib/zen/{base/package.rb → package.rb} +65 -55
  20. data/lib/zen/package/all.rb +5 -0
  21. data/lib/zen/package/categories/lib/categories.rb +7 -8
  22. data/lib/zen/package/comments/lib/comments.rb +7 -8
  23. data/lib/zen/package/comments/lib/comments/controller/comments_form.rb +1 -1
  24. data/lib/zen/package/comments/lib/comments/liquid/comments.rb +3 -1
  25. data/lib/zen/package/custom_fields/lib/custom_fields.rb +7 -8
  26. data/lib/zen/package/custom_fields/lib/custom_fields/model/custom_field_value.rb +14 -0
  27. data/lib/zen/package/custom_fields/migrations/1295255665_create_schema.rb +1 -1
  28. data/lib/zen/package/menus/lib/menus.rb +5 -6
  29. data/lib/zen/package/sections/lib/sections.rb +4 -5
  30. data/lib/zen/package/sections/lib/sections/language/en/section_entries.yml +2 -2
  31. data/lib/zen/package/sections/lib/sections/liquid/section_entries.rb +9 -2
  32. data/lib/zen/package/settings/lib/settings.rb +7 -8
  33. data/lib/zen/package/users/lib/users.rb +7 -8
  34. data/lib/zen/package/users/lib/users/view/admin/access-rules/form.xhtml +5 -5
  35. data/lib/zen/package/users/lib/users/view/admin/access-rules/index.xhtml +4 -4
  36. data/lib/zen/plugin.rb +172 -0
  37. data/lib/zen/plugin/markup.rb +30 -0
  38. data/lib/zen/public/admin/css/layout.css +17 -0
  39. data/lib/zen/strict_struct.rb +36 -0
  40. data/lib/zen/task/db.rb +14 -4
  41. data/lib/zen/task/package.rb +13 -8
  42. data/lib/zen/task/theme.rb +88 -0
  43. data/lib/zen/theme.rb +129 -0
  44. data/lib/zen/{base/version.rb → version.rb} +1 -1
  45. data/proto/app/config/config.rb +19 -6
  46. data/proto/app/config/database.rb +58 -2
  47. data/proto/app/config/middlewares.rb +69 -4
  48. data/proto/app/config/requires.rb +9 -2
  49. data/proto/app/{logs → log}/.gitkeep +0 -0
  50. data/proto/package/lib/package.rb +3 -13
  51. data/proto/package/lib/package/controller/controllers.rb +5 -9
  52. data/proto/package/lib/package/language/en/languages.yml +4 -0
  53. metadata +66 -26
  54. data/proto/package/LICENSE +0 -0
  55. data/proto/package/README.textile +0 -0
  56. data/proto/package/lib/package/language/en/languages.rb +0 -3
@@ -196,7 +196,12 @@ module Sections
196
196
  end
197
197
  end
198
198
 
199
- values['comment'] = markup_to_html(values['comment'], entry.section.comment_format)
199
+ values['comment'] = Zen::Plugin.call(
200
+ 'com.zen.plugin.markup',
201
+ entry.section.comment_format.to_sym,
202
+ values['comment']
203
+ )
204
+
200
205
  context['comments'].push(values)
201
206
  end
202
207
 
@@ -204,7 +209,9 @@ module Sections
204
209
  entry.custom_field_values.each do |field_value|
205
210
  field = field_value.custom_field
206
211
  name = field.slug
207
- value = markup_to_html(field_value.value, field.format.to_sym)
212
+ value = ::Zen::Plugin.call(
213
+ 'com.zen.plugin.markup', field.format.to_sym, field_value.value
214
+ )
208
215
 
209
216
  context[name.to_s] = value
210
217
  end
@@ -6,14 +6,13 @@ require __DIR__ 'settings/liquid/setting'
6
6
  Liquid::Template.register_tag('setting', Settings::Liquid::Setting)
7
7
 
8
8
  Zen::Package.add do |p|
9
- p.type = 'extension'
10
- p.name = 'Settings'
11
- p.author = 'Yorick Peterse'
12
- p.url = 'http://yorickpeterse.com/'
13
- p.version = 1.0
14
- p.about = 'Module for managing settings such as the default module, whether or not to allow registration, etc.'
15
- p.identifier = 'com.zen.settings'
16
- p.directory = __DIR__('settings')
9
+ p.name = 'Settings'
10
+ p.author = 'Yorick Peterse'
11
+ p.url = 'http://yorickpeterse.com/'
12
+ p.about = 'Module for managing settings such as the default module, whether or not to allow registration, etc.'
13
+ p.identifier = 'com.zen.settings'
14
+ p.directory = __DIR__('settings')
15
+ p.migration_dir = __DIR__('../migrations')
17
16
 
18
17
  p.menu = [{
19
18
  :title => "Settings",
@@ -18,15 +18,14 @@ Liquid::Template.register_tag('user' , Users::Liquid::User)
18
18
  Zen::Controllers::BaseController.trait(:user_model => Users::Models::User)
19
19
 
20
20
  Zen::Package.add do |p|
21
- p.type = 'extension'
22
- p.name = 'Users'
23
- p.author = 'Yorick Peterse'
24
- p.url = 'http://yorickpeterse.com/'
25
- p.version = '1.0'
26
- p.about = "Module for managing users along with handling authentication and authorization."
21
+ p.name = 'Users'
22
+ p.author = 'Yorick Peterse'
23
+ p.url = 'http://yorickpeterse.com/'
24
+ p.about = "Module for managing users along with handling authentication and authorization."
27
25
 
28
- p.identifier = 'com.zen.users'
29
- p.directory = __DIR__('users')
26
+ p.identifier = 'com.zen.users'
27
+ p.directory = __DIR__('users')
28
+ p.migration_dir = __DIR__('../migrations')
30
29
 
31
30
  p.menu = [{
32
31
  :title => "Users",
@@ -18,7 +18,7 @@
18
18
  users[user.id.to_s] = user.name
19
19
  end
20
20
 
21
- Zen::Package.extensions.each do |ident, ext|
21
+ Zen::Package.packages.each do |ident, ext|
22
22
  extensions[ident] = ext.name
23
23
  end
24
24
 
@@ -74,28 +74,28 @@
74
74
  lang('access_rules.labels.create'),
75
75
  :create_access,
76
76
  @access_rule.create_access,
77
- :values => @boolean_hash.invert
77
+ :values => @boolean_hash
78
78
  )
79
79
 
80
80
  f.input_radio(
81
81
  lang('access_rules.labels.read'),
82
82
  :read_access,
83
83
  @access_rule.read_access,
84
- :values => @boolean_hash.invert
84
+ :values => @boolean_hash
85
85
  )
86
86
 
87
87
  f.input_radio(
88
88
  lang('access_rules.labels.update'),
89
89
  :update_access,
90
90
  @access_rule.update_access,
91
- :values => @boolean_hash.invert
91
+ :values => @boolean_hash
92
92
  )
93
93
 
94
94
  f.input_radio(
95
95
  lang('access_rules.labels.delete'),
96
96
  :delete_access,
97
97
  @access_rule.delete_access,
98
- :values => @boolean_hash.invert
98
+ :values => @boolean_hash
99
99
  )
100
100
 
101
101
  f.g.div(:class => 'clearfix') do
@@ -49,10 +49,10 @@
49
49
  <td>#{rule.extension}</td>
50
50
  <?r end ?>
51
51
 
52
- <td>#{@boolean_hash[rule.create_access]}</td>
53
- <td>#{@boolean_hash[rule.read_access]}</td>
54
- <td>#{@boolean_hash[rule.update_access]}</td>
55
- <td>#{@boolean_hash[rule.delete_access]}</td>
52
+ <td>#{@boolean_hash.invert[rule.create_access]}</td>
53
+ <td>#{@boolean_hash.invert[rule.read_access]}</td>
54
+ <td>#{@boolean_hash.invert[rule.update_access]}</td>
55
+ <td>#{@boolean_hash.invert[rule.delete_access]}</td>
56
56
  <td>
57
57
  <?r if !rule.user_id.nil? ?>
58
58
  #{rule.user.name}
@@ -0,0 +1,172 @@
1
+ require __DIR__('error/plugin_error')
2
+
3
+ #:nodoc:
4
+ module Zen
5
+ ##
6
+ # Plugins in Zen are quite similar to packages except for a few differences. The biggest
7
+ # difference is that plugins won't update any Ramaze root directories or language
8
+ # direactories. This means that they can't have controllers, models and so on. On top
9
+ # of that they're nothing more than lambda's. Plugins are useful for supporting multiple
10
+ # markup formats (Markdown, Textile, etc) and other small tasks such as replacing Email
11
+ # addresses and so on.
12
+ #
13
+ # ## Creating Plugins
14
+ #
15
+ # Creating plugins works in a similar way as creating packages. Plugins are added by
16
+ # calling Zen::Plugin#add and passing a block to it with details such as the name of
17
+ # the plugin, the author, the identifier and a list of actions. The last two are very
18
+ # important as the plugin won't work without them.
19
+ #
20
+ # ### Actions
21
+ #
22
+ # Each plugin has a getter/setter called "actions", this is just a simple key/value
23
+ # hash where the keys are the names of the actions and the values lambda's. The keys
24
+ # should always be symbols. Example:
25
+ #
26
+ # actions = {
27
+ # :downcase => lambda do |string|
28
+ # string.downcase
29
+ # end
30
+ # }
31
+ #
32
+ # Note that you don't *have to* use lambda's, anything that responds to call() will do.
33
+ #
34
+ # Because the actions method contains just a hash you can easily add functionality to
35
+ # existing plugins as following:
36
+ #
37
+ # # First retrieve our plugin
38
+ # plugin = Zen::Plugin['com.something.plugin.name']
39
+ # plugin.actions[:my_action] = lamda do
40
+ # # Do something....
41
+ # end
42
+ #
43
+ # This can be very useful for extending plugins such as the markup plugin that's used to
44
+ # convert Markdown or Textile to HTML. By default this plugin only converts Markdown and
45
+ # Textile or HTML (it escapes all HTML) but by modifying the actions hash we can easily
46
+ # add new markup engines such as RDoc or even Latex.
47
+ #
48
+ # ## Calling Plugins
49
+ #
50
+ # Plugins can be called using Zen::Plugin#call, this method requires you to specify the
51
+ # plugin identifier, the action to call and optionally any data to send to the plugin.
52
+ # An example of calling a plugin would look like the following:
53
+ #
54
+ # Zen::Plugin.call('com.zen.plugin.markup', :markdown, 'hello **world**')
55
+ #
56
+ # ## Identifiers
57
+ #
58
+ # Plugin identifiers should always have the following format:
59
+ #
60
+ # com.VENDOR.plugin.NAME
61
+ #
62
+ # For example:
63
+ #
64
+ # com.zen.plugin.markup
65
+ #
66
+ # @author Yorick Peterse
67
+ # @since 0.2.4
68
+ # @attr_reader [Hash] plugins Hash containing all plugins.
69
+ #
70
+ module Plugin
71
+ class << self
72
+ attr_reader :plugins
73
+ end
74
+
75
+ ##
76
+ # Adds a new plugin with the given details.
77
+ #
78
+ # @example
79
+ # Zen::Plugin.add do |p|
80
+ # p.name = 'Markup'
81
+ # p.author = 'Yorick Peterse'
82
+ # p.actions = {
83
+ # :markdown => lambda do |markup|
84
+ # RDiscount.new(markup).to_html
85
+ # end
86
+ # end
87
+ #
88
+ # @author Yorick Peterse
89
+ # @since 0.2.4
90
+ # @yield [plugin] Struct object containing all the details of a plugin.
91
+ # @raise [Zen::PluginError] Error raised whenever the plugin already exists or is missing
92
+ # a certain setter.
93
+ #
94
+ def self.add
95
+ @plugins ||= {}
96
+ required = [:name, :author, :about, :identifier, :actions]
97
+ plugin = Zen::StrictStruct.new(
98
+ :name, :author, :about, :url, :identifier, :actions
99
+ ).new
100
+
101
+ yield plugin
102
+
103
+ # Check if all the required keys have been set
104
+ plugin.validate(required) do |k|
105
+ raise(Zen::PluginError, "The following plugin key is missing: #{k}")
106
+ end
107
+
108
+ # The actions getter should be a hash
109
+ if plugin.actions.class != Hash
110
+ raise(Zen::PluginError, "The actions setter/getter should be an instance of Hash.")
111
+ end
112
+
113
+ # Add our plugin
114
+ if !@plugins[plugin.identifier].nil?
115
+ raise(Zen::PluginError, "The plugin #{plugin.name} already exists.")
116
+ end
117
+
118
+ @plugins[plugin.identifier] = plugin
119
+ end
120
+
121
+ ##
122
+ # Returns a plugin for the given identifier.
123
+ #
124
+ # @example
125
+ # Zen::Plugin['com.zen.plugin.markup']
126
+ #
127
+ # @author Yorick Peterse
128
+ # @since 0.2.4
129
+ # @param [String] ident The plugin identifier.
130
+ # @raise Zen::PluginError Error that's raised when no plugins have been added yet or
131
+ # the specified plugin doesn't exist.
132
+ # @return [Struct] Instance of the plugin.
133
+ #
134
+ def self.[](ident)
135
+ if @plugins.nil?
136
+ raise(Zen::PluginError, "No plugins have been added.")
137
+ end
138
+
139
+ if !@plugins[ident]
140
+ raise(Zen::PluginError, "The plugin #{ident} doesn't exist.")
141
+ end
142
+
143
+ return @plugins[ident]
144
+ end
145
+
146
+ ##
147
+ # Calls the plugin for the given identifier and executes the action.
148
+ #
149
+ # @example
150
+ # Zen::Plugin.call('com.zen.foobar', :markdown, 'hello **world**')
151
+ #
152
+ # @author Yorick Peterse
153
+ # @since 0.2.4
154
+ # @param [String] ident The plugin identifier.
155
+ # @param [Symbol] action The plugin action to call.
156
+ # @param [Array] data Any data to pass to the plugin's action (a lambda).
157
+ # @return [Mixed]
158
+ #
159
+ def self.call(ident, action, *data)
160
+ plugin = self[ident]
161
+ action = action.to_sym
162
+
163
+ if !plugin.actions[action]
164
+ raise(Zen::PluginError, "The action #{action} doesn't exist for #{ident}.")
165
+ end
166
+
167
+ # Call the plugin and return it's value
168
+ return plugin.actions[action].call(*data)
169
+ end
170
+
171
+ end
172
+ end
@@ -0,0 +1,30 @@
1
+ Zen::Plugin.add do |plugin|
2
+ plugin.name = 'Markup'
3
+ plugin.author = 'Yorick Peterse'
4
+ plugin.about = 'Plugin used for converting various markup formats to HTML.'
5
+ plugin.identifier = 'com.zen.plugin.markup'
6
+ plugin.actions = {
7
+
8
+ # Converts HTML to, well, HTML.
9
+ :html => lambda do |markup|
10
+ markup
11
+ end,
12
+
13
+ # Converts the given markup to plain text by escaping all HTML
14
+ :plain => lambda do |markup|
15
+ include Ramaze::Helper::CGI
16
+ h(markup)
17
+ end,
18
+
19
+ # Comvert Markdown documents to HTML
20
+ :markdown => lambda do |markup|
21
+ RDiscount.new(markup).to_html
22
+ end,
23
+
24
+ # Convert Textile documents to HTML
25
+ :textile => lambda do |markup|
26
+ RedCloth.new(markup).to_html
27
+ end
28
+
29
+ }
30
+ end
@@ -103,6 +103,7 @@
103
103
  margin: 20px auto;
104
104
  width: 500px;
105
105
  }
106
+
106
107
  #login #container
107
108
  {
108
109
  margin-top: 50px;
@@ -116,7 +117,23 @@
116
117
  margin-top: 20px;
117
118
  text-align: center;
118
119
  }
120
+
119
121
  #main_footer p
120
122
  {
121
123
  margin-bottom: 8px;
124
+ margin: 0 auto 8px auto;
125
+ width: 300px;
126
+ }
127
+
128
+ #main_footer ul
129
+ {
130
+ list-style-type: none;
131
+ margin: 0 auto;
132
+ width: 300px;
122
133
  }
134
+ #main_footer ul li
135
+ {
136
+ float: left;
137
+ margin: 0px 8px;
138
+ text-align: center;
139
+ }
@@ -0,0 +1,36 @@
1
+ #:nodoc:
2
+ module Zen
3
+ ##
4
+ # StrictStruct is a simple extension of the Struct class, it provides a method that
5
+ # checks if all getters/setters have a value and if one doesn't it will call the
6
+ # appropriate block.
7
+ #
8
+ # @author Yorick Peterse
9
+ # @since 0.2.4
10
+ #
11
+ class StrictStruct < Struct
12
+
13
+ ##
14
+ # Validates all getter/setters in the current class to see if all values are set.
15
+ #
16
+ # @example
17
+ # struct = Zen::StrictStruct.new(:name, :age).new
18
+ # struct.validate([:name, :age]) do |k|
19
+ # puts "The key #{k} is required!"
20
+ # end
21
+ #
22
+ # @author Yorick Peterse
23
+ # @since 0.2.4
24
+ # @param [Array] required Array of getters that should return a value.
25
+ # @param [Block] block The block to call whenever an item doesn't have a value.
26
+ #
27
+ def validate(required, &block)
28
+ required.each do |k|
29
+ if !self.respond_to?(k) or self.send(k).nil?
30
+ block.call(k)
31
+ end
32
+ end
33
+ end
34
+
35
+ end
36
+ end
@@ -22,12 +22,17 @@ module Zen
22
22
  # @since 0.2
23
23
  #
24
24
  def migrate(show_output = true)
25
- exts = Zen::Package.extensions
25
+ exts = Zen::Package.packages
26
26
 
27
27
  puts "Migrating..." if show_output === true
28
28
 
29
29
  exts.each do |ident, ext|
30
- dir = ext.directory + '/../../migrations'
30
+ if ext.respond_to?(:migration_dir) and !ext.migration_dir.nil?
31
+ dir = ext.migration_dir
32
+ else
33
+ dir = ext.directory + '/../../migrations'
34
+ end
35
+
31
36
  table = ext.identifier.gsub('.', '_').to_sym
32
37
 
33
38
  if File.directory?(dir)
@@ -49,10 +54,15 @@ module Zen
49
54
  # @since 0.2
50
55
  #
51
56
  def delete
52
- exts = Zen::Package.extensions.map { |ident, ext| [ident, ext] }
57
+ exts = Zen::Package.packages.map { |ident, ext| [ident, ext] }
53
58
 
54
59
  exts.reverse.each do |ident, ext|
55
- dir = ext.directory + '/../../migrations'
60
+ if ext.respond_to?(:migration_dir) and !ext.migration_dir.nil?
61
+ dir = ext.migration_dir
62
+ else
63
+ dir = ext.directory + '/../../migrations'
64
+ end
65
+
56
66
  table = ext.identifier.gsub('.', '_').to_sym
57
67
 
58
68
  if File.directory?(dir)
@@ -14,19 +14,18 @@ module Zen
14
14
  desc('list', 'Lists all installed packages')
15
15
 
16
16
  ##
17
- # Lists all installed extensions.
17
+ # Lists all installed packages
18
18
  #
19
19
  # @author Yorick Peterse
20
20
  # @since 0.2
21
21
  #
22
22
  def list
23
23
  table = []
24
- table.push(['Name', 'Author', 'Identifier', 'Version', 'Type', 'Directory'])
25
- table.push(['------', '------', '------', '------', '------','------'])
26
- packages = Zen::Package.extensions.merge(Zen::Package.themes)
24
+ table.push(['Name', 'Author', 'Identifier', 'Directory'])
25
+ table.push(['------', '------', '------', '------'])
27
26
 
28
- packages.each do |ident, ext|
29
- table.push([ext.name, ext.author, ext.identifier, ext.version.to_s, ext.type, ext.directory])
27
+ Zen::Package.packages.each do |ident, ext|
28
+ table.push([ext.name, ext.author, ext.identifier, ext.directory])
30
29
  end
31
30
 
32
31
  print_table(table)
@@ -47,7 +46,7 @@ module Zen
47
46
  version = options[:version]
48
47
  ident = options[:identifier]
49
48
 
50
- if Zen::Package.extensions.nil? or Zen::Package.extensions.empty?
49
+ if Zen::Package.packages.nil? or Zen::Package.extensions.empty?
51
50
  abort "No packages have been loaded. Be sure to add them to config/requires.rb."
52
51
  end
53
52
 
@@ -61,7 +60,13 @@ module Zen
61
60
  abort "You specified an invalid identifier."
62
61
  end
63
62
 
64
- dir = install_ext.directory + '/../../migrations'
63
+ # Get the directory from the migration_dir getter, generate it if it isn't there.
64
+ if install_ext.respond_to?(:migration_dir) and !install_ext.migration_dir.nil?
65
+ dir = install_ext.migration_dir
66
+ else
67
+ dir = install_ext.directory + '/../../migrations'
68
+ end
69
+
65
70
  table = install_ext.identifier.gsub('.', '_').to_sym
66
71
 
67
72
  puts "Migrating package..."