lotus-view 0.0.0 → 0.1.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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +6 -15
  3. data/.travis.yml +6 -0
  4. data/.yardopts +3 -0
  5. data/Gemfile +13 -2
  6. data/README.md +514 -3
  7. data/Rakefile +17 -1
  8. data/lib/lotus/layout.rb +132 -0
  9. data/lib/lotus/presenter.rb +70 -0
  10. data/lib/lotus/view/dsl.rb +247 -0
  11. data/lib/lotus/view/inheritable.rb +50 -0
  12. data/lib/lotus/view/rendering/layout_finder.rb +104 -0
  13. data/lib/lotus/view/rendering/layout_registry.rb +63 -0
  14. data/lib/lotus/view/rendering/layout_scope.rb +138 -0
  15. data/lib/lotus/view/rendering/null_layout.rb +52 -0
  16. data/lib/lotus/view/rendering/null_template.rb +79 -0
  17. data/lib/lotus/view/rendering/partial.rb +29 -0
  18. data/lib/lotus/view/rendering/partial_finder.rb +41 -0
  19. data/lib/lotus/view/rendering/registry.rb +129 -0
  20. data/lib/lotus/view/rendering/scope.rb +48 -0
  21. data/lib/lotus/view/rendering/template.rb +56 -0
  22. data/lib/lotus/view/rendering/template_finder.rb +53 -0
  23. data/lib/lotus/view/rendering/templates_finder.rb +85 -0
  24. data/lib/lotus/view/rendering/view_finder.rb +37 -0
  25. data/lib/lotus/view/rendering.rb +265 -0
  26. data/lib/lotus/view/template.rb +45 -0
  27. data/lib/lotus/view/version.rb +4 -1
  28. data/lib/lotus/view.rb +180 -2
  29. data/lib/lotus-view.rb +1 -0
  30. data/lotus-view.gemspec +15 -11
  31. data/test/fixtures/templates/app/app_view.html.erb +0 -0
  32. data/test/fixtures/templates/app/view.html.erb +0 -0
  33. data/test/fixtures/templates/application.html.erb +10 -0
  34. data/test/fixtures/templates/articles/_form.html.erb +4 -0
  35. data/test/fixtures/templates/articles/alternative_new.html.erb +1 -0
  36. data/test/fixtures/templates/articles/index.atom.erb +5 -0
  37. data/test/fixtures/templates/articles/index.html.erb +3 -0
  38. data/test/fixtures/templates/articles/index.json.erb +9 -0
  39. data/test/fixtures/templates/articles/index.rss.erb +0 -0
  40. data/test/fixtures/templates/articles/new.html.erb +7 -0
  41. data/test/fixtures/templates/articles/show.html.erb +1 -0
  42. data/test/fixtures/templates/articles/show.json.erb +5 -0
  43. data/test/fixtures/templates/contacts/show.html.haml +1 -0
  44. data/test/fixtures/templates/dashboard/index.html.erb +2 -0
  45. data/test/fixtures/templates/hello_world_view.html.erb +1 -0
  46. data/test/fixtures/templates/index_view.html.erb +1 -0
  47. data/test/fixtures/templates/json_render_view.json.erb +3 -0
  48. data/test/fixtures/templates/render_view.html.erb +1 -0
  49. data/test/fixtures/templates/shared/_sidebar.html.erb +1 -0
  50. data/test/fixtures.rb +187 -0
  51. data/test/layout_test.rb +10 -0
  52. data/test/load_test.rb +79 -0
  53. data/test/presenter_test.rb +31 -0
  54. data/test/rendering_test.rb +125 -0
  55. data/test/root_test.rb +38 -0
  56. data/test/test_helper.rb +24 -0
  57. data/test/version_test.rb +7 -0
  58. data/test/view_test.rb +27 -0
  59. metadata +137 -10
