adzap-mustache-rails 0.2.3

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