curly-templates 0.1.1 → 0.2.0

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.
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: