curly-templates 2.5.0 → 2.6.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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +20 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +3 -0
  5. data/.yardopts +3 -0
  6. data/CHANGELOG.md +28 -0
  7. data/Gemfile +4 -2
  8. data/README.md +76 -3
  9. data/Rakefile +3 -116
  10. data/circle.yml +1 -1
  11. data/curly-templates.gemspec +6 -83
  12. data/lib/curly.rb +1 -1
  13. data/lib/curly/compiler.rb +2 -12
  14. data/lib/curly/component_compiler.rb +6 -3
  15. data/lib/curly/presenter.rb +32 -20
  16. data/lib/curly/presenter_name_error.rb +16 -0
  17. data/lib/curly/rspec.rb +16 -0
  18. data/lib/curly/version.rb +3 -0
  19. metadata +14 -72
  20. data/perf/compile_benchmark.rb +0 -71
  21. data/perf/compile_profile.rb +0 -64
  22. data/perf/component_benchmark.rb +0 -41
  23. data/spec/attribute_scanner_spec.rb +0 -44
  24. data/spec/collection_blocks_spec.rb +0 -78
  25. data/spec/compiler/collections_spec.rb +0 -230
  26. data/spec/compiler/context_blocks_spec.rb +0 -106
  27. data/spec/compiler_spec.rb +0 -192
  28. data/spec/component_compiler_spec.rb +0 -107
  29. data/spec/component_scanner_spec.rb +0 -36
  30. data/spec/components_spec.rb +0 -43
  31. data/spec/conditional_blocks_spec.rb +0 -40
  32. data/spec/dummy/.gitignore +0 -1
  33. data/spec/dummy/app/controllers/application_controller.rb +0 -2
  34. data/spec/dummy/app/controllers/dashboards_controller.rb +0 -14
  35. data/spec/dummy/app/helpers/application_helper.rb +0 -5
  36. data/spec/dummy/app/presenters/dashboards/collection_presenter.rb +0 -7
  37. data/spec/dummy/app/presenters/dashboards/item_presenter.rb +0 -23
  38. data/spec/dummy/app/presenters/dashboards/new_presenter.rb +0 -29
  39. data/spec/dummy/app/presenters/dashboards/partials_presenter.rb +0 -5
  40. data/spec/dummy/app/presenters/dashboards/show_presenter.rb +0 -12
  41. data/spec/dummy/app/presenters/layouts/application_presenter.rb +0 -21
  42. data/spec/dummy/app/views/dashboards/_item.html.curly +0 -1
  43. data/spec/dummy/app/views/dashboards/collection.html.curly +0 -8
  44. data/spec/dummy/app/views/dashboards/new.html.curly +0 -7
  45. data/spec/dummy/app/views/dashboards/partials.html.curly +0 -3
  46. data/spec/dummy/app/views/dashboards/show.html.curly +0 -3
  47. data/spec/dummy/app/views/layouts/application.html.curly +0 -11
  48. data/spec/dummy/config.ru +0 -4
  49. data/spec/dummy/config/application.rb +0 -12
  50. data/spec/dummy/config/boot.rb +0 -5
  51. data/spec/dummy/config/environment.rb +0 -5
  52. data/spec/dummy/config/environments/test.rb +0 -36
  53. data/spec/dummy/config/routes.rb +0 -6
  54. data/spec/generators/controller_generator_spec.rb +0 -34
  55. data/spec/integration/application_layout_spec.rb +0 -22
  56. data/spec/integration/collection_blocks_spec.rb +0 -37
  57. data/spec/integration/context_blocks_spec.rb +0 -27
  58. data/spec/integration/partials_spec.rb +0 -24
  59. data/spec/matchers/have_structure.rb +0 -29
  60. data/spec/parser_spec.rb +0 -92
  61. data/spec/presenter_spec.rb +0 -247
  62. data/spec/scanner_spec.rb +0 -124
  63. data/spec/spec_helper.rb +0 -45
  64. data/spec/syntax_error_spec.rb +0 -12
  65. data/spec/template_handler_spec.rb +0 -209
data/lib/curly.rb CHANGED
@@ -25,7 +25,6 @@
25
25
  #
26
26
  # See Curly::Presenter for more information on presenters.
27
27
  module Curly
