dryml 1.1.0 → 1.3.0.RC

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.
data/Rakefile CHANGED
@@ -2,26 +2,17 @@ require 'rake'
2
2
  require 'rake/rdoctask'
3
3
  require 'rake/testtask'
4
4
 
5
- $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), '/lib')
6
- $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), '/../hobosupport/lib')
7
- require 'dryml' # to get VERSION
8
-
9
5
  RUBY = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']).sub(/.*\s.*/m, '"\&"')
10
- if defined?(Bundler)
11
- RUBYDOCTEST = 'bundle exec rubydoctest'
12
- else
13
- RUBYDOCTEST = ENV['RUBYDOCTEST'] || "#{RUBY} -S rubydoctest"
14
- end
15
-
16
- desc "Default Task"
17
- task :default => [ :test ]
6
+ RUBYDOCTEST = ENV['RUBYDOCTEST'] || "#{RUBY} -S rubydoctest"
18
7
 
19
8
  # --- Testing --- #
20
9
 
21
- desc "Run all tests"
22
- task :test do |t|
23
- files=Dir['test/*.rdoctest'].map {|f| File.expand_path(f)}.join(' ')
24
- exit(1) if !system("#{RUBYDOCTEST} #{files}")
10
+ namespace "test" do
11
+ desc "Run the doctests"
12
+ task :doctest do |t|
13
+ files=Dir['test/**/*.rdoctest'].map {|f| File.expand_path(f)}.join(' ')
14
+ exit(1) if !system("#{RUBYDOCTEST} #{files}")
15
+ end
25
16
  end
26
17
 
27
18
  # --- RDOC --- #
@@ -30,19 +21,3 @@ require 'yard'
30
21
  YARD::Rake::YardocTask.new do |t|
31
22
  t.files = ['lib/**/*.rb', 'README', 'LICENSE.txt', 'CHANGES.txt']
32
23
  end
33
-
34
- # --- Packaging and Rubyforge & gemcutter & github--- #
35
-
36
- require 'jeweler'
37
- Jeweler::Tasks.new do |gemspec|
38
- gemspec.version = Dryml::VERSION
39
- gemspec.name = "dryml"
40
- gemspec.email = "tom@tomlocke.com"
41
- gemspec.summary = "The web app builder for Rails"
42
- gemspec.homepage = "http://hobocentral.net/"
43
- gemspec.authors = ["Tom Locke"]
44
- gemspec.rubyforge_project = "hobo"
45
- gemspec.add_dependency("hobosupport", ["= #{Dryml::VERSION}"])
46
- gemspec.add_dependency("actionpack", [">= 2.2.2", "< 3.0.0"])
47
- end
48
- Jeweler::GemcutterTasks.new
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.3.0.RC
data/dryml.gemspec CHANGED
@@ -1,72 +1,28 @@
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 -*-
1
+ name = File.basename( __FILE__, '.gemspec' )
2
+ version = File.read(File.expand_path('../VERSION', __FILE__)).strip
3
+ require 'date'
5
4
 
6
5
  Gem::Specification.new do |s|
7
- s.name = %q{dryml}
8
- s.version = "1.1.0"
9
6
 
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Tom Locke"]
12
- s.date = %q{2011-11-15}
13
- s.email = %q{tom@tomlocke.com}
14
- s.extra_rdoc_files = [
15
- "README"
16
- ]
17
- s.files = [
18
- "CHANGES.txt",
19
- "LICENSE.txt",
20
- "README",
21
- "Rakefile",
22
- "TODO.txt",
23
- "dryml.gemspec",
24
- "lib/dryml.rb",
25
- "lib/dryml/dryml_builder.rb",
26
- "lib/dryml/dryml_doc.rb",
27
- "lib/dryml/dryml_generator.rb",
28
- "lib/dryml/dryml_support_controller.rb",
29
- "lib/dryml/helper.rb",
30
- "lib/dryml/parser.rb",
31
- "lib/dryml/parser/attribute.rb",
32
- "lib/dryml/parser/base_parser.rb",
33
- "lib/dryml/parser/document.rb",
34
- "lib/dryml/parser/element.rb",
35
- "lib/dryml/parser/elements.rb",
36
- "lib/dryml/parser/source.rb",
37
- "lib/dryml/parser/text.rb",
38
- "lib/dryml/parser/tree_parser.rb",
39
- "lib/dryml/part_context.rb",
40
- "lib/dryml/scoped_variables.rb",
41
- "lib/dryml/static_tags",
42
- "lib/dryml/tag_parameters.rb",
43
- "lib/dryml/taglib.rb",
44
- "lib/dryml/template.rb",
45
- "lib/dryml/template_environment.rb",
46
- "lib/dryml/template_handler.rb",
47
- "taglibs/core.dryml",
48
- "test/dryml.rdoctest"
49
- ]
50
- s.homepage = %q{http://hobocentral.net/}
7
+ s.authors = ['Tom Locke']
8
+ s.email = 'tom@tomlocke.com'
9
+ s.homepage = 'http://hobocentral.net'
10
+ s.rubyforge_project = 'hobo'
11
+ s.summary = "The Don't Repeat Yourself Markup Language"
12
+ s.description = "The Don't Repeat Yourself Markup Language"
13
+
14
+ s.add_runtime_dependency('actionpack', ["~> 3.0.0"])
15
+ s.add_runtime_dependency('hobo_support', ["= #{version}"])
16
+ s.add_development_dependency('rubydoctest', [">= 0"])
17
+
18
+ s.files = `git ls-files -x #{name}/* -z`.split("\0")
19
+
20
+ s.name = File.basename( __FILE__, '.gemspec' )
21
+ s.version = version
22
+ s.date = Date.today.to_s
23
+
24
+ s.required_rubygems_version = ">= 1.3.6"
51
25
  s.rdoc_options = ["--charset=UTF-8"]
52
26
  s.require_paths = ["lib"]
53
- s.rubyforge_project = %q{hobo}
54
- s.rubygems_version = %q{1.4.2}
55
- s.summary = %q{The web app builder for Rails}
56
-
57
- if s.respond_to? :specification_version then
58
- s.specification_version = 3
59
27
 
60
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
61
- s.add_runtime_dependency(%q<hobosupport>, ["= 1.1.0"])
62
- s.add_runtime_dependency(%q<actionpack>, [">= 2.2.2", "< 3.0.0"])
63
- else
64
- s.add_dependency(%q<hobosupport>, ["= 1.1.0"])
65
- s.add_dependency(%q<actionpack>, [">= 2.2.2", "< 3.0.0"])
66
- end
67
- else
68
- s.add_dependency(%q<hobosupport>, ["= 1.1.0"])
69
- s.add_dependency(%q<actionpack>, [">= 2.2.2", "< 3.0.0"])
70
- end
71
28
  end
72
-
@@ -58,19 +58,16 @@ module Dryml
58
58
  end
59
59
 
60
60
 
61
- def erb_process(erb_src, method_def=false)
61
+ def erb_process(erb_src)
62
62
  trim_mode = ActionView::TemplateHandlers::ERB.erb_trim_mode
63
63
  erb = ERB.new(erb_src, nil, trim_mode, "output_buffer")
64
- src = erb.src.split(';')[1..-2].join(';')
65
-
66
- if method_def
67
- src.sub /^\s*def.*?\(.*?\)/, '\0 __in_erb_template=true; '
68
- else
69
- "__in_erb_template=true; " + src
64
+ res = erb.src.split(';')[1..-2].join(';')
65
+ if res.respond_to? :force_encoding
66
+ res.force_encoding(erb_src.encoding)
70
67
  end
68
+ res
71
69
  end
72
70
 
73
-
74
71
  def build(local_names, auto_taglibs, src_mtime)
75
72
 
76
73
  auto_taglibs.each { |t| import_taglib(t) }
@@ -82,7 +79,7 @@ module Dryml
82
79
  @environment.class_eval(instruction[:src], template_path, instruction[:line_num])
83
80
 
84
81
  when :def
85
- src = erb_process(instruction[:src], true)
82
+ src = erb_process(instruction[:src])
86
83
  @environment.class_eval(src, template_path, instruction[:line_num])
87
84
 
88
85
  when :render_page
@@ -138,3 +135,4 @@ module Dryml
138
135
  end
139
136
  end
140
137
  end
138
+
@@ -4,20 +4,20 @@ require 'rexml/xpath'
4
4
 
5
5
  # DrymlDoc provides the facility to parse a directory tree of DRYML taglibs, building a collection of objects that provide metadata
6
6
  module DrymlDoc
7
-
7
+
8
8
  def self.load_taglibs(directory, taglib_class=DrymlDoc::Taglib)
9
9
  dryml_files = Dir["#{directory}/**/*.dryml"]
10
10
 
11
11
  dryml_files.map { |f| taglib_class.new(directory, f) }
12
12
  end
13
-
13
+
14
14
  CommentMethods = classy_module do
15
-
15
+
16
16
  def comment_intro
17
17
  comment && comment =~ /(.*?)^#/m ? $1 : comment
18
18
  end
19
19
 
20
-
20
+
21
21
  def comment_rest
22
22
  comment && comment[comment_intro.length..-1]
23
23
  end
@@ -25,20 +25,20 @@ require 'rexml/xpath'
25
25
  %w(comment comment_intro comment_rest).each do |m|
26
26
  class_eval "def #{m}_html; Maruku.new(#{m}).to_html.gsub(/&amp;/, '&'); end"
27
27
  end
28
-
28
+
29
29
  end
30
-
30
+
31
31
  class Taglib
32
-
32
+
33
33
  def initialize(home, filename, name=nil)
34
34
  @name = name || filename.sub(/.dryml$/, '')[home.length+1..-1]
35
35
  @source = File.read(filename)
36
36
  @doc = Dryml::Parser::Document.new(File.read(filename), filename)
37
37
  parse_tag_defs
38
38
  end
39
-
39
+
40
40
  attr_reader :name, :doc, :tag_defs, :source
41
-
41
+
42
42
  def comment
43
43
  first_node = doc[0][0]
44
44
  if first_node.is_a?(REXML::Comment)
@@ -48,41 +48,41 @@ require 'rexml/xpath'
48
48
  text.match(/<%#(.*?)%>/m)[1] rescue nil
49
49
  end
50
50
  end
51
-
51
+
52
52
  include CommentMethods
53
-
54
- private
55
-
53
+
54
+ private
55
+
56
56
  def tagdef_class
57
57
  self.class.parent.const_get('TagDef')
58
58
  end
59
-
59
+
60
60
  def parse_tag_defs
61
61
  @tag_defs = []
62
62
  REXML::XPath.match(doc, '/*/*[@tag]').each { |node| @tag_defs << tagdef_class.new(self, node) }
63
63
  end
64
-
64
+
65
65
  end
66
-
66
+
67
67
  class TagDef
68
-
68
+
69
69
  def initialize(taglib, node)
70
70
  @taglib = taglib
71
71
  @node = node
72
72
  end
73
-
73
+
74
74
  attr_reader :taglib, :node
75
75
  delegate :doc, :to => :taglib
76
-
77
-
76
+
77
+
78
78
  def name
79
79
  node.attributes['tag']
80
80
  end
81
-
81
+
82
82
  def source
83
83
  doc.restore_erb_scriptlets(node.to_s).strip
84
84
  end
85
-
85
+
86
86
  # The contents of the XML or ERB comment, if any, immediately above the tag definition
87
87
  def comment
88
88
  @comment ||= begin
@@ -98,19 +98,19 @@ require 'rexml/xpath'
98
98
  end
99
99
  end
100
100
  end
101
-
101
+
102
102
  include CommentMethods
103
-
103
+
104
104
  def no_doc?
105
105
  comment =~ /^nodoc\b/
106
106
  end
107
-
107
+
108
108
  # An array of the arrtibute names defined by this tag
109
109
  def attributes
110
110
  (node.attributes['attrs'] || "").split(/\s*,\s*/).where_not.blank?
111
111
  end
112
-
113
-
112
+
113
+
114
114
  # Returns a recursive array srtucture, where each item in the array is a pair: [parameter_name, sub_parameters]
115
115
  # (sub-parameters is the same kind of structure)
116
116
  def parameters(element=node)
@@ -125,40 +125,40 @@ require 'rexml/xpath'
125
125
  end
126
126
  result
127
127
  end
128
-
129
-
128
+
129
+
130
130
  # Is this the base definition of a polymorphic tag
131
131
  def polymorphic?
132
132
  node.attributes['polymorphic'].present?
133
133
  end
134
-
134
+
135
135
  # Is this an <extend>?
136
136
  def extension?
137
137
  node.name == "extend"
138
138
  end
139
-
140
-
139
+
140
+
141
141
  # The definition's 'for' attribute
142
142
  def for_type
143
143
  node.attributes['for']
144
144
  end
145
-
145
+
146
146
 
147
147
  # The name of the tag, if any, that this definition merges its parameters into
148
148
  # That is, the tag with 'merge' or 'merge-params' declared
149
149
  def merge_params
150
150
  REXML::XPath.first(node, ".//*[@merge|@merge-params]")._?.name
151
151
  end
152
-
152
+
153
153
  # The name of the tag, if any, that this definition merges its attributes into
154
- # That is, the tag with 'merge' or 'merge-attrs' declared
154
+ # That is, the tag with 'merge' or 'merge-attrs' declared
155
155
  def merge_attrs
156
156
  REXML::XPath.first(node, ".//*[@merge|@merge-attrs]")._?.name
157
157
  end
158
-
158
+
159
159
  end
160
-
161
-
160
+
161
+
162
162
  end
163
-
163
+
164
164
  end
@@ -2,82 +2,56 @@
2
2
  require 'set'
3
3
  require 'fileutils'
4
4
 
5
- require 'action_controller/dispatcher'
6
-
7
5
  module Dryml
8
-
6
+
9
7
  class DrymlGenerator
10
-
8
+
11
9
  HEADER = "<!-- AUTOMATICALLY GENERATED FILE - DO NOT EDIT -->\n\n"
12
-
10
+
13
11
  class << self
14
- attr_accessor :run_on_every_request
15
12
  attr_accessor :output_directory
16
13
  end
17
-
14
+
18
15
  def self.enable(generator_directories = [], output_directory = nil)
19
16
  @output_directory = output_directory
20
- @output_directory ||= "#{RAILS_ROOT}/app/views/taglibs/auto" if defined? :RAILS_ROOT
17
+ @output_directory ||= "#{Rails.root}/app/views/taglibs/auto" if Object.const_defined?(:Rails)
21
18
  @generator_directories = generator_directories
22
-
23
- # Unfortunately the dispatcher callbacks don't give us the hook we need (after routes are reloaded)
24
- # so we have to alias_method_chain
25
- ActionController::Dispatcher.class_eval do
26
-
27
- if respond_to? :reload_application
28
- #Rails 2.3
29
- class << self
30
- def reload_application_with_dryml_generators
31
- reload_application_without_dryml_generators
32
- DrymlGenerator.run unless Dryml::DrymlGenerator.run_on_every_request == false || Rails.env.production?
33
- end
34
- alias_method_chain :reload_application, :dryml_generators
35
- end
36
- else
37
- #Rails <= 2.2
38
- def reload_application_with_dryml_generators
39
- reload_application_without_dryml_generators
40
- DrymlGenerator.run unless Dryml::DrymlGenerator.run_on_every_request == false || Rails.env.production?
41
- end
42
- alias_method_chain :reload_application, :dryml_generators
43
- end
44
- end
45
19
  end
46
-
20
+
47
21
  def self.run(generator_directories=nil, output_directory=nil)
48
22
  @generator_directories ||= generator_directories
49
23
  @output_directory ||= output_directory
50
- @generator ||= DrymlGenerator.new(generator_directories || @generator_directories)
24
+ @generator ||= new(generator_directories || @generator_directories)
51
25
  @generator.run
52
26
  end
53
-
54
-
27
+
28
+
55
29
  def initialize(generator_directories=nil)
56
30
  @templates = {}
57
31
  @digests = {}
58
32
  generator_directories ||= Dryml::DrymlGenerator.generator_directories
59
33
  load_templates(generator_directories)
60
34
  end
61
-
35
+
62
36
  attr_accessor :subsite
63
-
64
-
37
+
38
+
65
39
  def load_templates(generator_directories)
66
- generator_directories.each do |dir|
67
- Dir["#{dir}/**/*.dryml.erb"].each do |f|
40
+ generator_directories.each do |path|
41
+ dir = path.to_s
42
+ Dir.glob("#{dir}/**/*.dryml.erb").each do |f|
68
43
  name = f[dir.length + 1..-11]
69
44
  erb = File.read(f)
70
45
  @templates[name] = ERB.new(erb, nil, '-').src
71
-
72
46
  # Create output directories and parents as required
73
- [nil, *Hobo.subsites].each do |s|
47
+ [nil, *Hobo.subsites].each do |s|
74
48
  FileUtils.mkdir_p(File.dirname("#{output_dir s}/#{name}"))
75
49
  end
76
50
  end
77
51
  end
78
52
  end
79
-
80
-
53
+
54
+
81
55
  def run
82
56
  # FIXME
83
57
  # Ensure all view hints loaded before running
@@ -89,21 +63,21 @@ require 'action_controller/dispatcher'
89
63
 
90
64
  subsites.each { |s| run_for_subsite(s) }
91
65
  end
92
-
93
-
66
+
67
+
94
68
  def run_for_subsite(subsite)
95
69
  self.subsite = subsite
96
70
  @templates.each_pair do |name, src|
97
71
  run_one(name, src)
98
- end
72
+ end
99
73
  end
100
-
101
-
74
+
75
+
102
76
  def output_dir(s=subsite)
103
77
  s ? "#{Dryml::DrymlGenerator.output_directory}/#{s}" : Dryml::DrymlGenerator.output_directory
104
78
  end
105
-
106
-
79
+
80
+
107
81
  def run_one(name, src)
108
82
  dryml = instance_eval(src, name)
109
83
  if dryml_changed?(name, dryml)
@@ -111,8 +85,8 @@ require 'action_controller/dispatcher'
111
85
  File.open("#{output_dir}/#{name}.dryml", 'w') { |f| f.write(out) }
112
86
  end
113
87
  end
114
-
115
-
88
+
89
+
116
90
  def dryml_changed?(name, dryml)
117
91
  key = "#{subsite}/#{name}"
118
92
  d = digest dryml
@@ -123,27 +97,27 @@ require 'action_controller/dispatcher'
123
97
  false
124
98
  end
125
99
  end
126
-
127
-
100
+
101
+
128
102
  def digest(s)
129
103
  OpenSSL::Digest::SHA1.hexdigest(s)
130
104
  end
131
-
132
-
105
+
106
+
133
107
  # --- Helper methods for the templates --- #
134
-
108
+
135
109
  attr_reader :controller
136
-
137
-
110
+
111
+
138
112
  def controllers
139
- Hobo::ModelController.all_controllers(subsite).sort_by &:name
113
+ Hobo::Controller::Model.all_controllers(subsite).sort_by &:name
140
114
  end
141
-
142
-
143
- def models
115
+
116
+
117
+ def models
144
118
  Hobo::Model.all_models.sort_by &:name
145
119
  end
146
-
120
+
147
121
  def each_controller
148
122
  controllers.each do |controller|
149
123
  @controller = controller
@@ -151,8 +125,8 @@ require 'action_controller/dispatcher'
151
125
  end
152
126
  @controller = nil
153
127
  end
154
-
155
-
128
+
129
+
156
130
  def each_model
157
131
  models.each do |model|
158
132
  @model = model
@@ -160,15 +134,17 @@ require 'action_controller/dispatcher'
160
134
  end
161
135
  @model = nil
162
136
  end
163
-
164
-
137
+
138
+
165
139
  def model
166
140
  @model || @controller.model
167
141
  end
168
-
169
-
142
+
143
+ # This method is used only to generate static default Model names in english only
144
+ # it does not provide any translation
145
+ # Localized apps will override the defaults by setting the specific keys in their locale files
170
146
  def model_name(*options)
171
- name = :plural.in?(options) ? model.view_hints.model_name_plural : model.view_hints.model_name
147
+ name = :plural.in?(options) ? model.model_name.human(:count=>2, :locale=>:en) : model.model_name.human(:locale=>:en)
172
148
  name = name.titleize.downcase if :lowercase.in?(options)
173
149
  name = name.camelize if :camel.in?(options)
174
150
  name
@@ -179,18 +155,18 @@ require 'action_controller/dispatcher'
179
155
  def sq_escape(s)
180
156
  s.gsub(/[\\]/, "\\\\\\\\").gsub(/'/, "\\\\'")
181
157
  end
182
-
183
-
158
+
159
+
184
160
  def model_class
185
161
  model.name.underscore.gsub('_', '-').gsub('/', '--')
186
162
  end
187
-
188
-
163
+
164
+
189
165
  def view_hints
190
166
  model.view_hints
191
167
  end
192
168
 
193
-
169
+
194
170
  def through_collection_names(klass=model)
195
171
  klass.reflections.values.select do |refl|
196
172
  refl.macro == :has_many && refl.options[:through]
@@ -206,8 +182,8 @@ require 'action_controller/dispatcher'
206
182
  else
207
183
  args
208
184
  end
209
- Hobo::ModelRouter.linkable?(klass, action, options)
210
- end
185
+ Hobo::Routes.linkable?(klass, action, options)
186
+ end
211
187
 
212
188
 
213
189
  def sortable_collection?(collection, model=self.model)
@@ -218,20 +194,21 @@ require 'action_controller/dispatcher'
218
194
  if defined? ActiveRecord::Acts::List::InstanceMethods
219
195
  refl = model.reflections[collection]
220
196
  klass = refl.klass
221
- klass < ActiveRecord::Acts::List::InstanceMethods &&
197
+ klass < ActiveRecord::Acts::List::InstanceMethods &&
198
+ klass.table_exists? &&
222
199
  klass.new.position_column == refl.options[:order].to_s
223
200
  end
224
201
  end
225
-
226
-
202
+
203
+
227
204
  def standard_fields(*args)
228
205
  klass = args.first.is_a?(Class) ? args.shift : model
229
206
  extras = args
230
-
231
- fields = klass.attr_order.*.to_s & klass.content_columns.*.name
207
+
208
+ fields = klass.attr_order.*.to_s & (klass.table_exists? ? klass.content_columns.*.name : [])
232
209
 
233
210
  fields -= %w{created_at updated_at created_on updated_on deleted_at} unless extras.include?(:include_timestamps)
234
-
211
+
235
212
  bt = extras.include?(:belongs_to)
236
213
  hm = extras.include?(:has_many)
237
214
  klass.reflections.values.sort_by { |refl| refl.name.to_s }.map do |refl|
@@ -242,30 +219,30 @@ require 'action_controller/dispatcher'
242
219
  fields.reject! { |f| model.never_show? f }
243
220
  fields
244
221
  end
245
-
246
-
222
+
223
+
247
224
  def creators
248
225
  defined?(model::Lifecycle) ? model::Lifecycle.publishable_creators : []
249
226
  end
250
-
227
+
251
228
  def transitions
252
229
  defined?(model::Lifecycle) ? model::Lifecycle.publishable_transitions : []
253
230
  end
254
-
231
+
255
232
  def creator_names
256
233
  creators.map { |c| c.name.to_s }
257
234
  end
258
-
235
+
259
236
  def transition_names
260
237
  transitions.map { |t| t.name.to_s }.uniq
261
238
  end
262
-
263
-
239
+
240
+
264
241
  def a_or_an(word)
265
242
  (word =~ /^[aeiou]/i ? "an " : "a ") + word
266
243
  end
267
-
244
+
268
245
  end
269
-
246
+
270
247
  end
271
248