template-inheritance 0.0.0.0.0.0.0.0.1 → 0.1

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 (49) hide show
  1. data/.gitignore +9 -0
  2. data/README.textile +18 -1
  3. data/example/base.html.haml +31 -0
  4. data/example/example.rb +16 -0
  5. data/example/shared/google_analytics.html.haml +8 -0
  6. data/example/site/_wtf.html.haml +3 -0
  7. data/example/site/base.html.haml +38 -0
  8. data/example/site/post.html.haml +17 -0
  9. data/lib/template-inheritance.rb +118 -0
  10. data/lib/template-inheritance/exts/haml.rb +33 -0
  11. data/lib/template-inheritance/exts/tilt.rb +29 -0
  12. data/lib/template-inheritance/helpers.rb +144 -0
  13. data/spec/spec.opts +5 -0
  14. data/spec/spec_helper.rb +51 -0
  15. data/spec/stubs/block/block.html.haml +2 -0
  16. data/spec/stubs/block/blocks.html.haml +5 -0
  17. data/spec/stubs/block/error.html.haml +2 -0
  18. data/spec/stubs/block/getter.html.haml +3 -0
  19. data/spec/stubs/block/value.html.haml +1 -0
  20. data/spec/stubs/context_id.html.haml +1 -0
  21. data/spec/stubs/enhance_block/basic.html.haml +5 -0
  22. data/spec/stubs/enhance_block/error.html.haml +3 -0
  23. data/spec/stubs/enhance_block/name_error.html.haml +1 -0
  24. data/spec/stubs/enhance_block/nil.html.haml +3 -0
  25. data/spec/stubs/enhance_block/standalone.html.haml +2 -0
  26. data/spec/stubs/extend_block/basic.html.haml +5 -0
  27. data/spec/stubs/extend_block/error.html.haml +5 -0
  28. data/spec/stubs/extend_block/error2.html.haml +1 -0
  29. data/spec/stubs/extend_block/name_error.html.haml +1 -0
  30. data/spec/stubs/extend_block/nil.html.haml +4 -0
  31. data/spec/stubs/includes/base.html.haml +1 -0
  32. data/spec/stubs/includes/basic.html.haml +1 -0
  33. data/spec/stubs/includes/includes.html.haml +7 -0
  34. data/spec/stubs/includes/integration.html.haml +4 -0
  35. data/spec/stubs/includes/integration2.html.haml +4 -0
  36. data/spec/stubs/index.html.haml +1 -0
  37. data/spec/stubs/inheritance/basic/base.html.haml +2 -0
  38. data/spec/stubs/inheritance/basic/index.html.haml +2 -0
  39. data/spec/stubs/inheritance/capture/haml/base.html.haml +2 -0
  40. data/spec/stubs/inheritance/capture/haml/index.html.haml +3 -0
  41. data/spec/stubs/library.html.haml +3 -0
  42. data/spec/stubs/test.html.haml +1 -0
  43. data/spec/stubs/variables.html.haml +1 -0
  44. data/spec/templates/exts/haml_spec.rb +0 -0
  45. data/spec/templates/exts/tilt_spec.rb +0 -0
  46. data/spec/templates/helpers_spec.rb +139 -0
  47. data/spec/templates/template_spec.rb +61 -0
  48. data/template-inheritance.gemspec +42 -0
  49. metadata +66 -10