28
- VERSION = "2.5.0"
29
28
 
30
29
  # Compiles a Curly template to Ruby code.
31
30
  #
@@ -52,3 +51,4 @@ require 'curly/compiler'
52
51
  require 'curly/presenter'
53
52
  require 'curly/template_handler'
54
53
  require 'curly/railtie' if defined?(Rails)
54
+ require 'curly/version'
@@ -94,12 +94,7 @@ module Curly
94
94
  name = component.name.singularize
95
95
  counter = "#{name}_counter"
96
96
 
97
- begin
98
- item_presenter_class = presenter_class.presenter_for_name(name)
99
- rescue NameError
100
- raise Curly::Error,
101
- "cannot enumerate `#{name}`, could not find matching presenter class"
102
- end
97
+ item_presenter_class = presenter_class.presenter_for_name(name)
103
98
 
104
99
  output <<-RUBY
105
100
  presenters << presenter
@@ -146,12 +141,7 @@ module Curly
146
141
 
147
142
  name = component.name
148
143
 
149
- begin
150
- item_presenter_class = presenter_class.presenter_for_name(name)
151
- rescue NameError
152
- raise Curly::Error,
153
- "cannot use context `#{name}`, could not find matching presenter class"
154
- end
144
+ item_presenter_class = presenter_class.presenter_for_name(name)
155
145
 
156
146
  output <<-RUBY
157
147
  options_stack << options
@@ -64,8 +64,7 @@ module Curly
64
64
  end
65
65
 
66
66
  def invalid_signature?
67
- positional_params = param_types.select {|type| [:req, :opt].include?(type) }
68
- positional_params.size > 1
67
+ param_types.count { |type| [:req, :opt].include?(type) } > 1
69
68
  end
70
69
 
71
70
  def required_identifier?
@@ -89,7 +88,7 @@ module Curly
89
88
  end
90
89
 
91
90
  def validate_attributes!
92
- attributes.keys.each do |key|
91
+ attributes_collected? || attributes.keys.each do |key|
93
92
  unless attribute_names.include?(key)
94
93
  raise Curly::Error, "`#{method}` does not allow attribute `#{key}`"
95
94
  end
@@ -116,6 +115,10 @@ module Curly
116
115
  map {|type, name| name.to_s }
117
116
  end
118
117
 
118
+ def attributes_collected?
119
+ param_types.include?(:keyrest)
120
+ end
121
+
119
122
  def required_attribute_names
120
123
  @required_attribute_names ||= params.
121
124
  select {|type, name| type == :keyreq }.
@@ -1,3 +1,5 @@
1
+ require 'curly/presenter_name_error'
2
+
1
3
  module Curly
2
4
 
3
5
  # A base class that can be subclassed by concrete presenters.
@@ -154,28 +156,25 @@ module Curly
154
156
  #
155
157
  # Returns the Class or nil if the constant cannot be found.
156
158
  def presenter_for_path(path)
157
- name = presenter_name_for_path(path)
158
-
159
159
  begin
160
- name.constantize
161
- rescue NameError => e
162
- missing_name = e.name.to_s
163
-
164
- # Since we only want to return nil when the constant matching the
165
- # path could not be found, we need to do same hacky matching. If
166
- # the constant's name is Foo::BarPresenter and Foo does not exist,
167
- # we consider that a match. If Foo exists but Foo::BarPresenter does
168
- # not, NameError#name will return :BarPresenter, so we need to match
169
- # that as well.
170
- unless name.start_with?(missing_name) || name.end_with?(missing_name)
171
- raise # The NameError was due to something else, re-raise.
172
- end
160
+ # Assume that the path can be derived without a prefix; In other words
161
+ # from the given path we can look up objects by namespace.
162
+ presenter_for_name(path.camelize, [])
163
+ rescue Curly::PresenterNameError
164
+ nil
173
165
  end
174
166
  end
175
167
 
176
- def presenter_for_name(name)
177
- namespace = to_s.split("::")
178
- class_name = name.camelcase << "Presenter"
168
+ # Retrieve the named presenter with consideration for object scope.
169
+ # The namespace_prefixes are to acknowledge that sometimes we will have
170
+ # a subclass of Curly::Presenter receiving the .presenter_for_name
171
+ # and other times we will not (when we are receiving this message by
172
+ # way of the .presenter_for_path method).
173
+ def presenter_for_name(name, namespace_prefixes = to_s.split('::'))
174
+ full_class_name = name.camelcase << "Presenter"
175
+ relative_namespace = full_class_name.split("::")
176
+ class_name = relative_namespace.pop
177
+ namespace = namespace_prefixes + relative_namespace
179
178
 