@@ -0,0 +1,85 @@
1
+ require 'lotus/view/template'
2
+
3
+ module Lotus
4
+ module View
5
+ module Rendering
6
+ # Find templates for a view
7
+ #
8
+ # @api private
9
+ # @since 0.1.0
10
+ #
11
+ # @see View::Template
12
+ class TemplatesFinder
13
+ FORMAT = '*'.freeze
14
+ ENGINES = '*'.freeze
15
+
16
+ # Initialize a finder
17
+ #
18
+ # @param view [Class] the view
19
+ #
20
+ # @api private
21
+ # @since 0.1.0
22
+ def initialize(view)
23
+ @view = view
24
+ end
25
+
26
+ # Find all the associated templates to the view.
27
+ # It looks for templates under the root path of the view, that are
28
+ # matching the template name
29
+ #
30
+ # @return [Array<Lotus::View::Template>] the templates
31
+ #
32
+ # @api private
33
+ # @since 0.1.0
34
+ #
35
+ # @see Lotus::View::Dsl#root
36
+ # @see Lotus::View::Dsl#template
37
+ #
38
+ # @example
39
+ # require 'lotus/view'
40
+ #
41
+ # module Articles
42
+ # class Show
43
+ # include Lotus::View
44
+ # end
45
+ # end
46
+ #
47
+ # Articles::Show.root # => "/path/to/templates"
48
+ # Articles::Show.template # => "articles/show"
49
+ #
50
+ # # This view has a template:
51
+ # #
52
+ # # "/path/to/templates/articles/show.html.erb"
53
+ #
54
+ # Lotus::View::Rendering::TemplatesFinder.new(Articles::Show).find
55
+ # # => [#<Lotus::View::Template:0x007f8a0a86a970 ... @file="/path/to/templates/articles/show.html.erb">]
56
+ def find
57
+ Dir.glob( "#{ [root, template_name].join(separator) }.#{ format }.#{ engines }" ).map do |template|
58
+ View::Template.new template
59
+ end
60
+ end
61
+
62
+ protected
63
+ def template_name
64
+ @view.template
65
+ end
66
+
67
+ def root
68
+ @view.root
69
+ end
70
+
71
+ def separator
72
+ ::File::SEPARATOR
73
+ end
74
+
75
+ def format
76
+ FORMAT
77
+ end
78
+
79
+ def engines
80
+ ENGINES
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,37 @@
1
+ module Lotus
2
+ module View
3
+ module Rendering
4
+ # Find a view
5
+ #
6
+ # @api private
7
+ # @since 0.1.0
8
+ #
9
+ # @see Lotus::View::Rendering::Registry
10
+ class ViewFinder
11
+ # Initialize a finder
12
+ #
13
+ # @param view [Class] the superclass view
14
+ #
15
+ # @api private
16
+ # @since 0.1.0
17
+ def initialize(view)
18
+ @view = view
19
+ end
20
+
21
+ # Find a view for the given template.
22
+ # It looks up for the current view and its subclasses.
23
+ #
24
+ # @param template [Lotus::View::Template] a template to be associated
25
+ # to a view
26
+ #
27
+ # @return [Class] a view associated with the given template
28
+ #
29
+ # @api private
30
+ # @since 0.1.0
31
+ def find(template)
32
+ @view.subclasses.find {|v| v.format == template.format } || @view
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,265 @@
1
+ require 'lotus/view/rendering/registry'
2
+ require 'lotus/view/rendering/scope'
3
+
4
+ module Lotus
5
+ module View
6
+ # Rendering methods
7
+ #
8
+ # @since 0.1.0
9
+ #
10
+ # @see Lotus::View::Rendering::InstanceMethods
11
+ module Rendering
12
+ def self.extended(base)
13
+ base.class_eval do
14
+ include InstanceMethods
15
+ end
16
+ end
17
+
18
+ module InstanceMethods
19
+ # Initialize a view
20
+ #
21
+ # @param template [Lotus::View::Template] the template to render
22
+ # @param locals [Hash] a set of objects available during the rendering
23
+ # process.
24
+ #
25
+ # @since 0.1.0
26
+ #
27
+ # @see Lotus::View::Template
28
+ #
29
+ # @example
30
+ # require 'lotus/view'
31
+ #
32
+ # class IndexView
33
+ # include Lotus::View
34
+ # end
35
+ #
36
+ # template = Lotus::View::Template.new('index.html.erb')
37
+ # view = IndexView.new(template, {article: article})
38
+ def initialize(template, locals)
39
+ @template = template
40
+ @locals = locals
41
+ @scope = Scope.new(self, @locals)
42
+ end
43
+
44
+ # Render the template by bounding the local scope.
45
+ # If it uses a layout, it renders the template first and then the
46
+ # control passes to the layout.
47
+ #
48
+ # Override this method for custom rendering policies.
49
+ # For instance, when a serializer is used and there isn't the need of
50
+ # a template.
51
+ #
52
+ # @return [String] the output of the rendering process
53
+ #
54
+ # @raise [Lotus::View::MissingTemplateError] if the template is nil
55
+ #
56
+ # @since 0.1.0
57
+ #
58
+ # @see Lotus::View::Layout
59
+ #
60
+ # @example with template
61
+ # require 'lotus/view'
62
+ #
63
+ # class IndexView
64
+ # include Lotus::View
65
+ # end
66
+ #
67
+ # template = Lotus::View::Template.new('index.html.erb')
68
+ # view = IndexView.new(template, {article: article})
69
+ #
70
+ # view.render # => <h1>Introducing Lotus::view</h1> ...
71
+ #
72
+ # @example with template and layout
73
+ # require 'lotus/view'
74
+ #
75
+ # class ApplicationLayout
76
+ # include Lotus::View::Layout
77
+ # end
78
+ #
79
+ # class IndexView
80
+ # include Lotus::View
81
+ # layout :application
82
+ # end
83
+ #
84
+ # template = Lotus::View::Template.new('index.html.erb')
85
+ # view = IndexView.new(template, {article: article})
86
+ #
87
+ # view.render # => <html> ... <h1>Introducing Lotus::view</h1> ...
88
+ #
89
+ # @example with custom rendering
90
+ # require 'lotus/view'
91
+ #
92
+ # class IndexView
93
+ # include Lotus::View
94
+ #
95
+ # def render
96
+ # ArticleSerializer.new(article).render
97
+ # end
98
+ # end
99
+ #
100
+ # view = IndexView.new(nil, {article: article})
101
+ #
102
+ # view.render # => {title: ...}
103
+ def render
104
+ layout.render
105
+ end
106
+
107
+ protected
108
+ # The output of the template rendering process.
109
+ #
110
+ # @return [String] the rendering output
111
+ #
112
+ # @raise [Lotus::View::MissingTemplateError] if the template is nil
113
+ #
114
+ # @api private
115
+ # @since 0.1.0
116
+ def rendered
117
+ template.render @scope
118
+ end
119
+
120
+ # The layout.
121
+ #
122
+ # @return [Class, Lotus::View::Rendering::NullLayout]
123
+ #
124
+ # @see Lotus::View::Layout
125
+ # @see Lotus::View.layout
126
+ # @see Lotus::View::Dsl#layout
127
+ #
128
+ # @api private
129
+ # @since 0.1.0
130
+ def layout
131
+ @layout ||= self.class.layout.new(@scope, rendered)
132
+ end
133
+
134
+ # The template.
135
+ #
136
+ # @return [Lotus::View::Template] the template
137
+ #
138
+ # @raise [Lotus::View::MissingTemplateError] if the template is nil
139
+ #
140
+ # @api private
141
+ # @since 0.1.0
142
+ def template
143
+ @template or raise MissingTemplateError.new(self.class.template, @scope.format)
144
+ end
145
+
146
+ # A set of objects available during the rendering process.
147
+ #
148
+ # @return [Hash]
149
+ #
150
+ # @see Lotus::View#initialize
151
+ #
152
+ # @api private
153
+ # @since 0.1.0
154
+ def locals
155
+ @locals
156
+ end
157
+
158
+ # Delegates missing methods to the scope.
159
+ #
160
+ # @see Lotus::View::Rendering::Scope
161
+ #
162
+ # @api private
163
+ # @since 0.1.0
164
+ #
165
+ # @example
166
+ # require 'lotus/view'
167
+ #
168
+ # class IndexView
169
+ # include Lotus::View
170
+ # end
171
+ #
172
+ # template = Lotus::View::Template.new('index.html.erb')
173
+ # view = IndexView.new(template, {article: article})
174
+ #
175
+ # view.article # => #<Article:0x007fb0bbd3b6e8>
176
+ def method_missing(m)
177
+ @scope.__send__ m
178
+ end
179
+ end
180
+
181
+ # Render the given context and locals with the appropriate template.
182
+ # If there are registered subclasses, it choose the right class, according
183
+ # to the requested format.
184
+ #
185
+ # @param context [Hash] the context for the rendering process
186
+ # @option context [Symbol] :format the requested format
187
+ #
188
+ # @return [String] the output of the rendering process
189
+ #
190
+ # @raise [Lotus::View::MissingTemplateError] if it can't find a template
191
+ # for the given context
192
+ #
193
+ # @raise [Lotus::View::MissingFormatError] if the given context doesn't
194
+ # have the :format key
195
+ #
196
+ # @since 0.1.0
197
+ #
198
+ # @see Lotus::View#initialize
199
+ # @see Lotus::View#render
200
+ #
201
+ # @example
202
+ # require 'lotus/view'
203
+ #
204
+ # article = OpenStruct.new(title: 'Hello')
205
+ #
206
+ # module Articles
207
+ # class Show
208
+ # include Lotus::View
209
+ #
210
+ # def title
211
+ # @title ||= article.title.upcase
212
+ # end
213
+ # end
214
+ #
215
+ # class JsonShow < Show
216
+ # format :json
217
+ #
218
+ # def title
219
+ # super.downcase
220
+ # end
221
+ # end
222
+ # end
223
+ #
224
+ # Lotus::View.root = '/path/to/templates'
225
+ # Lotus::View.load!
226
+ #
227
+ # Articles::Show.render(format: :html, article: article)
228
+ # # => renders `articles/show.html.erb`
229
+ #
230
+ # Articles::Show.render(format: :json, article: article)
231
+ # # => renders `articles/show.json.erb`
232
+ #
233
+ # Articles::Show.render(format: :xml, article: article)
234
+ # # => raises Lotus::View::MissingTemplateError
235
+ def render(context)
236
+ registry.resolve(context).render
237
+ end
238
+
239
+ protected
240
+
241
+ # Loading mechanism hook.
242
+ #
243
+ # @api private
244
+ # @since 0.1.0
245
+ #
246
+ # @see Lotus::View.load!
247
+ def load!
248
+ super
249
+ registry.freeze
250
+ end
251
+
252
+ private
253
+
254
+ # The registry that holds all the registered subclasses.
255
+ #
256
+ # @api private
257
+ # @since 0.1.0
258
+ #
259
+ # @see Lotus::View::Rendering::Registry
260
+ def registry
261
+ @@registry ||= Registry.new(self)
262
+ end
263
+ end
264
+ end
265
+ end
@@ -0,0 +1,45 @@
1
+ require 'tilt'
2
+
3
+ module Lotus
4
+ module View
5
+ # A logic-less template.
6
+ #
7
+ # @since 0.1.0
8
+ class Template
9
+ def initialize(template)
10
+ @_template = Tilt.new(template)
11
+ end
12
+
13
+ # Returns the format that the template handles.
14
+ #
15
+ # @return [String] the format name
16
+ #
17
+ # @since 0.1.0
18
+ #
19
+ # @example
20
+ # require 'lotus/view'
21
+ #
22
+ # template = Lotus::View::Template.new('index.html.erb')
23
+ # template.format # => 'html'
24
+ def format
25
+ @_template.basename.match(/(\.[^.]+)/).to_s.
26
+ gsub('.', ''). # TODO shame on me, this should be part of the regex above
27
+ to_sym
28
+ end
29
+
30
+ # Render the template within the context of the given scope.
31
+ #
32
+ # @param scope [Lotus::View::Scope] the rendering scope
33
+ #
34
+ # @return [String] the output of the rendering process
35
+ #
36
+ # @api private
37
+ # @since 0.1.0
38
+ #
39
+ # @see Lotus::View::Scope
40
+ def render(scope, &blk)
41
+ @_template.render(scope, {}, &blk)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -1,5 +1,8 @@
1
1
  module Lotus
