dryml 1.3.3 → 1.4.0.pre2

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 (44) hide show
  1. data/Gemfile +6 -0
  2. data/README +2 -0
  3. data/Rakefile +2 -1
  4. data/VERSION +1 -1
  5. data/cucumber.yml +9 -0
  6. data/dryml.gemspec +4 -2
  7. data/features/cookbook/01_simple_page_templates.feature +44 -0
  8. data/features/cookbook/02_defining_simple_tags.feature +375 -0
  9. data/features/cookbook/03_implicit_context.feature +229 -0
  10. data/features/cookbook/04_tag_attributes.feature +120 -0
  11. data/features/cookbook/05_repeated_and_optional_content.feature +241 -0
  12. data/features/cookbook/06_pseudo_parameters.feature +191 -0
  13. data/features/cookbook/07_nested_parameters.feature +147 -0
  14. data/features/cookbook/08_customizing_tags.feature +307 -0
  15. data/features/cookbook/09_aliasing_tags.feature +50 -0
  16. data/features/cookbook/10_polymorphic_tags.feature +168 -0
  17. data/features/cookbook/11_wrapping_content.feature +57 -0
  18. data/features/cookbook/12_local_and_scoped_variables.feature +102 -0
  19. data/features/doctest_examples.feature +187 -0
  20. data/features/merge_params.feature +36 -0
  21. data/features/replace_parameters.feature +21 -0
  22. data/features/static_tags.feature +91 -0
  23. data/features/step_definitions/contexts.rb +25 -0
  24. data/features/step_definitions/dom_comparison.rb +10 -0
  25. data/features/step_definitions/rendering.rb +21 -0
  26. data/features/support/env.rb +32 -0
  27. data/features/support/models/author.rb +18 -0
  28. data/features/support/models/blog_post.rb +37 -0
  29. data/features/support/models/discussion.rb +15 -0
  30. data/features/support/models/post.rb +12 -0
  31. data/features/support/strip_formatter.rb +14 -0
  32. data/lib/dryml/dryml_builder.rb +4 -14
  33. data/lib/dryml/dryml_doc.rb +6 -1
  34. data/lib/dryml/helper.rb +17 -1
  35. data/lib/dryml/part_context.rb +12 -15
  36. data/lib/dryml/railtie/template_handler.rb +1 -3
  37. data/lib/dryml/railtie.rb +1 -0
  38. data/lib/dryml/taglib.rb +24 -30
  39. data/lib/dryml/template.rb +32 -86
  40. data/lib/dryml/template_environment.rb +40 -17
  41. data/lib/dryml.rb +22 -11
  42. data/taglibs/core.dryml +18 -12
  43. data/taglibs/dryml.dryml +3 -0
  44. metadata +97 -56