180
179
  # Because Rails' autoloading mechanism doesn't work properly with
181
180
  # namespace we need to loop through the namespace ourselves. Ideally,
@@ -185,8 +184,21 @@ module Curly
185
184
  begin
186
185
  full_name = namespace.join("::") << "::" << class_name
187
186
  const_get(full_name)
188
- rescue NameError
189
- raise if namespace.empty?
187
+ rescue NameError => e
188
+ # Due to the way the exception hirearchy works, we need to check
189
+ # that this exception is actually a `NameError` - since other
190
+ # classes can inherit `NameError`, rescue will actually rescue
191
+ # those classes as being under `NameError`, causing this block to
192
+ # be executed for classes that aren't `NameError`s (but are rather
193
+ # subclasses of it), which isn't the desired behavior. This
194
+ # prevents anything but `NameError`s from triggering the resulting
195
+ # code. `NoMethodError` is actually a subclass of `NameError`,
196
+ # so a typo in a file (e.g. `present` instead of `presents`) can
197
+ # cause the library to act as if the class was never defined.
198
+ raise unless e.class == NameError
199
+ if namespace.empty?
200
+ raise Curly::PresenterNameError.new(e, name)
201
+ end
190
202
  namespace.pop
191
203
  retry
192
204
  end
@@ -0,0 +1,16 @@
1
+ require 'curly/error'
2
+
3
+ module Curly
4
+ class PresenterNameError < Error
5
+ attr_reader :original_exception, :name
6
+
7
+ def initialize(original_exception, name)
8
+ @name = name
9
+ @original_exception = original_exception
10
+ end
11
+
12
+ def message
13
+ "cannot use context `#{name}`, could not find matching presenter class"
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ require 'rspec/rails'
2
+
3
+ module Curly
4
+ module RSpec
5
+ module PresenterExampleGroup
6
+ extend ActiveSupport::Concern
7
+ include ::RSpec::Rails::ViewExampleGroup
8
+
9
+ included do
10
+ let(:presenter) { described_class.new(view, view_assigns) }
11
+ end
12
+ end
13
+
14
+ ::RSpec.configuration.include PresenterExampleGroup, type: :presenter
15
+ end
16
+ end
@@ -0,0 +1,3 @@
1
+ module Curly
2
+ VERSION = "2.6.0"
3
+ end
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: 2.5.0
4
+ version: 2.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Schierbeck
@@ -19,7 +19,7 @@ dependencies:
19
19
  version: '3.1'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: '5.0'
22
+ version: '5.1'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -29,7 +29,7 @@ dependencies:
29
29
  version: '3.1'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: '5.0'
32
+ version: '5.1'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: railties
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -39,7 +39,7 @@ dependencies:
39
39
  version: '3.1'
40
40
  - - "<"
41
41
  - !ruby/object:Gem::Version
42
- version: '5.0'
42
+ version: '5.1'
43
43
  type: :development
44
44
  prerelease: false
45
45
  version_requirements: !ruby/object:Gem::Requirement
@@ -49,7 +49,7 @@ dependencies:
49
49
  version: '3.1'
50
50
  - - "<"
51
51
  - !ruby/object:Gem::Version
52
- version: '5.0'
52
+ version: '5.1'
53
53
  - !ruby/object:Gem::Dependency
54
54
  name: rake
55
55
  requirement: !ruby/object:Gem::Requirement
@@ -98,6 +98,10 @@ executables: []
98
98
  extensions: []
99
99
  extra_rdoc_files: []
100
100
  files:
101
+ - ".gitignore"
102
+ - ".rspec"
103
+ - ".travis.yml"
104
+ - ".yardopts"
101
105
  - CHANGELOG.md
102
106
  - CONTRIBUTING.md
103
107
  - Gemfile
@@ -118,61 +122,18 @@ files:
118
122
  - lib/curly/invalid_component.rb
119
123
  - lib/curly/parser.rb