@@ -0,0 +1,9 @@
1
+ /*.gem
2
+
3
+ .DS_Store
4
+ .cache
5
+ .yardoc
6
+
7
+ script/*
8
+ .bundle
9
+ .rvmrc
@@ -1,3 +1,20 @@
1
1
  h1. About
2
2
 
3
- Currently this is just a placeholder, but in the future you can expect here a framework-agnostic template inheritance implementation from Rango.
3
+ This is a framework-agnostic template inheritance engine from Rango.
4
+
5
+ h1. Usage
6
+
7
+ <pre>
8
+ require "template-inheritance"
9
+
10
+ TemplateInheritance::Template.paths &lt;&lt; File.expand_path("..", __FILE__)
11
+
12
+ template = TemplateInheritance::Template.new("site/post.html.haml")
13
+ template.render(post: post)
14
+ </pre>
15
+
16
+ h1. Haml Extensions
17
+
18
+ <pre>
19
+ Tilt::HamlTemplate.options[:default_attributes] = {form: {method: "post"}}
20
+ </pre>
@@ -0,0 +1,31 @@
1
+ !!! 5
2
+
3
+ / Why should be poor templates so low-level?
4
+ / Even they deserve their Kernel#require!
5
+ - includes "shared/google_analytics.html"
6
+
7
+ %html
8
+ %head
9
+ / This is a great fun, the content for the block value
10
+ / can be just anything, not just some dumb string.
11
+ / The default value is there just in case that no
12
+ / scripts would be provided in children templates.
13
+ - block(:scripts, Array.new).each do |script|
14
+ %script{src: "/scripts/#{script}"}
15
+ %body
16
+ / Just to make sure that the default value for
17
+ / method works (as defined in example.rb).
18
+ %form{action: "/search"}
19
+
20
+ = block(:google_analytics)
21
+ = block(:main) do
22
+ / This is default content for the 'main' block.
23
+ / In case that we wouldn't fill in the block in
24
+ / any of child templates, the default content
25
+ / would be rendered. If we fill in the block,
26
+ / the default content is ignored.
27
+
28
+ / We can use either block(name, content)
29
+ / or block(name) { content }.
30
+
31
+ No content yet.
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+
3
+ $LOAD_PATH << File.expand_path("../../lib", __FILE__)
4
+
5
+ require "ostruct"
6
+ require "template-inheritance"
7
+
8
+ TemplateInheritance::Template.paths << File.expand_path("..", __FILE__)
9
+
10
+ post = OpenStruct.new(title: "My First Post!", content: "This is my first post!")
11
+
12
+ # setup
13
+ Tilt::HamlTemplate.options[:default_attributes] = {form: {method: "post"}}
14
+
15
+ template = TemplateInheritance::Template.new("site/post.html.haml")
16
+ puts "", template.render(post: post)
@@ -0,0 +1,8 @@
1
+ / This about this template as about a library, it
2
+ / provides some blocks (API) and it changes others.
3
+ - block(:scripts).unshift("ga.js")
4
+
5
+ - block(:google_analytics) do
6
+ / Google Analytics
7
+ %script
8
+ // Some clever JS magic.
@@ -0,0 +1,3 @@
1
+ %p
2
+ Tell me why on Earth should I use partials now? But if you want them, here you are!
3
+ == Now let's test the local variables for partials, do they work? : #{local}
@@ -0,0 +1,38 @@
1
+ / Extends means "use this template as a layout". Of course
2
+ / as this is template inheritance, the layout can have its
3
+ / own layout which can have its own layout etc, there's no
4
+ / restriction.
5
+
6
+ / The right fun starts with conditional extends, for example
7
+ / extends "base.html" unless request.ajax? (works in Rango)
8
+ / So in case of a XHR request it will just render current
9
+ / template without any layouting. Then if you use code
10
+ / "= block(:main)" instead of "- block(:main)", it will
11
+ / actually returns result of the block(:main) into the
12
+ / template. This way you are agnostic to XHR/non-XHR
13
+ / requests, simply return wrapped HTML or just the
14
+ / required chunk depending on the type of request.
15
+ - extends "base.html" # unless request.ajax?
16
+
17
+ / Oh yeah you can access the value and modify it as you like!
18
+ - block(:scripts).unshift("mootools-core.js")
19
+
20
+ / You might thing that the following solution might work
21
+ / as well, but it won't, because in this case it'd be the
22
+ / default value and default value is used just in case it
23
+ / won't get any value in the child template.
24
+ /- block(:scripts, block(:scripts) + ["mootools-core"])
25
+
26
+ / However there's the extend_block helper which
27
+ / will rewrite the value from the child template:
28
+ /- extend_block(:scripts, block(:scripts) + ["mootools-core"])
29
+
30
+ / Another one is enhance_block which does the same,
31
+ / but unlike the extend_block helper, it doesn't
32
+ / fail in case the block isn't defined yet.
33
+
34
+ / And you can also clear block using clear_block(name).
35
+
36
+ - block(:main) do
37
+ %h1 Welcome to my cool blog!
38
+ = block(:post)
@@ -0,0 +1,17 @@
1
+ / Paths
2
+
3
+ / ./base.html: Find template base.html in the same directory as current template.
4
+ / ../base.html: Find template base.html in parent directory of current template.
5
+
6
+ / base.html: find template base.html in TemplateInheritance::Template.paths array.
7
+ / The lookup works same as Ruby's require lookup, it's basically
8
+ / TemplateInheritance::Template.paths.find { |dir| File.join(dir, template_name) }
9
+ - extends "./base.html"
10
+
11
+ - block(:scripts, ["post.js"])
12
+
13
+ - block(:post) do
14
+ %h2= post.title
15
+ %p= post.content
16
+
17
+ = partial "./wtf", local: true
@@ -0,0 +1,118 @@
1
+ # encoding: utf-8
2
+
3
+ require "template-inheritance/exts/tilt"
4
+ require "template-inheritance/helpers"
5
+
6
+ module TemplateInheritance
7
+ @@development = true
8
+ def self.development=(boolean)
9
+ @@development = boolean
10
+ end
11
+
12
+ def self.development?
13
+ @@development
14
+ end
15
+
16
+ def self.logger
17
+ @@logger ||= SimpleLogger.new
18
+ end
19
+
20
+ def self.logger=(logger)
21
+ @@logger = logger
22
+ end
23
+
24
+ class TemplateNotFound < StandardError
25
+ def initialize(message = "Template not found")
26
+ end
27
+ end
28
+
29
+ class SimpleLogger
30
+ def log(message)
31
+ puts "~ #{message}"
32
+ end
33
+
34
+ alias_method :info, :log
35
+ alias_method :debug, :log
36
+ end
37
+
38
+ class Template
39
+ def self.paths
40
+ @@paths ||= Array.new
41
+ end
42
+
43
+ # template -> supertemplate is the same relationship as class -> superclass
44
+ # @since 0.0.2
45
+ attr_accessor :path, :scope, :supertemplate, :context
46
+
47
+ # @since 0.0.2
48
+ attr_writer :blocks
49
+ def blocks
50
+ @blocks ||= Hash.new
51
+ end
52
+
53
+ # @since 0.0.2
54
+ def initialize(path, scope = Object.new)
55
+ self.path = path#[scope.class.template_prefix.chomp("/"), template].join("/")
56
+ self.scope = scope
57
+ self.scope.extend(TemplateHelpers)
58
+ # this enables template caching
59
+ unless TemplateInheritance.development?
60
+ self.scope.extend(Tilt::CompileSite)
61
+ end
62
+ self.scope.template = self
63
+ end
64
+
65
+ # @since 0.0.2
66
+ def fullpath
67
+ @fullpath ||= begin
68
+ if self.path.match(/^(\/|\.)/) # /foo or ./foo
69
+ Dir[self.path, "#{self.path}.*"].find {|file| !File.directory?(file)}
70
+ else
71
+ self.find_in_paths
72
+ end
73
+ end
74
+ end
75
+
76
+ def adapter
77
+ snake_case(self.template.class.name.split("::").last).sub("_template", "")
78
+ end
79
+
80
+ def extension # haml, erb ...
81
+ File.extname(path)[1..-1]
82
+ end
83
+
84
+ def template(options = Hash.new)
85
+ @template ||= Tilt.new(self.fullpath, nil, options)
86
+ end
87
+
88
+ # @since 0.0.2
89
+ def render(context = Hash.new)
90
+ raise TemplateNotFound.new("Template #{self.path} wasn't found in these paths: #{self.class.paths.inspect}") if self.fullpath.nil?
91
+ TemplateInheritance.logger.info("Rendering template #{self.path} with context keys #{context.keys.inspect}")
92
+ self.scope.context = self.context = context # so we can access context in the scope object as well
93
+ value = self.template.render(self.scope, context)
94
+ TemplateInheritance.logger.debug("Available blocks: #{self.blocks.keys.inspect}")
95
+ if self.supertemplate
96
+ TemplateInheritance.logger.debug("Extends call: #{self.supertemplate}")
97
+ supertemplate = self.class.new(self.supertemplate, self.scope)
98
+ supertemplate.blocks = self.blocks
99
+ return supertemplate.render(context)
100
+ end
101
+ value
102
+ end
103
+
104
+ protected
105
+ def find_in_paths
106
+ self.class.paths.each do |directory|
107
+ path = File.join(directory, self.path)
108
+ return Dir[path, "#{path}.*"].find {|file| !File.directory?(file)}
109
+ end
110
+ end
111
+
112
+ def snake_case(string)
113
+ return string.downcase if string =~ /^[A-Z]+$/
114
+ string.gsub(/([A-Z]+)(?=[A-Z][a-z]?)|\B[A-Z]/, '_\&') =~ /_*(.*)/
115
+ return $+.downcase
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+
3
+ # Option default_attributes
4
+ #
5
+ # A hash of default attributes for tags (`{tag => {attribute => default_value}}`).
6
+ # Attributes of each tag will reverse merged with his default attributes, so you
7
+ # don't have to write over and over that script tag has attribute `type` with value
8
+ # `text/javascript`. For example, `%script` compiles to `<script type="text/javascript"></script>`.
9
+ # Defaults to `{script: {type: "text/javascript"}, form: {method: "POST"}}`
10
+
11
+ module Haml
12
+ module Precompiler
13
+ alias_method :__prerender_tag__, :prerender_tag
14
+ def prerender_tag(name, self_close, attributes)
15
+ # merge given attributes with default attributes from options
16
+ defaults = Tilt::HamlTemplate.options[:default_attributes][name.to_sym]
17
+ attributes = defaults.merge(attributes) if defaults
18
+ __prerender_tag__(name, self_close, attributes)
19
+ end
20
+ end
21
+
22
+ class Buffer
23
+ alias_method :__open_tag__, :open_tag
24
+ def open_tag(name, self_closing, try_one_line, preserve_tag, escape_html, class_id,
25
+ nuke_outer_whitespace, nuke_inner_whitespace, obj_ref, content, *attributes_hashes)
26
+ defaults = Tilt::HamlTemplate.options[:default_attributes][name.to_sym]
27
+ attributes_hashes.unshift(defaults) if defaults
28
+
29
+ __open_tag__(name, self_closing, try_one_line, preserve_tag, escape_html, class_id,
30
+ nuke_outer_whitespace, nuke_inner_whitespace, obj_ref, content, *attributes_hashes)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+
3
+ require "tilt"
4
+
5
+ module TemplateInheritance
6
+ module TiltExtensions
7
+ # Tilt::HamlTemplate.options[:default_attributes] = {script: {type: "text/javascript"}, form: {method: "POST"}}
8
+ module Haml
9
+ def self.included(klass)
10
+ klass.send(:remove_method, :initialize_engine)
11
+ def klass.options
12
+ @options ||= Hash.new
13
+ end
14
+ end
15
+
16
+ def initialize_engine
17
+ require_template_library 'haml' unless defined? ::Haml::Engine
18
+ require "template-inheritance/exts/haml" if self.class.options[:default_attributes]
19
+ end
20
+
21
+ def initialize(*args)
22
+ super
23
+ self.options.merge!(self.class.options)
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ Tilt::HamlTemplate.send(:include, TemplateInheritance::TiltExtensions::Haml)
@@ -0,0 +1,144 @@
1
+ # encoding: utf-8
2
+
3
+ module TemplateInheritance
4
+ SubtemplateNotFound = Class.new(StandardError)
5
+
6
+ module TemplateHelpers
7
+ def self.extended(scope)
8
+ class << scope
9
+ attr_accessor :template
10
+ attr_accessor :context
11
+ # @example Capture being used in a .html.erb page:
12
+ # <% @foo = capture do %>
13
+ # <p>Some Foo content!</p>
14
+ # <% end %>
15
+ #
16
+ # @params [*args] Arguments to pass to the block.
17
+ # @params [&block] The template block to call.
18
+ # @return [String] The output of the block.
19
+ # @api private
20
+ def capture(*args, &block)
21
+ capture_method = "capture_#{self.template.adapter}"
22
+ if self.respond_to?(capture_method) # tilt doesn't support @_out_buf for haml
23
+ self.send("capture_#{self.template.adapter}", *args, &block)
24
+ else
25
+ # @_out_buf comes from tilt
26
+ unless self.instance_variable_defined?("@_out_buf")
27
+ raise "Adapter #{self.template.adapter} doesn't support capturing"
28
+ end
29
+ _old_buf, @_out_buf = @_out_buf, ""
30
+ block.call(*args)
31
+ @_out_buf = _old_buf.chomp.strip
32
+ end
33
+ end
34
+
35
+ def concat(string)
36
+ concat_method = "concat_#{self.template.adapter}"
37
+ if self.respond_to?(concat_method) # tilt doesn't support @_out_buf for haml
38
+ self.send("concat_#{self.template.adapter}", string)
39
+ else
40
+ # @_out_buf comes from tilt
41
+ unless self.instance_variable_defined?("@_out_buf")
42
+ raise "Adapter #{self.template.adapter} doesn't support concating"
43
+ end
44
+ @_out_buf << string
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ def self.included(scope_class)
51
+ scope_class.class_eval { attr_accessor :template }
52
+ end
53
+
54
+ # post/show.html: it's block is the block we like to see in output
55
+ # post/base.html
56
+ # base.html: here it will be rendered, so we need block to returns the correct block code
57
+ # @since 0.0.2
58
+ # @version 0.2
59
+ def block(name, value = nil, &block)
60
+ raise ArgumentError, "Block has to have a name!" if name.nil?
61
+ raise ArgumentError, "You have to provide value or block, not both of them!" if value && block
62
+ self.template.blocks[name] ||= block ? self.template.scope.capture(&block) : value
63
+ return self.template.blocks[name]
64
+ end
65
+
66
+ # - extend_block(:head) do
67
+ # = pupu :lighter, syntax: "html", theme: "standard"
68
+ # = block(:head)
69
+ def extend_block(name, value = nil, &block)
70
+ unless self.template.blocks[name]
71
+ raise NameError, "Block #{name.inspect} wasn't defined yet, you can't extend it!"
72
+ end
73
+ self.enhance_block(name, value, &block)
74
+ end
75
+
76
+ def enhance_block(name, value = nil, &block)
77
+ raise ArgumentError, "Block has to have a name!" if name.nil?
78
+ raise ArgumentError, "You have to provide value or block, not both of them!" if value && block
79
+ value = self.template.scope.capture(&block) if value.nil? && block
80
+ self.template.blocks[name] = value if value
81
+ return self.template.blocks[name]
82
+ end
83
+
84
+ # Clears default content of given block.
85
+ #
86
+ # @example
87
+ # clear_block(:flyout)
88
+ def clear_block(name)
89
+ raise ArgumentError, "You need to specify name of block to clear." if name.nil?
90
+ self.template.blocks[name] = String.new
91
+ end
92
+
93
+ # Low-level rendering method for templates.
94
+ #
95
+ # @since 0.2
96
+ # @example
97
+ # render "base.html"
98
+ # render "./base.html"
99
+ # render "../base.html"
100
+ def render(path, context = Hash.new)
101
+ full_path = normalize_template_path(path)
102
+ original_template = self.template
103
+ template = TemplateInheritance::Template.new(full_path, self) # self is scope
104
+ self.template = original_template
105
+ return template.render(context)
106
+ rescue Exceptions::TemplateNotFound # FIXME: this doesn't work
107
+ raise SubtemplateNotFound, "Template #{path} doesn't exist in #{full_path}"
108
+ end
109
+
110
+ # partial "products/list"
111
+ # @since 0.0.2
112
+ # @version 0.2.1
113
+ def partial(template, extra_context = Hash.new)
114
+ # NOTE: we can't use File.split because it normalize the path,
115
+ # so "./base.html" will be the same as "base.html", but it shouldn't be
116
+ *path, basename = template.split("/")
117
+ render File.join(path.join("/"), "_#{basename}"), self.template.context.merge(extra_context)
118
+ end
119
+
120
+ # @since 0.2
121
+ def includes(template, context = Hash.new)
122
+ render normalize_template_path(template), context
123
+ return true
124
+ end
125
+
126
+ # extends "base.html"
127
+ # @since 0.0.2
128
+ def extends(path)
129
+ # we can't just create a new template, because it has to do it after it reads the whole file
130
+ self.template.supertemplate = normalize_template_path(path)
131
+ end
132
+
133
+ # @since 0.2
134
+ def normalize_template_path(template)
135
+ if template.start_with?("./")
136
+ File.expand_path(File.join(File.dirname(self.template.fullpath), template))
137
+ elsif template.start_with?("../")
138
+ File.expand_path(File.join(File.dirname(self.template.fullpath), "..", template))
139
+ else
140
+ template
141
+ end
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,5 @@
1
+ --colour
2
+ --format
3
+ progress
4
+ --loadby
5
+ mtime
@@ -0,0 +1,51 @@
1
+ # encoding: utf-8
2
+
3
+ SPEC_ROOT = File.dirname(__FILE__)
4
+ STUBS_ROOT = File.join(SPEC_ROOT, "stubs")
5
+
6
+ $:.unshift(File.join(SPEC_ROOT, "..", "lib"))
7
+
8
+ begin
9
+ # Require the preresolved locked set of gems.
10
+ require File.expand_path("../.bundle/environment", __FILE__)
11
+ rescue LoadError
12
+ # Fallback on doing the resolve at runtime.
13
+ require "rubygems"
14
+ require "bundler"
15
+ Bundler.setup
16
+ end
17
+
18
+ require "spec" # so you can run ruby spec/rango/whatever_spec.rb
19
+
20
+ require "rango"
21
+ require "logger"
22
+ Rango.logger = Logger.new("/dev/null")
23
+
24
+ class RecursiveOpenStruct < OpenStruct
25
+ def initialize(attributes = Hash.new)
26
+ attributes.each do |key, value|
27
+ if value.is_a?(Hash)
28
+ attributes[key] = OpenStruct.new(value)
29
+ end
30
+ end
31
+ super(attributes)
32
+ end
33
+ end
34
+
35
+ module Spec
36
+ module Matchers
37
+ def match(expected)
38
+ Matcher.new(:match, expected) do |expected|
39
+ match do |actual|
40
+ actual.match(expected)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ Spec::Runner.configure do |config|
48
+ config.before(:all) do
49
+ Rango.environment = "test"
50
+ end
51
+ end
@@ -0,0 +1,2 @@
1
+ = block(:second) do
2
+ a block
@@ -0,0 +1,5 @@
1
+ - block(:head, nil)
2
+ - block(:head, "first")
3
+ - block(:head, "second")
4
+
5
+ = block(:head)
@@ -0,0 +1,2 @@
1
+ = block(:content, "value") do
2
+ Content from block
@@ -0,0 +1,3 @@
1
+ - block(:content, "Hello World!")
2
+
3
+ = block(:content)
@@ -0,0 +1 @@
1
+ = block(:one, "a value")
@@ -0,0 +1 @@
1
+ = self.object_id
@@ -0,0 +1,5 @@
1
+ - block(:content) do
2
+ Original
3
+
4
+ = enhance_block(:content) do
5
+ I own the only #{block(:content)}!
@@ -0,0 +1,3 @@
1
+ = enhance_block(:content, "another value") do
2
+ Content from block
3
+
@@ -0,0 +1 @@
1
+ - enhance_block(nil)
@@ -0,0 +1,3 @@
1
+ - block(:content, "Original")
2
+
3
+ = enhance_block(:content, nil)
@@ -0,0 +1,2 @@
1
+ = enhance_block(:content) do
2
+ Hello World!
@@ -0,0 +1,5 @@
1
+ - block(:content) do
2
+ Original
3
+
4
+ = extend_block(:content) do
5
+ I own the only #{block(:content)}!
@@ -0,0 +1,5 @@
1
+ - block(:content, "value")
2
+
3
+ = extend_block(:content, "another value") do
4
+ Content from block
5
+
@@ -0,0 +1 @@
1
+ = extend_block(:content, "foo")
@@ -0,0 +1 @@
1
+ - extend_block(nil)
@@ -0,0 +1,4 @@
1
+ - block(:content) do
2
+ Original
3
+
4
+ = extend_block(:content, nil)
@@ -0,0 +1 @@
1
+ == #{block(:title)} by #{block(:author)}
@@ -0,0 +1 @@
1
+ = includes "library.html"
@@ -0,0 +1,7 @@
1
+ - includes "library.html"
2
+
3
+ %html
4
+ %head
5
+ %title= block(:title)
6
+
7
+ %body= block(:content)
@@ -0,0 +1,4 @@
1
+ - includes "library.html"
2
+ - extends "includes/base.html"
3
+
4
+ = block(:author, "Jakub Stastny")
@@ -0,0 +1,4 @@
1
+ - extends "includes/base.html"
2
+ - includes "library.html"
3
+
4
+ = block(:author, "Jakub Stastny")
@@ -0,0 +1 @@
1
+ = title
@@ -0,0 +1,2 @@
1
+ %html
2
+ %body= block(:content)
@@ -0,0 +1,2 @@
1
+ - extends "inheritance/basic/base.html"
2
+ - block(:content, "Hello!")
@@ -0,0 +1,2 @@
1
+ %html
2
+ %body= block(:content)
@@ -0,0 +1,3 @@
1
+ - extends "inheritance/capture/haml/base.html"
2
+ - block(:content) do
3
+ Hello!
@@ -0,0 +1,3 @@
1
+ - block(:title, "Greeting") # we don't want to show this in the partial
2
+ - block(:content) do
3
+ Hello World!
@@ -0,0 +1 @@
1
+ %html
@@ -0,0 +1 @@
1
+ = title
File without changes
File without changes
@@ -0,0 +1,139 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative "../../spec_helper"
4
+ require "rango/templates/helpers"
5
+
6
+ Rango::Template.template_paths.clear.push(File.join(STUBS_ROOT, "templates"))
7
+
8
+ describe Rango::TemplateHelpers do
9
+ include Rango::TemplateHelpers
10
+ describe "#partial" do
11
+ it "should work" do
12
+ pending "This can't work because self.template doesn't exist, we have to use render mixin"
13
+ partial "basic.html"
14
+ end
15
+
16
+ it "should share context with the parent template" do
17
+ pending
18
+ end
19
+
20
+ it "should be able to specify additional context which isn't propagated to the parent template" do
21
+ pending
22
+ end
23
+ end
24
+
25
+ describe "#render" do
26
+ it "should consider 'path.html' as a path relative to Template.template_paths" do
27
+ pending
28
+ end
29
+
30
+ it "should consider './path.html' as a path relative to the current template" do
31
+ pending
32
+ end
33
+
34
+ it "should look for '../path.html' in the parent directory of directory with current template" do
35
+ pending
36
+ end
37
+ end
38
+
39
+ describe "#includes" do
40
+ require "rango/mixins/render"
41
+ it "should return true" do
42
+ Rango::RenderMixin.render("includes/basic.html").strip.should eql("true")
43
+ end
44
+
45
+ it "should work with blocks" do
46
+ Rango::RenderMixin.render("includes/includes.html")
47
+ end
48
+
49
+ it "should work with extends" do
50
+ output = Rango::RenderMixin.render("includes/integration.html")
51
+ output.strip.should eql("Greeting by Jakub Stastny")
52
+ end
53
+
54
+ it "should work with extends" do
55
+ output = Rango::RenderMixin.render("includes/integration2.html")
56
+ output.strip.should eql("Greeting by Jakub Stastny")
57
+ end
58
+ end
59
+
60
+ describe "extends" do
61
+ end
62
+
63
+ describe "block" do
64
+ it "should raise argument error if name isn't specified" do
65
+ -> { block(nil) }.should raise_error(ArgumentError)
66
+ end
67
+
68
+ it "should work as a setter if a value is provided" do
69
+ output = Rango::RenderMixin.render("block/value.html")
70
+ output.strip.should eql("a value")
71
+ end
72
+
73
+ it "should work as a setter if a block is provided" do
74
+ output = Rango::RenderMixin.render("block/block.html")
75
+ output.strip.should eql("a block")
76
+ end
77
+
78
+ it "should work as a getter" do
79
+ output = Rango::RenderMixin.render("block/getter.html")
80
+ output.strip.should eql("Hello World!")
81
+ end
82
+
83
+ it "should raise argument error if both value and block is provided" do
84
+ -> { Rango::RenderMixin.render("block/error.html") }.should raise_error(ArgumentError)
85
+ end
86
+
87
+ it "should store the first non-nil value" do
88
+ output = Rango::RenderMixin.render("block/blocks.html")
89
+ output.strip.should eql("first")
90
+ end
91
+ end
92
+
93
+ describe "extend_block" do
94
+ it "should raise argument error if name isn't specified" do
95
+ -> { Rango::RenderMixin.render("extend_block/name_error.html") }.should raise_error(NameError)
96
+ end
97
+
98
+ it "should raise argument error if both value and block is provided" do
99
+ -> { Rango::RenderMixin.render("extend_block/error.html") }.should raise_error(ArgumentError)
100
+ end
101
+
102
+ it "should raise argument error if block of given name doesn't exist so far" do
103
+ -> { Rango::RenderMixin.render("extend_block/error2.html") }.should raise_error
104
+ end
105
+
106
+ it "should work with super()-like inheritance" do
107
+ Rango::RenderMixin.render("extend_block/basic.html")
108
+ end
109
+
110
+ it "should do nothing if the value or block is nil" do
111
+ output = Rango::RenderMixin.render("extend_block/nil.html")
112
+ output.strip.should eql("Original")
113
+ end
114
+ end
115
+
116
+ describe "enhance_block" do
117
+ it "should work even if the block isn't defined so far" do
118
+ output = Rango::RenderMixin.render("enhance_block/standalone.html")
119
+ output.strip.should eql("Hello World!")
120
+ end
121
+
122
+ it "should not raise argument error if name isn't specified" do
123
+ -> { Rango::RenderMixin.render("enhance_block/name_error.html") }.should_not raise_error(NameError)
124
+ end
125
+
126
+ it "should raise argument error if both value and block is provided" do
127
+ -> { Rango::RenderMixin.render("enhance_block/error.html") }.should raise_error(ArgumentError)
128
+ end
129
+
130
+ it "should work with super()-like inheritance" do
131
+ Rango::RenderMixin.render("enhance_block/basic.html")
132
+ end
133
+
134
+ it "should do nothing if the value or block is nil" do
135
+ output = Rango::RenderMixin.render("enhance_block/nil.html")
136
+ output.strip.should eql("Original")
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,61 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative "../../spec_helper"
4
+ require "rango/templates/template"
5
+
6
+ Rango::Template.template_paths.clear.push(File.join(STUBS_ROOT, "templates"))
7
+
8
+ describe Rango::Template do
9
+ describe "#initialize" do
10
+ it "should take path as a first argument" do
11
+ template = Rango::Template.new("test.html")
12
+ template.path.should eql("test.html")
13
+ end
14
+
15
+ it "should take scope as an optional second argument" do
16
+ scope = Object.new
17
+ template = Rango::Template.new("test.html", scope)
18
+ template.scope.should eql(scope)
19
+ end
20
+ end
21
+
22
+ describe "#fullpath" do
23
+ it "should find" do
24
+ template = Rango::Template.new("test.html")
25
+ fullpath = File.join(STUBS_ROOT, "templates", "test.html.haml")
26
+ template.fullpath.should eql(fullpath)
27
+ end
28
+ end
29
+
30
+ describe "#render" do
31
+ it "should raise TemplateNotFound if template can't be found" do
32
+ template = Rango::Template.new("idonotexist.html")
33
+ -> { template.render }.should raise_error(Rango::Exceptions::TemplateNotFound)
34
+ end
35
+
36
+ it "should render" do
37
+ template = Rango::Template.new("test.html")
38
+ template.render.should eql("<html></html>\n")
39
+ end
40
+
41
+ it "should have template inheritance" do
42
+ template = Rango::Template.new("inheritance/basic/index.html")
43
+ end
44
+
45
+ it "should capture haml" do
46
+ template = Rango::Template.new("inheritance/capture/haml/index.html")
47
+ template.render
48
+ template.blocks[:content].should match("Hello!")
49
+ end
50
+ end
51
+
52
+ describe "variables" do
53
+ before(:each) do
54
+ @template = Rango::Template.new("variables.html")
55
+ end
56
+
57
+ it "should capture erb" do
58
+ # @template.render(title: "Hi!").should match("Hi!")
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env gem build
2
+ # encoding: utf-8
3
+
4
+ require "base64"
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "template-inheritance"
8
+ s.version = "0.1"
9
+ s.authors = ["Jakub Šťastný aka Botanicus"]
10
+ s.homepage = "http://github.com/botanicus/template-inheritance"
11
+ s.summary = ""
12
+ s.description = "" # TODO: long description
13
+ s.cert_chain = nil
14
+ s.email = Base64.decode64("c3Rhc3RueUAxMDFpZGVhcy5jeg==\n")
15
+ s.has_rdoc = true
16
+
17
+ # files
18
+ s.files = `git ls-files`.split("\n")
19
+
20
+ s.require_paths = ["lib"]
21
+
22
+ # Ruby version
23
+ # Current JRuby with --1.9 switch has RUBY_VERSION set to "1.9.2dev"
24
+ # and RubyGems don't play well with it, so we have to set minimal
25
+ # Ruby version to 1.9, even if it actually is 1.9.1
26
+ s.required_ruby_version = ::Gem::Requirement.new("~> 1.9")
27
+
28
+ # dependencies
29
+ s.add_dependency "tilt"
30
+ s.add_dependency "haml"
31
+
32
+ # begin
33
+ # require "changelog"
34
+ # rescue LoadError
35
+ # warn "You have to have changelog gem installed for post install message"
36
+ # else
37
+ # s.post_install_message = CHANGELOG.new.version_changes
38
+ # end
39
+
40
+ # RubyForge
41
+ s.rubyforge_project = "template-inheritance"
42
+ end
metadata CHANGED
@@ -4,28 +4,22 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 0
8
- - 0
9
- - 0
10
- - 0
11
- - 0
12
- - 0
13
- - 0
14
7
  - 1
15
- version: 0.0.0.0.0.0.0.0.1
8
+ version: "0.1"
16
9
  platform: ruby
17
10
  authors:
18
11
  - "Jakub \xC5\xA0\xC5\xA5astn\xC3\xBD aka Botanicus"
19
12
  autorequire:
20
13
  bindir: bin
21
14
  cert_chain:
22
- date: 2010-03-24 00:00:00 +00:00
15
+ date: 2010-10-02 00:00:00 +01:00
23
16
  default_executable:
24
17
  dependencies:
25
18
  - !ruby/object:Gem::Dependency
26
19
  name: tilt
27
20
  prerelease: false
28
21
  requirement: &id001 !ruby/object:Gem::Requirement
22
+ none: false
29
23
  requirements:
30
24
  - - ">="
31
25
  - !ruby/object:Gem::Version
@@ -34,6 +28,19 @@ dependencies:
34
28
  version: "0"
35
29
  type: :runtime
36
30
  version_requirements: *id001
31
+ - !ruby/object:Gem::Dependency
32
+ name: haml
33
+ prerelease: false
34
+ requirement: &id002 !ruby/object:Gem::Requirement
35
+ none: false
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ segments:
40
+ - 0
41
+ version: "0"
42
+ type: :runtime
43
+ version_requirements: *id002
37
44
  description: ""
38
45
  email: stastny@101ideas.cz
39
46
  executables: []
@@ -43,7 +50,54 @@ extensions: []
43
50
  extra_rdoc_files: []
44
51
 
45
52
  files:
53
+ - .gitignore
46
54
  - README.textile
55
+ - example/base.html.haml
56
+ - example/example.rb
57
+ - example/shared/google_analytics.html.haml
58
+ - example/site/_wtf.html.haml
59
+ - example/site/base.html.haml
60
+ - example/site/post.html.haml
61
+ - lib/template-inheritance.rb
62
+ - lib/template-inheritance/exts/haml.rb
63
+ - lib/template-inheritance/exts/tilt.rb
64
+ - lib/template-inheritance/helpers.rb
65
+ - spec/spec.opts
66
+ - spec/spec_helper.rb
67
+ - spec/stubs/block/block.html.haml
68
+ - spec/stubs/block/blocks.html.haml
69
+ - spec/stubs/block/error.html.haml
70
+ - spec/stubs/block/getter.html.haml
71
+ - spec/stubs/block/value.html.haml
72
+ - spec/stubs/context_id.html.haml
73
+ - spec/stubs/enhance_block/basic.html.haml
74
+ - spec/stubs/enhance_block/error.html.haml
75
+ - spec/stubs/enhance_block/name_error.html.haml
76
+ - spec/stubs/enhance_block/nil.html.haml
77
+ - spec/stubs/enhance_block/standalone.html.haml
78
+ - spec/stubs/extend_block/basic.html.haml
79
+ - spec/stubs/extend_block/error.html.haml
80
+ - spec/stubs/extend_block/error2.html.haml
81
+ - spec/stubs/extend_block/name_error.html.haml
82
+ - spec/stubs/extend_block/nil.html.haml
83
+ - spec/stubs/includes/base.html.haml
84
+ - spec/stubs/includes/basic.html.haml
85
+ - spec/stubs/includes/includes.html.haml
86
+ - spec/stubs/includes/integration.html.haml
87
+ - spec/stubs/includes/integration2.html.haml
88
+ - spec/stubs/index.html.haml
89
+ - spec/stubs/inheritance/basic/base.html.haml
90
+ - spec/stubs/inheritance/basic/index.html.haml
91
+ - spec/stubs/inheritance/capture/haml/base.html.haml
92
+ - spec/stubs/inheritance/capture/haml/index.html.haml
93
+ - spec/stubs/library.html.haml
94
+ - spec/stubs/test.html.haml
95
+ - spec/stubs/variables.html.haml
96
+ - spec/templates/exts/haml_spec.rb
97
+ - spec/templates/exts/tilt_spec.rb
98
+ - spec/templates/helpers_spec.rb
99
+ - spec/templates/template_spec.rb
100
+ - template-inheritance.gemspec
47
101
  has_rdoc: true
48
102
  homepage: http://github.com/botanicus/template-inheritance
49
103
  licenses: []
@@ -54,6 +108,7 @@ rdoc_options: []
54
108
  require_paths:
55
109
  - lib
56
110
  required_ruby_version: !ruby/object:Gem::Requirement
111
+ none: false
57
112
  requirements:
58
113
  - - ~>
59
114
  - !ruby/object:Gem::Version
@@ -62,6 +117,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
62
117
  - 9
63
118
  version: "1.9"
64
119
  required_rubygems_version: !ruby/object:Gem::Requirement
120
+ none: false
65
121
  requirements:
66
122
  - - ">="
67
123
  - !ruby/object:Gem::Version
@@ -71,7 +127,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
71
127
  requirements: []
72
128
 
73
129
  rubyforge_project: template-inheritance
74
- rubygems_version: 1.3.6
130
+ rubygems_version: 1.3.7
75
131
  signing_key:
76
132
  specification_version: 3
77
133
  summary: ""