dryml 1.3.3 → 1.4.0.pre2

Sign up to get free protection for your applications and to get access to all the features.
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