120
124
  - lib/curly/presenter.rb
125
+ - lib/curly/presenter_name_error.rb
121
126
  - lib/curly/presenter_not_found.rb
122
127
  - lib/curly/railtie.rb
128
+ - lib/curly/rspec.rb
123
129
  - lib/curly/scanner.rb
124
130
  - lib/curly/syntax_error.rb
125
131
  - lib/curly/template_handler.rb
132
+ - lib/curly/version.rb
126
133
  - lib/generators/curly/controller/controller_generator.rb
127
134
  - lib/generators/curly/controller/templates/presenter.rb.erb
128
135
  - lib/generators/curly/controller/templates/view.html.curly.erb
129
136
  - lib/rails/projections.json
130
- - perf/compile_benchmark.rb
131
- - perf/compile_profile.rb
132
- - perf/component_benchmark.rb
133
- - spec/attribute_scanner_spec.rb
134
- - spec/collection_blocks_spec.rb
135
- - spec/compiler/collections_spec.rb
136
- - spec/compiler/context_blocks_spec.rb
137
- - spec/compiler_spec.rb
138
- - spec/component_compiler_spec.rb
139
- - spec/component_scanner_spec.rb
140
- - spec/components_spec.rb
141
- - spec/conditional_blocks_spec.rb
142
- - spec/dummy/.gitignore
143
- - spec/dummy/app/controllers/application_controller.rb
144
- - spec/dummy/app/controllers/dashboards_controller.rb
145
- - spec/dummy/app/helpers/application_helper.rb
146
- - spec/dummy/app/presenters/dashboards/collection_presenter.rb
147
- - spec/dummy/app/presenters/dashboards/item_presenter.rb
148
- - spec/dummy/app/presenters/dashboards/new_presenter.rb
149
- - spec/dummy/app/presenters/dashboards/partials_presenter.rb
150
- - spec/dummy/app/presenters/dashboards/show_presenter.rb
151
- - spec/dummy/app/presenters/layouts/application_presenter.rb
152
- - spec/dummy/app/views/dashboards/_item.html.curly
153
- - spec/dummy/app/views/dashboards/collection.html.curly
154
- - spec/dummy/app/views/dashboards/new.html.curly
155
- - spec/dummy/app/views/dashboards/partials.html.curly
156
- - spec/dummy/app/views/dashboards/show.html.curly
157
- - spec/dummy/app/views/layouts/application.html.curly
158
- - spec/dummy/config.ru
159
- - spec/dummy/config/application.rb
160
- - spec/dummy/config/boot.rb
161
- - spec/dummy/config/environment.rb
162
- - spec/dummy/config/environments/test.rb
163
- - spec/dummy/config/routes.rb
164
- - spec/generators/controller_generator_spec.rb
165
- - spec/integration/application_layout_spec.rb
166
- - spec/integration/collection_blocks_spec.rb
167
- - spec/integration/context_blocks_spec.rb
168
- - spec/integration/partials_spec.rb
169
- - spec/matchers/have_structure.rb
170
- - spec/parser_spec.rb
171
- - spec/presenter_spec.rb
172
- - spec/scanner_spec.rb
173
- - spec/spec_helper.rb
174
- - spec/syntax_error_spec.rb
175
- - spec/template_handler_spec.rb
176
137
  homepage: https://github.com/zendesk/curly
177
138
  licenses:
178
139
  - apache2
@@ -194,28 +155,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
194
155
  version: '0'
195
156
  requirements: []
196
157
  rubyforge_project:
197
- rubygems_version: 2.2.2
158
+ rubygems_version: 2.4.5.1
198
159
  signing_key:
199
160
  specification_version: 2
200
161
  summary: Free your views!
201
- test_files:
202
- - spec/attribute_scanner_spec.rb
203
- - spec/collection_blocks_spec.rb
204
- - spec/compiler/collections_spec.rb
205
- - spec/compiler/context_blocks_spec.rb
206
- - spec/compiler_spec.rb
207
- - spec/component_compiler_spec.rb
208
- - spec/component_scanner_spec.rb
209
- - spec/components_spec.rb
210
- - spec/conditional_blocks_spec.rb
211
- - spec/generators/controller_generator_spec.rb
212
- - spec/integration/application_layout_spec.rb
213
- - spec/integration/collection_blocks_spec.rb
214
- - spec/integration/context_blocks_spec.rb
215
- - spec/integration/partials_spec.rb
216
- - spec/parser_spec.rb
217
- - spec/presenter_spec.rb
218
- - spec/scanner_spec.rb
219
- - spec/syntax_error_spec.rb
220
- - spec/template_handler_spec.rb
162
+ test_files: []
221
163
  has_rdoc:
@@ -1,71 +0,0 @@
1
- require 'bundler/setup'
2
- require 'benchmark/ips'
3
-
4
- ENV["RAILS_ENV"] = "test"
5
-
6
- require_relative '../spec/dummy/config/environment'
7
-
8
- class TestPresenter < Curly::Presenter
9
- def foo
10
- end
11
-
12
- def bar
13
- end
14
-
15
- def form(&block)
16
- xcontent_tag :form, block.call
17
- end
18
-
19
- class FormPresenter < Curly::Presenter
20
- def fields
21
- %w[]
22
- end
23
-
24
- class FieldPresenter < Curly::Presenter
25
- presents :field
26
-
27
- def field_name
28
- @field
29
- end
30
- end
31
- end
32
- end
33
-
34
- # Build a huge template.
35
- TEMPLATE = <<-CURLY
36
- <h1>{{foo}}</h1>
37
- <h2>{{bar}}</h2>
38
-
39
- {{@form}}
40
- {{*fields}}
41
- <input name={{field_name}}><br>
42
- {{/fields}}
43
- {{*fields}}
44
- <input name={{field_name}}><br>
45
- {{/fields}}
46
- {{*fields}}
47
- <input name={{field_name}}><br>
48
- {{/fields}}
49
- {{*fields}}
50
- <input name={{field_name}}><br>
51
- {{/fields}}
52
- {{*fields}}
53
- <input name={{field_name}}><br>
54
- {{/fields}}
55
- {{*fields}}
56
- <input name={{field_name}}><br>
57
- {{/fields}}
58
- {{/form}}
59
- CURLY
60
-
61
- Benchmark.ips do |x|
62
- x.report "compiling a huge template" do
63
- Curly::Compiler.compile(TEMPLATE * 100, TestPresenter)
64
- end
65
-
66
- x.report "compiling a normal template" do
67
- Curly::Compiler.compile(TEMPLATE, TestPresenter)
68
- end
69
-
70
- x.compare!
71
- end
@@ -1,64 +0,0 @@
1
- require 'bundler/setup'
2
- require 'benchmark/ips'
3
- require 'stackprof'
4
-
5
- ENV["RAILS_ENV"] = "test"
6
-
7
- require_relative '../spec/dummy/config/environment'
8
-
9
- class TestPresenter < Curly::Presenter
10
- def foo
11
- end
12
-
13
- def bar
14
- end
15
-
16
- def form(&block)
17
- xcontent_tag :form, block.call
18
- end
19
-
20
- class FormPresenter < Curly::Presenter
21
- def fields
22
- %w[]
23
- end
24
-
25
- class FieldPresenter < Curly::Presenter
26
- presents :field
27
-
28
- def field_name
29
- @field
30
- end
31
- end
32
- end
33
- end
34
-
35
- # Build a huge template.
36
- TEMPLATE = <<-CURLY
37
- <h1>{{foo}}</h1>
38
- <h2>{{bar}}</h2>
39
-
40
- {{@form}}
41
- {{*fields}}
42
- <input name={{field_name}}><br>
43
- {{/fields}}
44
- {{*fields}}
45
- <input name={{field_name}}><br>
46
- {{/fields}}
47
- {{*fields}}
48
- <input name={{field_name}}><br>
49
- {{/fields}}
50
- {{*fields}}
51
- <input name={{field_name}}><br>
52
- {{/fields}}
53
- {{*fields}}
54
- <input name={{field_name}}><br>
55
- {{/fields}}
56
- {{*fields}}
57
- <input name={{field_name}}><br>
58
- {{/fields}}
59
- {{/form}}
60
- CURLY
61
-
62
- StackProf.run(mode: :cpu, out: "tmp/stackprof-cpu-compile.dump") do
63
- Curly::Compiler.compile(TEMPLATE * 100, TestPresenter)
64
- end