@@ -0,0 +1,10 @@
1
+ Then /^the output DOM should be:$/ do |expected_html|
2
+ expected_rendered = ''
3
+ actual_rendered = ''
4
+ formatter = StripFormatter.new
5
+ # wrap in html tag, as REXML gets grumpy if there's more than one root node
6
+ formatter.write(REXML::Document.new("<html>#{expected_html}</html>"), expected_rendered)
7
+ formatter.write(REXML::Document.new("<html>#{@rendered_dom}</html>"), actual_rendered)
8
+ actual_rendered.should eq(expected_rendered)
9
+ end
10
+
@@ -0,0 +1,21 @@
1
+ When /^I render "([^"]*)"$/ do |file|
2
+ file_path = aruba_path(file)
3
+ file_data = File.read(file_path)
4
+ @locals ||= {}
5
+ @taglibs ||= []
6
+ @rendered_dom = Dryml.render(file_data, @locals, file_path, @taglibs)
7
+ Dryml::Template.clear_build_cache
8
+ end
9
+
10
+ When /^I include the taglib "([^"]*)"$/ do |file|
11
+ file_path = aruba_path(file+".dryml")
12
+ template_dir = File.dirname(file_path)
13
+ @taglibs ||= []
14
+ @taglibs << { :src => file, :absolute_template_path => template_dir }
15
+ end
16
+
17
+ Given /^the local variable "([^"]*)" has the value "([^"]*)"$/ do |var, value|
18
+ @locals ||= {}
19
+ @locals[var.to_sym] = value
20
+ end
21
+
@@ -0,0 +1,32 @@
1
+ lib = File.expand_path('../../../lib', __FILE__)
2
+ $:.unshift lib unless $:.include?(lib)
3
+
4
+ require 'bundler'
5
+ Bundler.setup
6
+ require 'aruba/cucumber'
7
+
8
+ require 'active_support'
9
+ require 'action_view'
10
+ require 'action_controller'
11
+
12
+ require 'dryml'
13
+ require 'dryml/railtie/template_handler'
14
+
15
+ def aruba_path(file_or_dir)
16
+ File.expand_path("../../../tmp/aruba/#{file_or_dir}", __FILE__)
17
+ end
18
+
19
+ After do
20
+ # muck out the caches
21
+ Dryml::Taglib.clear_cache
22
+ Dryml::Template.clear_build_cache
23
+ Dryml.clear_cache
24
+ end
25
+
26
+ # stub this
27
+ module Hobo
28
+ def self.root
29
+ 'no_such_path'
30
+ end
31
+ end
32
+
@@ -0,0 +1,18 @@
1
+ class Author
2
+ attr_accessor :id
3
+ attr_accessor :name
4
+
5
+ def initialize(options={})
6
+ self.id = options[:id] || 1
7
+ self.name = options[:name] || 'Nobody'
8
+ end
9
+
10
+ # needed for field= to work
11
+ def [](idx)
12
+ send(idx)
13
+ end
14
+
15
+ def url
16
+ "/authors/#{id}"
17
+ end
18
+ end
@@ -0,0 +1,37 @@
1
+ class BlogPost
2
+ attr_accessor :id
3
+ attr_accessor :title
4
+ attr_accessor :body
5
+ attr_accessor :published_at
6
+ attr_accessor :author
7
+
8
+ def initialize(options = {})
9
+ self.id = options[:id] || 1
10
+ self.title = options[:title] || 'A Blog Post'
11
+ self.body = options[:body] || 'Some body content'
12
+ self.published_at = options[:published_at] || Time.utc(2011,12,30,10,25)
13
+ self.author = Author.new(options[:author] || {})
14
+ end
15
+
16
+ # needed for field= to work
17
+ def [](idx)
18
+ send(idx)
19
+ end
20
+
21
+ def url
22
+ "/blog_posts/#{id}"
23
+ end
24
+
25
+ def name
26
+ title
27
+ end
28
+
29
+ end
30
+
31
+ class SpecialBlogPost < BlogPost
32
+
33
+ def url
34
+ "/special_blog_posts/#{id}"
35
+ end
36
+
37
+ end
@@ -0,0 +1,15 @@
1
+ class Discussion
2
+ attr_accessor :name
3
+ attr_accessor :posts
4
+
5
+ def initialize(options={})
6
+ self.name = options[:name] || 'Some Discussion'
7
+ self.posts = options[:posts] || []
8
+ end
9
+
10
+ # needed for field= to work
11
+ def [](idx)
12
+ send(idx)
13
+ end
14
+ end
15
+
@@ -0,0 +1,12 @@
1
+ class Post
2
+ attr_accessor :title
3
+
4
+ def initialize(options={})
5
+ self.title = options[:title] || 'A Post'
6
+ end
7
+
8
+ # needed for field= to work
9
+ def [](idx)
10
+ send(idx)
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ require 'rexml/document'
2
+ require 'rexml/formatters/default'
3
+
4
+ # strip whitespace when formatting XML
5
+
6
+ class StripFormatter < REXML::Formatters::Default
7
+
8
+ protected
9
+
10
+ def write_text(node, output)
11
+ output << node.to_s.strip
12
+ end
13
+
14
+ end
@@ -134,9 +134,6 @@ module Dryml
134
134
  when :module
135
135
  import_module(name.constantize, instruction[:as])
136
136
 
137
- when :set_theme
138
- set_theme(name)
139
-
140
137
  when :alias_method
141
138
  @environment.send(:alias_method, instruction[:new], instruction[:old])
142
139
 
@@ -154,10 +151,11 @@ module Dryml
154
151
  import_module(options[:module].constantize, options[:as])
155
152
  else
156
153
  template_dir = File.dirname(template_path)
157
- options = options.merge(:template_dir => template_dir)
154
+ options = options.merge(:template_dir => template_dir, :source_template => template_path)
158
155
 
159
- taglib = Taglib.get(options)
160
- taglib.import_into(@environment, options[:as])
156
+ Taglib.get(options).each do |taglib|
157
+ taglib.import_into(@environment, options[:as])
158
+ end
161
159
  end
162
160
  end
163
161
 
@@ -166,14 +164,6 @@ module Dryml
166
164
  raise NotImplementedError if as
167
165
  @environment.send(:include, mod)
168
166
  end
169
-
170
-
171
- def set_theme(name)
172
- if Hobo.current_theme.nil? or Hobo.current_theme == name
173
- Hobo.current_theme = name
174
- import_taglib(:src => "taglibs/themes/#{name}/#{name}")
175
- end
176
- end
177
167
  end
178
168
  end
179
169
 
@@ -32,12 +32,17 @@ require 'rexml/xpath'
32
32
 
33
33
  def initialize(home, filename, name=nil)
34
34
  @name = name || filename.sub(/.dryml$/, '')[home.length+1..-1]
35
+ @filename = filename
36
+ parse_file(filename)
37
+ end
38
+
39
+ def parse_file(filename)
35
40
  @source = File.read(filename)
36
41
  @doc = Dryml::Parser::Document.new(File.read(filename), filename)
37
42
  parse_tag_defs
38
43
  end
39
44
 
40
- attr_reader :name, :doc, :tag_defs, :source
45
+ attr_reader :name, :doc, :tag_defs, :source, :filename
41
46
 
42
47
  def comment
43
48
  first_node = doc[0][0]
data/lib/dryml/helper.rb CHANGED
@@ -1,5 +1,21 @@
1
1
  # An ActionView Helper
2
2
  module Dryml::Helper
3
+ def create_part_id(part_name, part_locals, binding)
4
+ locals={}
5
+ part_locals.split(',').each do |local|
6
+ local=local.strip
7
+ locals[local] = eval(local, binding)
8
+ end
9
+ key2=[typed_id, locals.to_yaml]
10
+ @part_ids ||= {}
11
+ if @part_ids[part_name]
12
+ @part_ids[part_name][key2] ||= "#{part_name}-#{@part_ids[part_name].length.to_s}"
13
+ else
14
+ @part_ids[part_name] = {key2 => part_name}
15
+ part_name
16
+ end
17
+ end
18
+
3
19
  def context_map(enum = this)
4
20
  # TODO: Calls to respond_to? in here can cause the full collection hiding behind a scoped collection to get loaded
5
21
  res = []
@@ -59,7 +75,7 @@ module Dryml::Helper
59
75
  def param_name_for_this(foreign_key=false)
60
76
  return "" unless form_this
61
77
  name = if foreign_key && (refl = this_field_reflection) && refl.macro == :belongs_to
62
- param_name_for(path_for_form_field[0..-2] + [refl.primary_key_name])
78
+ param_name_for(path_for_form_field[0..-2] + [refl.foreign_key])
63
79
  else
64
80
  param_name_for(path_for_form_field)
65
81
  end
@@ -13,16 +13,13 @@
13
13
  self.digest = 'SHA1'
14
14
 
15
15
 
16
- def self.client_side_storage(contexts, session)
17
- return "" if contexts.empty?
18
-
19
- contexts.map do |dom_id, context|
20
- code = context.marshal(session).split("\n").map{|line| "'#{line}\\n'"}.join(" +\n ")
21
- "hoboParts['#{dom_id}'] = (#{code});\n"
22
- end.join.html_safe
16
+ def self.client_side_storage_uncoded(contexts, session)
17
+ contexts.inject({}) do |h, (dom_id, context)|
18
+ h[dom_id] = context.marshal(session)
19
+ h
20
+ end
23
21
  end
24
22
 
25
-
26
23
  def self.pre_marshal(x)
27
24
  if x.is_a?(ActiveRecord::Base) && x.respond_to?(:typed_id)
28
25
  TypedId.new(x.typed_id)
@@ -75,9 +72,9 @@
75
72
 
76
73
  part_name, this_id, locals, form_field_path = context
77
74
 
78
- if RAILS_DEFAULT_LOGGER
79
- RAILS_DEFAULT_LOGGER.info "Call part: #{part_name}. this-id = #{this_id}, locals = #{locals.inspect}"
80
- RAILS_DEFAULT_LOGGER.info " : form_field_path = #{form_field_path.inspect}" if form_field_path
75
+ if Rails
76
+ Rails.logger.info "Call part: #{part_name}. this-id = #{this_id}, locals = #{locals.inspect}"
77
+ Rails.logger.info " : form_field_path = #{form_field_path.inspect}" if form_field_path
81
78
  end
82
79
 
83
80
  self.part_name = part_name
@@ -99,13 +96,13 @@
99
96
 
100
97
 
101
98
  def parse_this_id(page_this)
102
- if this_id == "this"
99
+ if this_id.nil? || this_id =="nil"
100
+ nil
101
+ elsif this_id == "this" || this_id == page_this.typed_id
103
102
  self.this = page_this
104
- elsif this_id =~ /^this:(.*)/
103
+ elsif this_id =~ /^this:(.*)/ || (page_this.typed_id && this_id =~ /^#{page_this.typed_id}:(.*)/)
105
104
  self.this = page_this
106
105
  self.this_field = $1
107
- elsif this_id == "nil"
108
- nil
109
106
  else
110
107
  parts = this_id.split(':')
111
108
  if parts.length == 3
@@ -1,8 +1,6 @@
1
1
  module Dryml
2
2
  class Railtie
3
- class TemplateHandler < ActionView::Template::Handler
4
-
5
- self.default_format = Mime::HTML
3
+ class TemplateHandler
6
4
 
7
5
  def self.call(template)
8
6
  "Dryml.call_render(self, local_assigns, '#{template.identifier}')"
data/lib/dryml/railtie.rb CHANGED
@@ -5,6 +5,7 @@ module Dryml
5
5
  require 'dryml'
6
6
  require 'dryml/template'
7
7
  require 'dryml/dryml_generator'
8
+ require 'dryml/railtie/page_tag_resolver'
8
9
  end
9
10
 
10
11
  ActiveSupport.on_load(:action_controller) do
data/lib/dryml/taglib.rb CHANGED
@@ -7,15 +7,16 @@
7
7
  class << self
8
8
 
9
9
  def get(options)
10
- src_file = taglib_filename(options)
11
- taglib = @cache[src_file]
12
- if taglib
13
- taglib.reload
14
- else
15
- taglib = Taglib.new(src_file)
16
- @cache[src_file] = taglib
10
+ taglib_filenames(options).map do |src_file|
11
+ taglib = @cache[src_file]
12
+ if taglib
13
+ taglib.reload
14
+ else
15
+ taglib = Taglib.new(src_file)
16
+ @cache[src_file] = taglib
17
+ end
18
+ taglib
17
19
  end
18
- taglib
19
20
  end
20
21
 
21
22
  def clear_cache
@@ -32,32 +33,25 @@
32
33
  # If the plugin defines different taglibs you must also specify the src attribute of the taglib that you want
33
34
  # to include: <include gem='gem_name' src='taglib_name'/>'
34
35
 
35
- def taglib_filename(options)
36
+ def taglib_filenames(options)
36
37
  plugin = options[:plugin]
37
38
  gem = options[:gem]
38
39
  app_root = Object.const_defined?(:Rails) ? Rails.root : Pathname.new(File.expand_path('.'))
39
- taglibs_path = case
40
- when plugin == 'dryml'
41
- Dryml.root.join 'taglibs'
42
- when plugin == 'hobo', gem == 'hobo'
43
- Hobo.root.join 'lib/hobo/rapid/taglibs'
44
- when !plugin.blank?
45
- app_root.join 'vendor/plugins', plugin, 'taglibs'
46
- when !gem.blank?
47
- gem.tr('-','_').camelize.constantize.root.join 'taglibs'
48
- when options[:src] =~ /\//
49
- app_root.join 'app/views'
50
- when options[:template_dir] =~ /^#{Hobo.root}/
51
- Pathname.new(options[:template_dir])
52
- when options[:absolute_template_path]
53
- Pathname.new(options[:absolute_template_path])
54
- else
55
- app_root.join options[:template_dir].gsub(/^\//, '') # remove leading / if there is one
56
- end
40
+ search_path = []
41
+ search_path << Dryml.root.join('taglibs') if plugin == 'dryml'
42
+ search_path << Hobo.root.join('lib/hobo/rapid/taglibs') if plugin == 'hobo' || gem == 'hobo'
43
+ search_path << app_root.join('vendor/plugins', plugin, 'taglibs') if !plugin.blank?
44
+ search_path << gem.tr('-','_').camelize.constantize.root.join('taglibs') if !gem.blank?
45
+ search_path << app_root.join('app/views') if options[:src] =~ /\//
46
+ search_path << Pathname.new(options[:absolute_template_path]) if options[:absolute_template_path]
47
+ search_path << Pathname.new(options[:template_dir]) if options[:template_dir] =~ /^\//
48
+ search_path << app_root.join(options[:template_dir].gsub(/^\//, ''))
57
49
  src = options[:src] || gem || plugin
58
- taglib_file = taglibs_path.join "#{src}.dryml"
59
- raise DrymlException, "No such taglib: #{src} #{options.inspect} #{taglib_file}" unless taglib_file.exist?
60
- taglib_file.to_s
50
+ results = nil
51
+ search_path.any? {|path| !(results = Dir[path.join "#{src}.dryml"]).empty?}
52
+ raise DrymlException, "No such taglib: #{src} #{options.inspect}" if results.empty?
53
+ results - [File.expand_path(options[:source_template])]
54
+
61
55
  end
62
56
 
63
57
  end