2
2
  module View
3
- VERSION = "0.0.0"
3
+ # Defines the version
4
+ #
5
+ # @since 0.1.0
6
+ VERSION = '0.1.0'.freeze
4
7
  end
5
8
  end
data/lib/lotus/view.rb CHANGED
@@ -1,7 +1,185 @@
1
- require "lotus/view/version"
1
+ require 'set'
2
+ require 'pathname'
3
+ require 'lotus/view/version'
4
+ require 'lotus/view/inheritable'
5
+ require 'lotus/view/rendering'
6
+ require 'lotus/view/dsl'
7
+ require 'lotus/layout'
8
+ require 'lotus/presenter'
2
9
 
3
10
  module Lotus
11
+ # View
12
+ #
13
+ # @since 0.1.0
4
14
  module View
5
- # Your code goes here...
15
+ # Missing template error
16
+ #
17
+ # This is raised at the runtime when Lotus::View cannot find a template for
18
+ # the requested format.
19
+ #
20
+ # We can't raise this error during the loading phase, because at that time
21
+ # we don't know if a view implements its own rendering policy.
22
+ # A view is allowed to override `#render`, and this scenario can make the
23
+ # presence of a template useless. One typical example is the usage of a
24
+ # serializer that returns the output string, without rendering a template.
25
+ #
26
+ # @since 0.1.0
27
+ class MissingTemplateError < ::StandardError
28
+ def initialize(template, format)
29
+ super("Can't find template '#{ template }' for '#{ format }' format.")
30
+ end
31
+ end
32
+
33
+ # Missing format error
34
+ #
35
+ # This is raised at the runtime when rendering context lacks of the :format
36
+ # key.
37
+ #
38
+ # @since 0.1.0
39
+ #
40
+ # @see Lotus::View::Rendering#render
41
+ class MissingFormatError < ::StandardError
42
+ end
43
+
44
+ # Register a view
45
+ #
46
+ # @api private
47
+ # @since 0.1.0
48
+ #
49
+ # @example
50
+ # require 'lotus/view'
51
+ #
52
+ # class IndexView
53
+ # include Lotus::View
54
+ # end
55
+ def self.included(base)
56
+ base.class_eval do
57
+ extend Inheritable.dup
58
+ extend Dsl.dup
59
+ extend Rendering.dup
60
+ end
61
+
62
+ views.add(base)
63
+ end
64
+
65
+ # Set the directory root where templates are located
66
+ #
67
+ # @param root [String] the root path
68
+ #
69
+ # @see Lotus::View.root
70
+ #
71
+ # @since 0.1.0
72
+ #
73
+ # @example
74
+ # require 'lotus/view'
75
+ #
76
+ # Lotus::View.root = '/path/to/templates'
77
+ def self.root=(root)
78
+ @root = Pathname.new(root) rescue nil
79
+ end
80
+
81
+ # Returns the directory root where templates are located.
82
+ # If not already set, it returns the current directory.
83
+ #
84
+ # @return [Pathname] the root path for templates
85
+ #
86
+ # @see Lotus::View.root=
87
+ #
88
+ # @since 0.1.0
89
+ #
90
+ # @example with already set value
91
+ # require 'lotus/view'
92
+ #
93
+ # Lotus::View.root = '/path/to/templates'
94
+ # Lotus::View.root # => #<Pathname:/path/to/templates>
95
+ #
96
+ # @example with missing set value
97
+ # require 'lotus/view'
98
+ #
99
+ # Lotus::View.root # => #<Pathname:.>
100
+ def self.root
101
+ @root ||= begin
102
+ self.root = '.'
103
+ @root
104
+ end
105
+ end
106
+
107
+ # Sets the default layout for all the registered views.
108
+ #
109
+ # @param layout [Symbol] the layout name
110
+ #
111
+ # @since 0.1.0
112
+ #
113
+ # @see Lotus::View::Dsl#layout
114
+ # @see Lotus::View.load!
115
+ #
116
+ # @example
117
+ # require 'lotus/view'
118
+ #
119
+ # Lotus::View.layout = :application
120
+ #
121
+ # class IndexView
122
+ # include Lotus::View
123
+ # end
124
+ #
125
+ # Lotus::View.load!
126
+ # IndexView.layout # => ApplicationLayout
127
+ def self.layout=(layout)
128
+ @layout = Rendering::LayoutFinder.find(layout)
129
+ end
130
+
131
+ # Returns the default layout to assign to the registered views.
132
+ # If not already set, it returns a <tt>Rendering::NullLayout</tt>.
133
+ #
134
+ # @return [Class,Rendering::NullLayout] depends if already set or not.
135
+ #
136
+ # @since 0.1.0
137
+ #
138
+ # @see Lotus::View.layout=
139
+ def self.layout
140
+ @layout ||= Rendering::NullLayout
141
+ end
142
+
143
+ # A set of registered views.
144
+ #
145
+ # @return [Set] all the registered views.
146
+ #
147
+ # @api private
148
+ # @since 0.1.0
149
+ def self.views
150
+ @views ||= Set.new
151
+ end
152
+
153
+ # A set of registered layouts.
154
+ #
155
+ # @return [Set] all the registered layout.
156
+ #
157
+ # @api private
158
+ # @since 0.1.0
159
+ def self.layouts
160
+ @layouts ||= Set.new
161
+ end
162
+
163
+ #FIXME extract a Loader class
164
+ def self.load!
165
+ root.freeze
166
+ layout.freeze
167
+ views.freeze
168
+
169
+ views.each do |view|
170
+ view.send(:load!)
171
+ end
172
+
173
+ layouts.each do |layout|
174
+ layout.send(:load!)
175
+ end
176
+ end
177
+
178
+ def self.unload!
179
+ instance_variable_set(:@root, nil)
180
+ instance_variable_set(:@layout, nil)
181
+ instance_variable_set(:@views, Set.new)
182
+ instance_variable_set(:@layouts, Set.new)
183
+ end
6
184
  end
