adzap-mustache-rails 0.2.3

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.
@@ -0,0 +1,82 @@
1
+ # Mustache Rails
2
+
3
+ Implements Mustache views and templates for Rails 3.x
4
+
5
+ ## Installation
6
+
7
+ ``` ruby
8
+ gem 'mustache-rails', :require => 'mustache/railtie'
9
+ ```
10
+
11
+ Or alternatively `require 'mustache/railtie'` in your `config/application.rb`.
12
+
13
+ ## Usage
14
+
15
+ In typical mustache fashion, `.mustache` templates go under `app/templates` and view `.rb` files go under `app/views`. Any view classes will be looked for under the `::Views` modules.
16
+
17
+ Simple template scaffolding:
18
+
19
+ ``` ruby
20
+ # app/views/layouts/application.rb
21
+ module Views
22
+ module Layouts
23
+ class Application < ActionView::Mustache
24
+ def title
25
+ "Hello"
26
+ end
27
+ end
28
+ end
29
+ end
30
+ ```
31
+
32
+ ``` mustache
33
+ {{ ! app/templates/layouts/application.mustache }}
34
+ <!DOCTYPE html>
35
+ <html>
36
+ <head>
37
+ <meta charset='utf-8'>
38
+ <title>{{title}}</title>
39
+ </head>
40
+ <body>
41
+ {{yield}}
42
+ </body>
43
+ </html>
44
+ ```
45
+
46
+ ``` ruby
47
+ # app/views/users/show.rb
48
+ module Views
49
+ module Users
50
+ class Show < Layouts::Application
51
+ attr_reader :user
52
+ end
53
+ end
54
+ end
55
+ ```
56
+
57
+ ``` mustache
58
+ {{ ! app/templates/users/show.mustache }}
59
+ {{#user}}
60
+ <h1>{{name}}</h1>
61
+ {{/user}}
62
+ ```
63
+
64
+ ### Optional Configuration
65
+
66
+ ``` ruby
67
+ # config/application.rb
68
+ module Foo
69
+ class Application < Rails::Application
70
+ # Config defaults
71
+ config.mustache.template_path = "app/templates"
72
+ config.mustache.view_path = "app/views"
73
+ config.mustache.view_namespace = "::Views"
74
+ end
75
+ end
76
+ ```
77
+
78
+ ## License
79
+
80
+ Copyright &copy; 2012 Joshua Peek.
81
+
82
+ Released under the MIT license. See `LICENSE` for details.
@@ -0,0 +1,105 @@
1
+ require 'active_support/concern'
2
+ require 'action_view'
3
+ require 'action_view/base'
4
+ require 'action_view/helpers'
5
+ require 'action_view/mustache'
6
+
7
+ module ActionView
8
+ module Helpers
9
+ # Public: Standard helper mixed into ActionView context for
10
+ # constructing the Mustache View.
11
+ module MustacheHelper
12
+ extend ActiveSupport::Concern
13
+
14
+ included do
15
+ # PID: Storing our view namespace settings on a class variable
16
+ # is kinda nasty. It'd better to avoid the global and always
17
+ # use our application's config object.
18
+ cattr_accessor :mustache_view_namespace
19
+
20
+ # Default class to use if no view class is found.
21
+ # A nil value will raise an exception.
22
+ cattr_accessor :mustache_default_view_class
23
+ end
24
+
25
+ # Public: Get Mustache View Class for template.
26
+ #
27
+ # Choose template class by camalizing the template path name and
28
+ # prefixing our view namespace.
29
+ #
30
+ # The class must be a subclass of ActionView::Mustache
31
+ # otherwise a TypeError will be raised.
32
+ #
33
+ # If the template is "anonymous" and has no path, which is the
34
+ # case for render(:inline), the default ActionView::Mustache
35
+ # base class will be returned.
36
+ #
37
+ # Examples
38
+ #
39
+ # "blog/show" => Blog::Show
40
+ #
41
+ # Returns Class or raises a TypeError.
42
+ def mustache_view_class
43
+ if @virtual_path
44
+ begin
45
+ klass = "#{mustache_view_namespace}/#{@virtual_path}"
46
+ load_mustache_view_class_name(klass)
47
+ rescue NameError => e
48
+ if klass = mustache_default_view_class
49
+ load_mustache_view_class_name(klass)
50
+ else
51
+ raise e
52
+ end
53
+ end
54
+ else
55
+ if klass = mustache_default_view_class
56
+ load_mustache_view_class_name(klass)
57
+ else
58
+ ActionView::Mustache
59
+ end
60
+ end
61
+ end
62
+
63
+ # Internal: Load Mustache View class.
64
+ #
65
+ # klass_name - Actual Class or String of class name.
66
+ #
67
+ # Returns view class that is a subclass of ActionView::Mustache
68
+ # or raises an exception.
69
+ def load_mustache_view_class_name(klass_name)
70
+ case klass_name
71
+ when String
72
+ klass_name = klass_name.camelize
73
+ begin
74
+ klass = klass_name.constantize
75
+ rescue NameError => e
76
+ load_path = ActiveSupport::Dependencies.autoload_paths.map { |p| " #{p}\n" }.join
77
+ raise NameError, "Couldn't find #{klass_name}\n#{load_path}"
78
+ end
79
+ when Class
80
+ klass = klass_name
81
+ else
82
+ raise ArgumentError, "#{klass_name} isn't a Class"
83
+ end
84
+
85
+ unless klass < ActionView::Mustache
86
+ raise TypeError, "#{klass} isn't a subclass of ActionView::Mustache"
87
+ end
88
+ klass
89
+ end
90
+
91
+ # Public: Get or initialize Mustache View.
92
+ #
93
+ # The view object is cached so partial renders will reuse the
94
+ # same instance.
95
+ #
96
+ # Returns a Mustache View which is a subclass of
97
+ # ActionView::Mustache.
98
+ def mustache_view
99
+ @_mustache_view ||= mustache_view_class.new(self)
100
+ end
101
+ end
102
+ end
103
+
104
+ Base.send :include, Helpers::MustacheHelper
105
+ end
@@ -0,0 +1,77 @@
1
+ require 'action_view'
2
+ require 'mustache'
3
+ require 'action_view/mustache/context'
4
+
5
+ module ActionView
6
+ # Public: Mustache View base class.
7
+ #
8
+ # All Mustache views MUST inherit from this class.
9
+ #
10
+ # Examples
11
+ #
12
+ # module Layouts
13
+ # class Application < ActionView::Mustache; end
14
+ # end
15
+ #
16
+ class Mustache < ::Mustache
17
+ # Internal: Initializes Mustache View.
18
+ #
19
+ # Initialization is handled by MustacheHelper#mustache_view.
20
+ #
21
+ # view - ActionView::Base instance
22
+ #
23
+ # Returns ActionView::Mustache instance.
24
+ def initialize(view)
25
+ # Reference to original ActionView context.
26
+ @_view = view
27
+
28
+ # Grab template path from view
29
+ self.template_name = view.instance_variable_get(:@virtual_path)
30
+
31
+ # If view has an associated controller
32
+ if controller = view.controller
33
+ # Copy controller ivars into our view
34
+ controller.view_assigns.each do |name, value|
35
+ instance_variable_set '@'+name, value
36
+ end
37
+ end
38
+
39
+ # Define `yield` keyword for content_for :layout
40
+ context[:yield] = lambda { content_for :layout }
41
+ end
42
+
43
+ # Remove Mustache's render method so ActionView's render can be
44
+ # delegated to.
45
+ undef_method :render
46
+
47
+ # Public: Get view context.
48
+ #
49
+ # Returns ActionView::Mustache::Context instance.
50
+ def context
51
+ @context ||= Context.new(self)
52
+ end
53
+
54
+ # Public: Get cache key for current template contents.
55
+ #
56
+ # Useful for busting caches when the template changes.
57
+ #
58
+ # Returns 10 hex char String.
59
+ def template_cache_key
60
+ context[:template_cache_key]
61
+ end
62
+
63
+ # Public: Forwards methods to original Rails view context
64
+ #
65
+ # Returns an Object.
66
+ def method_missing(*args, &block)
67
+ @_view.send(*args, &block)
68
+ end
69
+
70
+ # Public: Checks if method exists in Rails view context.
71
+ #
72
+ # Returns Boolean.
73
+ def respond_to?(method, include_private = false)
74
+ super || @_view.respond_to?(method, include_private)
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,75 @@
1
+ require 'action_view'
2
+ require 'mustache'
3
+
4
+ module ActionView
5
+ class Mustache < ::Mustache
6
+ # Internal: Override Mustache's default Context class
7
+ class Context < ::Mustache::Context
8
+ # Partials are no longer routed through Mustache but through
9
+ # ActionView's own render method.
10
+ undef_method :partial
11
+
12
+ # Escape helper isn't used, its all handled by Rails' SafeBuffer
13
+ # auto escaping.
14
+ undef_method :escapeHTML
15
+
16
+ # Internal: Evaluate section block.
17
+ #
18
+ # view - ActionView::Context instance
19
+ # buffer - ActiveSupport::SafeBuffer object
20
+ # value - Object value of section tag
21
+ #
22
+ # Returns nothing.
23
+ def _eval_section(view, buffer, value, &block)
24
+ if value
25
+ if value == true
26
+ yield
27
+ elsif value.is_a?(Proc)
28
+ buffer.concat(value.call { view.capture(&block) }.to_s)
29
+ else
30
+ value = [value] unless value.is_a?(Array) || defined?(Enumerator) && value.is_a?(Enumerator)
31
+ for h in value
32
+ push(h)
33
+ yield
34
+ pop
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ # Internal: Evaluate inverted section block.
41
+ #
42
+ # buffer - ActiveSupport::SafeBuffer object
43
+ # value - Object value of inverted section tag
44
+ #
45
+ # Returns nothing.
46
+ def _eval_inverted_section(buffer, value)
47
+ if (value.nil? || value == false || value.respond_to?(:empty?) && value.empty?)
48
+ yield
49
+ end
50
+ end
51
+
52
+ # Internal: Evaluate unescaped tag.
53
+ #
54
+ # buffer - ActiveSupport::SafeBuffer object
55
+ # value - Object value of tag
56
+ #
57
+ # Returns nothing.
58
+ def _eval_utag(buffer, value)
59
+ value = value.call.to_s if value.is_a?(Proc)
60
+ buffer.safe_concat(value.to_s)
61
+ end
62
+
63
+ # Internal: Evaluate escaped tag.
64
+ #
65
+ # buffer - ActiveSupport::SafeBuffer object
66
+ # value - Object value of tag
67
+ #
68
+ # Returns nothing.
69
+ def _eval_etag(buffer, value)
70
+ value = value.call.to_s if value.is_a?(Proc)
71
+ buffer.concat(value.to_s)
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,123 @@
1
+ require 'action_view'
2
+ require 'action_view/mustache'
3
+ require 'mustache'
4
+
5
+ module ActionView
6
+ class Mustache < ::Mustache
7
+ # Public: Compiles tokens from Mustache::Parser into evaluatable
8
+ # Ruby code.
9
+ #
10
+ # The code generate targets Rails output buffer and must be
11
+ # evaluated inside an ActionView::Base instance.
12
+ #
13
+ # See Mustache::Generator for more info.
14
+ class Generator
15
+ # Public: Convert tokens to plain old Ruby.
16
+ #
17
+ # exp - Array of tokens produced by Mustache::Parser
18
+ #
19
+ # Returns String of compiled Ruby code.
20
+ def compile(exp)
21
+ src = ""
22
+ src << "@output_buffer = output_buffer || ActionView::OutputBuffer.new; "
23
+ src << compile!(exp)
24
+ src << "@output_buffer.to_s;"
25
+ src
26
+ end
27
+
28
+ # Internal: Recursively compile token expression.
29
+ #
30
+ # exp - Token Array structure
31
+ #
32
+ # Returns String.
33
+ def compile!(exp)
34
+ case exp.first
35
+ when :multi
36
+ exp[1..-1].map { |e| compile!(e) }.join
37
+ when :static
38
+ text(exp[1])
39
+ when :mustache
40
+ send("on_#{exp[1]}", *exp[2..-1])
41
+ else
42
+ raise "Unhandled exp: #{exp.first}"
43
+ end
44
+ end
45
+
46
+ # Internal: Compile section.
47
+ #
48
+ # name - String of section name
49
+ # content - Array of section content tokens
50
+ #
51
+ # Returns String.
52
+ def on_section(name, content, raw, delims)
53
+ "v = #{compile!(name)}; ctx._eval_section(self, @output_buffer, v) {\n#{compile!(content)}\n}; "
54
+ end
55
+
56
+ # Internal: Compile inverted section.
57
+ #
58
+ # name - String of section name
59
+ # content - Array of section content tokens
60
+ #
61
+ # Returns String.
62
+ def on_inverted_section(name, content, raw, delims)
63
+ "v = #{compile!(name)}; ctx._eval_inverted_section(@output_buffer, v) {\n#{compile!(content)}\n}; "
64
+ end
65
+
66
+ # Internal: Compile partial render call.
67
+ #
68
+ # name - String of partial name
69
+ # indentation - String of indentation level
70
+ #
71
+ # Returns String.
72
+ def on_partial(name, indentation)
73
+ "@output_buffer.concat(render(:partial => #{name.inspect}));\n"
74
+ end
75
+
76
+ # Internal: Compile unescaped tag.
77
+ #
78
+ # name - String name of tag
79
+ #
80
+ # Returns String.
81
+ def on_utag(name)
82
+ "v = #{compile!(name)}; ctx._eval_utag(@output_buffer, v); "
83
+ end
84
+
85
+ # Internal: Compile escaped tag.
86
+ #
87
+ # name - String name of tag
88
+ #
89
+ # Returns String.
90
+ def on_etag(name)
91
+ "v = #{compile!(name)}; ctx._eval_etag(@output_buffer, v); "
92
+ end
93
+
94
+ # Internal: Compile fetch lookup.
95
+ #
96
+ # names - Array of names to fetch.
97
+ #
98
+ # Returns String.
99
+ def on_fetch(names)
100
+ names = names.map { |n| n.to_sym }
101
+
102
+ if names.length == 0
103
+ "ctx[:to_s]"
104
+ elsif names.length == 1
105
+ "ctx[#{names.first.to_sym.inspect}]"
106
+ else
107
+ initial, *rest = names
108
+ "#{rest.inspect}.inject(ctx[#{initial.inspect}]) { |v, k| v && ctx.find(v, k) }; "
109
+ end
110
+ end
111
+
112
+ # Internal: Compile static string.
113
+ #
114
+ # text - String of text.
115
+ #
116
+ # Returns String.
117
+ def text(text)
118
+ text = text.gsub(/['\\]/, '\\\\\&')
119
+ "@output_buffer.safe_concat('#{text}'); "
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,43 @@
1
+ require 'action_view'
2
+ require 'action_view/template'
3
+ require 'action_view/template/handlers'
4
+ require 'action_view/helpers/mustache_helper'
5
+ require 'action_view/mustache'
6
+ require 'action_view/mustache/generator'
7
+ require 'mustache'
8
+ require 'digest/md5'
9
+
10
+ module ActionView
11
+ class Template
12
+ module Handlers
13
+ # Public: Mustache template compiler.
14
+ #
15
+ # Requiring this file should automatically register the template
16
+ # handler, so there should be no need to reference the class
17
+ # directly.
18
+ class Mustache
19
+ # Public: Compile template into Ruby.
20
+ #
21
+ # template - ActionView::Template object
22
+ #
23
+ # Returns String of Ruby code to be evaled.
24
+ def self.call(template)
25
+ # Use standard mustache parser to generate tokens
26
+ tokens = ::Mustache::Parser.new.compile(template.source)
27
+
28
+ # Use custom generator to generate the compiled ruby
29
+ src = ActionView::Mustache::Generator.new.compile(tokens)
30
+
31
+ digest = Digest::MD5.hexdigest(template.source)[0, 10]
32
+ set_cache_key = "merge({:template_cache_key => \"#{digest}\"})"
33
+
34
+ <<-RUBY
35
+ ctx = mustache_view.context; begin; ctx.push(local_assigns.#{set_cache_key}); #{src}; ensure; ctx.pop; end
36
+ RUBY
37
+ end
38
+ end
39
+ end
40
+
41
+ register_template_handler :mustache, Handlers::Mustache
42
+ end
43
+ end
@@ -0,0 +1,89 @@
1
+ require 'mustache'
2
+ require 'rails/railtie'
3
+
4
+ class Mustache
5
+ # Railtie initializer for Rails 3.x and higher.
6
+ #
7
+ # Either add a require to the top of your `config/application.rb`
8
+ #
9
+ # require "mustache/rails"
10
+ #
11
+ # Or setup an auto-require in your Gemfile
12
+ #
13
+ # gem "mustache-rails", :require => "mustache/railtie"
14
+ #
15
+ class Railtie < Rails::Railtie
16
+ # Public: Application configuration object.
17
+ #
18
+ # Defaults can be modified in your `config/application.rb`.
19
+ config.mustache = ActiveSupport::OrderedOptions.new
20
+
21
+ # Public: Relative path to .mustache template files.
22
+ #
23
+ # Defaults to "app/templates". Its highly recommended to keep the
24
+ # default value.
25
+ #
26
+ # Returns String.
27
+ config.mustache.template_path = "app/templates"
28
+
29
+ # Public: Relative path to mustache view classes.
30
+ #
31
+ # Defaults to "app". Since "::Views::Blog::Show" will
32
+ # automatically look up "app/" + "views/blog/show".
33
+ #
34
+ # If you want to drop the namespace, this should be set to
35
+ # "app/views".
36
+ #
37
+ # Returns String.
38
+ config.mustache.view_path = "app"
39
+
40
+ # Public: Namespace to look for mustache view classes under.
41
+ #
42
+ # Defaults to "::Views". You may want to drop this namespace by
43
+ # setting the value to "".
44
+ #
45
+ # The value may also be set to a Class, but a String is
46
+ # recommended for lazily loading.
47
+ #
48
+ # Returns String or Class.
49
+ config.mustache.view_namespace = "::Views"
50
+
51
+ # Public: Set default Mustache View class to use if none is found.
52
+ #
53
+ # Defaults to "nil" which means an exception will be raised with
54
+ # the class it expected to find. This can be useful during
55
+ # development or when your just getting started.
56
+ #
57
+ # Setting a String or Class will cause the class to be used as a
58
+ # fallback anytime the expected view class lookup fails.
59
+ #
60
+ # Returns nil, String or Class.
61
+ config.mustache.default_view_class = nil
62
+
63
+ # Internal: Ensures view path is included in autoload path.
64
+ initializer 'mustache.add_autoload_paths', :before => :set_autoload_paths do |app|
65
+ app.config.autoload_paths << app.root.join(app.config.mustache.view_path).to_s
66
+ end
67
+
68
+ # Internal: Adds .mustache template path to ActionController's view paths.
69
+ initializer 'mustache.add_view_paths', :after => :add_view_paths do |app|
70
+ ActiveSupport.on_load(:action_controller) do
71
+ append_view_path app.root.join(app.config.mustache.template_path).to_s
72
+ end
73
+ end
74
+
75
+ # Internal: Assigns configured view namespace to ActionView context.
76
+ initializer 'mustache.set_view_namespace' do |app|
77
+ ActiveSupport.on_load(:action_view) do
78
+ require 'action_view/template/handlers/mustache'
79
+ require 'action_view/helpers/mustache_helper'
80
+
81
+ # PID: Setting a global on ActionView::Base is kinda nasty.
82
+ # It'd be better if ApplicationController could reference its
83
+ # local app configuration.
84
+ ActionView::Base.mustache_view_namespace = app.config.mustache.view_namespace
85
+ ActionView::Base.mustache_default_view_class = app.config.mustache.default_view_class
86
+ end
87
+ end
88
+ end
89
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: adzap-mustache-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.3
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Joshua Peek
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-04-14 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: actionpack
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '3.1'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '3.1'
30
+ - !ruby/object:Gem::Dependency
31
+ name: mustache
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - '='
36
+ - !ruby/object:Gem::Version
37
+ version: 0.99.4
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - '='
44
+ - !ruby/object:Gem::Version
45
+ version: 0.99.4
46
+ - !ruby/object:Gem::Dependency
47
+ name: rake
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: Implements Mustache views and templates for Rails 3.x
63
+ email: josh@joshpeek.com
64
+ executables: []
65
+ extensions: []
66
+ extra_rdoc_files: []
67
+ files:
68
+ - README.md
69
+ - lib/action_view/helpers/mustache_helper.rb
70
+ - lib/action_view/mustache/context.rb
71
+ - lib/action_view/mustache/generator.rb
72
+ - lib/action_view/mustache.rb
73
+ - lib/action_view/template/handlers/mustache.rb
74
+ - lib/mustache/railtie.rb
75
+ homepage: https://github.com/josh/mustache-rails
76
+ licenses: []
77
+ post_install_message:
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ! '>='
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubyforge_project:
95
+ rubygems_version: 1.8.23
96
+ signing_key:
97
+ specification_version: 3
98
+ summary: Mustache Rails adapter
99
+ test_files: []