curly-templates 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,2 +1,10 @@
1
1
  source :rubygems
2
+
2
3
  gemspec
4
+
5
+ platform :ruby do
6
+ gem 'yard'
7
+ gem 'yard-tomdoc'
8
+ gem 'redcarpet'
9
+ gem 'github-markup'
10
+ end
data/README.md CHANGED
@@ -29,7 +29,61 @@ Installing Curly is as simple as running `gem install curly-templates`. If you'r
29
29
  using Bundler to manage your dependencies, add this to your Gemfile
30
30
 
31
31
  ```ruby
32
- gem 'curly-templates', '~> 0.1.0', require: 'curly'
32
+ gem 'curly-templates', '~> 0.1.0'
33
+ ```
34
+
35
+
36
+ How to use Curly
37
+ ----------------
38
+
39
+ In order to use Curly for a view or partial, use the suffix `.curly` instead of
40
+ `.erb`, e.g. `app/views/posts/_comment.html.curly`. Curly will look for a
41
+ corresponding presenter class named `Posts::CommentPresenter`. By convention,
42
+ these are placed in `app/presenters/`, so in this case the presenter would
43
+ reside in `app/presenters/posts/comment_presenter.rb`. Note that presenters
44
+ for partials are not prepended with an underscore.
45
+
46
+ Add some HTML to the partial template along with some Curly variables:
47
+
48
+ ```html
49
+ <!-- app/views/posts/_comment.html.curly -->
50
+ <div class="comment">
51
+ <p>
52
+ {{author_link}} posted {{time_ago}} ago.
53
+ </p>
54
+
55
+ {{body}}
56
+ </div>
57
+ ```
58
+
59
+ The presenter will be responsible for filling in the variables. Add the necessary
60
+ Ruby code to the presenter:
61
+
62
+ ```ruby
63
+ # app/presenters/posts/comment_presenter.rb
64
+ class Posts::CommentPresenter < Curly::Presenter
65
+ presents :comment
66
+
67
+ def body
68
+ BlueCloth.new(@comment.body).to_html
69
+ end
70
+
71
+ def author_link
72
+ link_to(@comment.author.name, @comment.author, rel: "author")
73
+ end
74
+
75
+ def time_ago
76
+ time_ago_in_words(@comment.created_at)
77
+ end
78
+ end
79
+ ```
80
+
81
+ The partial can now be rendered like any other, e.g. by calling
82
+
83
+ ```ruby
84
+ render 'comment', comment: comment
85
+ render comment
86
+ render collection: post.comments
33
87
  ```
34
88
 
35
89
 
data/Rakefile CHANGED
@@ -52,14 +52,6 @@ task :default => :spec
52
52
  require 'rspec/core/rake_task'
53
53
  RSpec::Core::RakeTask.new(:spec)
54
54
 
55
- require 'rdoc/task'
56
- Rake::RDocTask.new do |rdoc|
57
- rdoc.rdoc_dir = 'rdoc'
58
- rdoc.title = "#{name} #{version}"
59
- rdoc.rdoc_files.include('README*')
60
- rdoc.rdoc_files.include('lib/**/*.rb')
61
- end
62
-
63
55
  desc "Open an irb session preloaded with this library"
64
56
  task :console do
65
57
  sh "irb -rubygems -r ./lib/#{name}.rb"
@@ -4,15 +4,15 @@ Gem::Specification.new do |s|
4
4
  s.rubygems_version = '1.3.5'
5
5
 
6
6
  s.name = 'curly-templates'
7
- s.version = '0.1.1'
8
- s.date = '2013-01-23'
7
+ s.version = '0.2.0'
8
+ s.date = '2013-02-07'
9
9
 
10
10
  s.summary = "Free your views!"
11
11
  s.description = "A view layer for your Rails apps that separates structure and logic."
12
12
 
13
13
  s.authors = ["Daniel Schierbeck"]
14
- s.email = 'dasch@zendesk.com'
15
- s.homepage = 'http://github.com/zendesk/curly-templates'
14
+ s.email = 'daniel.schierbeck@gmail.com.com'
15
+ s.homepage = 'https://github.com/dasch/curly'
16
16
 
17
17
  s.require_paths = %w[lib]
18
18
 
@@ -20,8 +20,10 @@ Gem::Specification.new do |s|
20
20
 
21
21
  s.add_dependency("actionpack", "~> 3.2.11")
22
22
 
23
+ s.add_development_dependency("railties", "~> 3.2.11")
23
24
  s.add_development_dependency("rake")
24
25
  s.add_development_dependency("rspec", "~> 2.12.0")
26
+ s.add_development_dependency("genspec")
25
27
 
26
28
  # = MANIFEST =