7
185
  end
data/lib/lotus-view.rb ADDED
@@ -0,0 +1 @@
1
+ require 'lotus/view'
data/lotus-view.gemspec CHANGED
@@ -4,20 +4,24 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'lotus/view/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = "lotus-view"
7
+ spec.name = 'lotus-view'
8
8
  spec.version = Lotus::View::VERSION
9
- spec.authors = ["Luca Guidi"]
10
- spec.email = ["me@lucaguidi.com"]
11
- spec.summary = %q{View layer for Lotus}
9
+ spec.authors = ['Luca Guidi']
10
+ spec.email = ['me@lucaguidi.com']
12
11
  spec.description = %q{View layer for Lotus}
13
- spec.homepage = ""
14
- spec.license = "MIT"
12
+ spec.summary = %q{View layer for Lotus, with a separation between views and templates}
13
+ spec.homepage = 'http://lotusrb.org'
14
+ spec.license = 'MIT'
15
15
 
16
16
  spec.files = `git ls-files`.split($/)
17
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ["lib"]
17
+ spec.executables = []
18
+ spec.test_files = spec.files.grep(%r{^(test)/})
19
+ spec.require_paths = ['lib']
20
20
 
21
- spec.add_development_dependency "bundler", "~> 1.5"
22
- spec.add_development_dependency "rake"
21
+ spec.add_runtime_dependency 'tilt', '~> 2.0', '>= 2.0.1'
22
+ spec.add_runtime_dependency 'lotus-utils', '~> 0.1'
23
+
24
+ spec.add_development_dependency 'bundler', '~> 1.5'
25
+ spec.add_development_dependency 'minitest', '~> 5'
26
+ spec.add_development_dependency 'rake', '~> 10'
23
27
  end
File without changes
File without changes
@@ -0,0 +1,10 @@
1
+ <html>
2
+ <head>
3
+ <title><%= title %></title>
4
+ </head>
5
+
6
+ <body>
7
+ <%= render partial: 'shared/sidebar' %>
8
+ <%= yield %>
9
+ </body>
10
+ </html>
@@ -0,0 +1,4 @@
1
+ <form>
2
+ <input type="hidden" name="secret" value="<%= secret %>" />
3
+ <input type="text" name="article[title]" value="<%= article.title %>" />
4
+ </form>
@@ -0,0 +1 @@
1
+ <%= render template: 'articles/new', locals: { errors: {} } %>
@@ -0,0 +1,5 @@
1
+ <entry>
2
+ <% articles.each do |article| %>
3
+ <title><%= article.title %></title>
4
+ <% end %>
5
+ <entry>