27
29
  s.files = %w[
@@ -34,7 +36,11 @@ Gem::Specification.new do |s|
34
36
  lib/curly/presenter.rb
35
37
  lib/curly/railtie.rb
36
38
  lib/curly/template_handler.rb
39
+ lib/generators/curly/controller/controller_generator.rb
40
+ lib/generators/curly/controller/templates/presenter.rb.erb
41
+ lib/generators/curly/controller/templates/view.html.curly.erb
37
42
  spec/curly_spec.rb
43
+ spec/generators/controller_generator_spec.rb
38
44
  spec/presenter_spec.rb
39
45
  spec/spec_helper.rb
40
46
  spec/template_handler_spec.rb
@@ -26,7 +26,7 @@
26
26
  # See Curly::Presenter for more information on presenters.
27
27
  #
28
28
  module Curly
29
- VERSION = "0.1.1"
29
+ VERSION = "0.2.0"
30
30
 
31
31
  REFERENCE_REGEX = %r(\{\{(\w+)\}\})
32
32
 
@@ -35,6 +35,11 @@ module Curly
35
35
 
36
36
  class << self
37
37
 
38
+ # Compiles a Curly template to Ruby code.
39
+ #
40
+ # template - The template String that should be compiled.
41
+ #
42
+ # Returns a String containing the Ruby code.
38
43
  def compile(template)
39
44
  source = template.inspect
40
45
  source.gsub!(REFERENCE_REGEX) { compile_reference($1) }
@@ -42,6 +47,13 @@ module Curly
42
47
  source
43
48
  end
44
49
 
50
+ # Whether the Curly template is valid. This includes whether all
51
+ # references are available on the presenter class.
52
+ #
53
+ # template - The template String that should be validated.
54
+ # presenter_class - The presenter Class.
55
+ #
56
+ # Returns true if the template is valid, false otherwise.
45
57
  def valid?(template, presenter_class)
46
58
  references = extract_references(template)
47
59
  methods = presenter_class.available_methods.map(&:to_s)
@@ -68,4 +80,6 @@ module Curly
68
80
  end
69
81
  end
70
82
 
83
+ require 'curly/presenter'
84
+ require 'curly/template_handler'
71
85
  require 'curly/railtie' if defined?(Rails)
@@ -12,7 +12,7 @@ module Curly
12
12
  #
13
13
  # A presenter is always instantiated with a context to which it delegates
14
14
  # unknown messages, usually an instance of ActionView::Base provided by
15
- # Rails. See Curly::Handler for a typical use.
15
+ # Rails. See Curly::TemplateHandler for a typical use.
16
16
  #
17
17
  # Examples
18
18
  #
@@ -36,6 +36,7 @@ module Curly
36
36
  # presenter.author #=> "Jackie Chan"
37
37
  #
38
38
  class Presenter
39
+
39
40
  # Initializes the presenter with the given context and options.
40
41
  #
41
42
  # context - An ActionView::Base context.
@@ -48,18 +49,62 @@ module Curly
48
49
  end
49
50
  end
50
51
 
52
+ # The key that should be used to cache the view.
53
+ #
54
+ # Unless `#cache_key` returns nil, the result of rendering the template
55
+ # that the presenter supports will be cached. The return value will be
56
+ # part of the final cache key, along with a digest of the template itself.
57
+ #
58
+ # Any object can be used as a cache key, so long as it
59
+ #
60
+ # - is a String,
61
+ # - responds to #cache_key itself, or
62
+ # - is an Array of a Hash whose items themselves fit either of these
63
+ # criteria.
64
+ #
65
+ # Returns the cache key Object or nil if no caching should be performed.
51
66
  def cache_key
52
67
  nil
53
68
  end
54
69
 
70
+ # The duration that the view should be cached for. Only relevant if
71
+ # `#cache_key` returns a non nil value.
72
+ #
73
+ # If nil, the view will not have an expiration time set.
74
+ #
75
+ # Examples
76
+ #
77
+ # def cache_duration
78
+ # 10.minutes
79
+ # end
80
+ #
81
+ # Returns the Fixnum duration of the cache item, in seconds, or nil if no
82
+ # duration should be set.
55
83
  def cache_duration
56
84
  nil
57
85
  end
58
86
 
87
+ # Whether a method is available to templates rendered with the presenter.
88
+ #
89
+ # Templates can reference "variables", which are simply methods defined on
90
+ # the presenter. By default, only public instance methods can be
91
+ # referenced, and any method defined on Curly::Presenter itself cannot be
92
+ # referenced. This means that methods such as `#cache_key` and #inspect are
93
+ # not available. This is done for safety purposes.
94
+ #
95
+ # This policy can be changed by overriding this method in your presenters.
96
+ #
97
+ # method - The Symbol name of the method.
98
+ #
99
+ # Returns true if the method can be referenced by a template,
100
+ # false otherwise.
59
101
  def method_available?(method)
60
102
  self.class.available_methods.include?(method)
61
103
  end
62
104
 
105
+ # A list of methods available to templates rendered with the presenter.
106
+ #
107
+ # Returns an Array of Symbol method names.
63
108
  def self.available_methods
64
109
  public_instance_methods - Curly::Presenter.public_instance_methods
65
110
  end
@@ -73,6 +118,9 @@ module Curly
73
118
  self.presented_names += args
74
119
  end
75
120
 
121
+ # Delegates private method calls to the current view context.
122
+ #
123
+ # The view context, an instance of ActionView::Base, is set by Rails.
76
124
  def method_missing(method, *args, &block)
77
125
  @_context.public_send(method, *args, &block)
78
126
  end
@@ -1,7 +1,8 @@
1
1
  module Curly
2
2
  class Railtie < Rails::Railtie
3
+ config.app_generators.template_engine :curly
4
+
3
5
  initializer 'curly.initialize_template_handler' do
4
- require 'curly/template_handler'
5
6
  ActionView::Template.register_template_handler :curly, Curly::TemplateHandler
6
7
  end
7
8
  end
@@ -3,10 +3,28 @@ require 'action_view'
3
3
  require 'curly'
4
4
 
5
5
  class Curly::TemplateHandler
6
+
7
+ # The name of the presenter class for a given view path.
8
+ #
9
+ # path - The String path of a view.
10
+ #
11
+ # Examples
12
+ #
13
+ # Curly::TemplateHandler.presenter_name_for_path("foo/bar")
14
+ # #=> "Foo::BarPresenter"
15
+ #
16
+ # Returns the String name of the matching presenter class.
6
17
  def self.presenter_name_for_path(path)
7
18
  "#{path}_presenter".camelize
8
19
  end
9
20
 
21
+ # Handles a Curly template, compiling it to Ruby code. The code will be
22
+ # evaluated in the context of an ActionView::Base instance, having access
23
+ # to a number of variables.
24
+ #
25
+ # template - The ActionView::Template template that should be compiled.
26
+ #
27
+ # Returns a String containing the Ruby code representing the template.
10
28
  def self.call(template)
11
29
  presenter_class = presenter_name_for_path(template.virtual_path)
12
30
 
@@ -0,0 +1,30 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/named_base'
3
+
4
+ module Curly
5
+ module Generators
6
+ class ControllerGenerator < Rails::Generators::NamedBase
7
+ source_root File.expand_path("../templates", __FILE__)
8
+
9
+ argument :actions, type: :array, default: [], banner: "action action"
10
+
11
+ def create_view_files
12
+ base_views_path = File.join("app/views", class_path, file_name)
13
+ base_presenters_path = File.join("app/presenters", class_path, file_name)
14
+
15
+ empty_directory base_views_path
16
+ empty_directory base_presenters_path
17
+
18
+ actions.each do |action|
19
+ @view_path = File.join(base_views_path, "#{action}.html.curly")
20
+ @presenter_path = File.join(base_presenters_path, "#{action}_presenter.rb")
21
+ @action = action
22
+ @presenter_name = "#{class_name}::#{action.capitalize}Presenter"
23
+
24
+ template "view.html.curly.erb", @view_path
25
+ template "presenter.rb.erb", @presenter_path
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,10 @@
1
+ class <%= @presenter_name %> < Curly::Presenter
2
+ # If you need to assign variables to the presenter, you can use the
3
+ # `presents` method.
4
+ #
5
+ # presents :foo, :bar
6
+ #
7
+ # Any public method defined in a presenter class will be available
8
+ # to the Curly template as a variable. Consider making these methods
9
+ # idempotent.
10
+ end
@@ -0,0 +1,2 @@
1
+ <h1><%= class_name %>#<%= @action %></h1>
2
+ <p>Find me in <%= @view_path %></p>
@@ -1,5 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'active_support/core_ext/string/output_safety'
3
2
  require 'curly'
4
3
 
5
4
  describe Curly do
@@ -38,7 +37,6 @@ describe Curly do
38
37
  end
39
38
 
40
39
  let(:presenter) { presenter_class.new }
41
- let(:context) { double("context", presenter: presenter) }
42
40
 
43
41
  it "compiles Curly templates to Ruby code" do
44
42
  evaluate("{{foo}}").should == "FOO"
@@ -85,8 +83,16 @@ describe Curly do
85
83
  end
86
84
  end
87
85
 
88
- def evaluate(template)
86
+ def evaluate(template, &block)
89
87
  code = Curly.compile(template)
90
- context.instance_eval(code)
88
+ context = double("context", presenter: presenter)
89
+
90
+ context.instance_eval(<<-RUBY)
91
+ def self.render
92
+ #{code}
93
+ end
94
+ RUBY
95
+
96
+ context.render(&block)
91
97
  end
92
98
  end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+ require 'genspec'
3
+ require 'generators/curly/controller/controller_generator'
4
+
5
+ describe Curly::Generators::ControllerGenerator do
6
+ with_args "animals/cows", "foo"
7
+
8
+ it "generates a Curly template for each action" do
9
+ subject.should generate("app/views/animals/cows/foo.html.curly") {|content|
10
+ expected_content = "<h1>Animals::Cows#foo</h1>\n" +
11
+ "<p>Find me in app/views/animals/cows/foo.html.curly</p>\n"
12
+
13
+ content.should == expected_content
14
+ }
15
+ end
16
+
17
+ it "generates a Curly presenter for each action" do
18
+ subject.should generate("app/presenters/animals/cows/foo_presenter.rb") {|content|
19
+ expected_content = (<<-RUBY).gsub(/^\s{8}/, "")
20
+ class Animals::Cows::FooPresenter < Curly::Presenter
21
+ # If you need to assign variables to the presenter, you can use the
22
+ # `presents` method.
23
+ #
24
+ # presents :foo, :bar
25
+ #
26
+ # Any public method defined in a presenter class will be available
27
+ # to the Curly template as a variable. Consider making these methods
28
+ # idempotent.
29
+ end
30
+ RUBY
31
+
32
+ content.should == expected_content
33
+ }
34
+ end
35
+ end
@@ -1,6 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'active_support/all'
3
- require 'curly/presenter'
4
2
 
5
3
  describe Curly::Presenter do
6
4
  class CircusPresenter < Curly::Presenter
@@ -0,0 +1 @@
1
+ require 'active_support/all'
@@ -1,7 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'active_support/core_ext/string/output_safety'
3
- require 'active_support/core_ext/hash'
4
- require 'curly/template_handler'
5
2
 
6
3
  describe Curly::TemplateHandler do
7
4
  let :presenter_class do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: curly-templates
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-23 00:00:00.000000000 Z
12
+ date: 2013-02-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: actionpack
@@ -27,6 +27,22 @@ dependencies:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
29
  version: 3.2.11
30
+ - !ruby/object:Gem::Dependency
31
+ name: railties
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 3.2.11
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 3.2.11
30
46
  - !ruby/object:Gem::Dependency
31
47
  name: rake
32
48
  requirement: !ruby/object:Gem::Requirement
@@ -59,8 +75,24 @@ dependencies:
59
75
  - - ~>
60
76
  - !ruby/object:Gem::Version
61
77
  version: 2.12.0
78
+ - !ruby/object:Gem::Dependency
79
+ name: genspec
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
62
94
  description: A view layer for your Rails apps that separates structure and logic.
63
- email: dasch@zendesk.com
95
+ email: daniel.schierbeck@gmail.com.com
64
96
  executables: []
65
97
  extensions: []
66
98
  extra_rdoc_files: []
@@ -74,11 +106,15 @@ files:
74
106
  - lib/curly/presenter.rb
75
107
  - lib/curly/railtie.rb
76
108
  - lib/curly/template_handler.rb
109
+ - lib/generators/curly/controller/controller_generator.rb
110
+ - lib/generators/curly/controller/templates/presenter.rb.erb
111
+ - lib/generators/curly/controller/templates/view.html.curly.erb
77
112
  - spec/curly_spec.rb
113
+ - spec/generators/controller_generator_spec.rb
78
114
  - spec/presenter_spec.rb
79
115
  - spec/spec_helper.rb
80
116
  - spec/template_handler_spec.rb
81
- homepage: http://github.com/zendesk/curly-templates
117
+ homepage: https://github.com/dasch/curly
82
118
  licenses: []
83
119
  post_install_message:
84
120
  rdoc_options:
@@ -93,7 +129,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
93
129
  version: '0'
94
130
  segments:
95
131
  - 0
96
- hash: -3306742458990639659
132
+ hash: -1725225944803924182
97
133
  required_rubygems_version: !ruby/object:Gem::Requirement
98
134
  none: false
99
135
  requirements:
@@ -108,5 +144,7 @@ specification_version: 2
108
144
  summary: Free your views!
109
145
  test_files:
110
146
  - spec/curly_spec.rb
147
+ - spec/generators/controller_generator_spec.rb
111
148
  - spec/presenter_spec.rb
112
149
  - spec/template_handler_spec.rb
150
+ has_rdoc: