dry-view 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -4
- data/CHANGELOG.md +14 -0
- data/CONTRIBUTING.md +29 -0
- data/Gemfile +1 -2
- data/dry-view.gemspec +1 -1
- data/lib/dry/view/controller.rb +10 -6
- data/lib/dry/view/decorator.rb +1 -1
- data/lib/dry/view/exposure.rb +54 -16
- data/lib/dry/view/exposures.rb +2 -2
- data/lib/dry/view/missing_renderer.rb +15 -0
- data/lib/dry/view/part.rb +3 -10
- data/lib/dry/view/renderer.rb +15 -3
- data/lib/dry/view/scope.rb +1 -9
- data/lib/dry/view/version.rb +1 -1
- data/spec/fixtures/templates/_hello.html.slim +1 -0
- data/spec/fixtures/templates/edit.html.slim +11 -0
- data/spec/fixtures/templates/greeting.html.slim +2 -0
- data/spec/integration/exposures_spec.rb +114 -19
- data/spec/spec_helper.rb +1 -1
- data/spec/unit/controller_spec.rb +20 -19
- data/spec/unit/exposure_spec.rb +56 -16
- data/spec/unit/exposures_spec.rb +33 -3
- data/spec/unit/part_spec.rb +55 -40
- data/spec/unit/renderer_spec.rb +38 -11
- data/spec/unit/scope_spec.rb +4 -9
- metadata +12 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ba3055d4bb318adbf1cc7718433873c0f8726e26
|
4
|
+
data.tar.gz: 9e09c2f6cf9b340010dcda9319c23b6d78d48c61
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0decd3ced65ee18f4f4bd95c18af6866c53fba4ed92c1e6a2774f8e8bdc787183ee90a260c5904c5a9b661cf106f822e60bd48ba4b4d89ff33fad630daf1eccc
|
7
|
+
data.tar.gz: 5b7792fd0b18d5c9dcd2c10d53d3f817fd643ee90e97d866f68e8920f543126d4fed444afa9e0cae1193fa7cde5794cb9d54a16d8d63a1f9314228bc23171308
|
data/.travis.yml
CHANGED
@@ -13,10 +13,9 @@ after_success:
|
|
13
13
|
# Send coverage report from the job #1 == current MRI release
|
14
14
|
- '[ "${TRAVIS_JOB_NUMBER#*.}" = "1" ] && [ "$TRAVIS_BRANCH" = "master" ] && bundle exec codeclimate-test-reporter'
|
15
15
|
rvm:
|
16
|
-
- 2.4.
|
17
|
-
- 2.3.
|
18
|
-
- 2.2.
|
19
|
-
- 2.1.10
|
16
|
+
- 2.4.2
|
17
|
+
- 2.3.5
|
18
|
+
- 2.2.8
|
20
19
|
- jruby-9.1.6.0
|
21
20
|
env:
|
22
21
|
global:
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
# 0.4.0 / 2017-11-01
|
2
|
+
|
3
|
+
### Added
|
4
|
+
|
5
|
+
- Raise a helpful error when trying to render a template or partial that cannot be found (GustavoCaso)
|
6
|
+
- Raise a helpful error when trying to call a view controller with no template configured (timriley)
|
7
|
+
- Allow a default to be specified for pass-through exposures with the `default:` option (GustavoCaso)
|
8
|
+
|
9
|
+
### Changed
|
10
|
+
|
11
|
+
- [BREAKING] Exposures specify the input data they require using keyword arguments. This includes support for providing default values (via the keyword argument) for keys that are missing from the input data (GustavoCaso)
|
12
|
+
- Allow `Dry::View::Part` instances to be created without explicitly passing a `renderer`. This is helpful for unit testing view parts that don't need to render anything (dNitza)
|
13
|
+
- Partials can be nested within additional sub-directories by rendering them their relative path as their name, e.g. `render(:"foo/bar")` will look for a `foo/_bar.html.slim` template within the normal template lookup paths (timriley)
|
14
|
+
|
1
15
|
# 0.3.0 / 2017-05-14
|
2
16
|
|
3
17
|
This release reintroduces view parts in a more helpful form. You can provide your own custom view part classes to encapsulate your view logic, as well as a decorator for custom, shared behavior arouund view part wrapping.
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Issue Guidelines
|
2
|
+
|
3
|
+
## Reporting bugs
|
4
|
+
|
5
|
+
If you found a bug, report an issue and describe what's the expected behavior versus what actually happens. If the bug causes a crash, attach a full backtrace. If possible, a reproduction script showing the problem is highly appreciated.
|
6
|
+
|
7
|
+
## Reporting feature requests
|
8
|
+
|
9
|
+
Report a feature request **only after discussing it first on [discourse.dry-rb.org](https://discourse.dry-rb.org)** where it was accepted. Please provide a concise description of the feature, don't link to a discussion thread, and instead summarize what was discussed.
|
10
|
+
|
11
|
+
## Reporting questions, support requests, ideas, concerns etc.
|
12
|
+
|
13
|
+
**PLEASE DON'T** - use [discourse.dry-rb.org](http://discourse.dry-rb.org) instead.
|
14
|
+
|
15
|
+
# Pull Request Guidelines
|
16
|
+
|
17
|
+
A Pull Request will only be accepted if it addresses a specific issue that was reported previously, or fixes typos, mistakes in documentation etc.
|
18
|
+
|
19
|
+
Other requirements:
|
20
|
+
|
21
|
+
1) Do not open a pull request if you can't provide tests along with it. If you have problems writing tests, ask for help in the related issue.
|
22
|
+
2) Follow the style conventions of the surrounding code. In most cases, this is standard ruby style.
|
23
|
+
3) Add API documentation if it's a new feature
|
24
|
+
4) Update API documentation if it changes an existing feature
|
25
|
+
5) Bonus points for sending a PR to [github.com/dry-rb/dry-rb.org](github.com/dry-rb/dry-rb.org) which updates user documentation and guides
|
26
|
+
|
27
|
+
# Asking for help
|
28
|
+
|
29
|
+
If these guidelines aren't helpful, and you're stuck, please post a message on [discourse.dry-rb.org](https://discourse.dry-rb.org).
|
data/Gemfile
CHANGED
data/dry-view.gemspec
CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
|
-
spec.required_ruby_version = '>= 2.
|
22
|
+
spec.required_ruby_version = '>= 2.2.0'
|
23
23
|
|
24
24
|
spec.add_runtime_dependency "tilt", "~> 2.0"
|
25
25
|
spec.add_runtime_dependency "dry-core", "~> 0.2"
|
data/lib/dry/view/controller.rb
CHANGED
@@ -10,6 +10,8 @@ require 'dry/view/scope'
|
|
10
10
|
module Dry
|
11
11
|
module View
|
12
12
|
class Controller
|
13
|
+
UndefinedTemplateError = Class.new(StandardError)
|
14
|
+
|
13
15
|
DEFAULT_LAYOUTS_DIR = 'layouts'.freeze
|
14
16
|
DEFAULT_CONTEXT = Object.new.freeze
|
15
17
|
EMPTY_LOCALS = {}.freeze
|
@@ -51,17 +53,17 @@ module Dry
|
|
51
53
|
# @api public
|
52
54
|
def self.expose(*names, **options, &block)
|
53
55
|
if names.length == 1
|
54
|
-
exposures.add(names.first, block,
|
56
|
+
exposures.add(names.first, block, options)
|
55
57
|
else
|
56
58
|
names.each do |name|
|
57
|
-
exposures.add(name,
|
59
|
+
exposures.add(name, options)
|
58
60
|
end
|
59
61
|
end
|
60
62
|
end
|
61
63
|
|
62
64
|
# @api public
|
63
65
|
def self.private_expose(*names, **options, &block)
|
64
|
-
expose(*names, **options
|
66
|
+
expose(*names, **options, private: true, &block)
|
65
67
|
end
|
66
68
|
|
67
69
|
# @api private
|
@@ -80,13 +82,15 @@ module Dry
|
|
80
82
|
|
81
83
|
# @api public
|
82
84
|
def call(format: config.default_format, context: config.context, **input)
|
85
|
+
raise UndefinedTemplateError, "no +template+ configured" unless template_path
|
86
|
+
|
83
87
|
renderer = self.class.renderer(format)
|
84
88
|
|
85
|
-
template_content = renderer.(template_path, template_scope(renderer, context,
|
89
|
+
template_content = renderer.template(template_path, template_scope(renderer, context, input))
|
86
90
|
|
87
91
|
return template_content unless layout?
|
88
92
|
|
89
|
-
renderer.(layout_path, layout_scope(renderer, context)) do
|
93
|
+
renderer.template(layout_path, layout_scope(renderer, context)) do
|
90
94
|
template_content
|
91
95
|
end
|
92
96
|
end
|
@@ -107,7 +111,7 @@ module Dry
|
|
107
111
|
end
|
108
112
|
|
109
113
|
def template_scope(renderer, context, **input)
|
110
|
-
scope(renderer.chdir(template_path), context, locals(
|
114
|
+
scope(renderer.chdir(template_path), context, locals(input))
|
111
115
|
end
|
112
116
|
|
113
117
|
def scope(renderer, context, locals = EMPTY_LOCALS)
|
data/lib/dry/view/decorator.rb
CHANGED
@@ -8,7 +8,7 @@ module Dry
|
|
8
8
|
|
9
9
|
# @api public
|
10
10
|
def call(name, value, renderer:, context:, **options)
|
11
|
-
klass = part_class(name, value,
|
11
|
+
klass = part_class(name, value, options)
|
12
12
|
|
13
13
|
if value.respond_to?(:to_ary)
|
14
14
|
singular_name = Dry::Core::Inflector.singularize(name).to_sym
|
data/lib/dry/view/exposure.rb
CHANGED
@@ -5,7 +5,8 @@ module Dry
|
|
5
5
|
class Exposure
|
6
6
|
include Dry::Equalizer(:name, :proc, :object, :options)
|
7
7
|
|
8
|
-
|
8
|
+
EXPOSURE_DEPENDENCY_PARAMETER_TYPES = [:req, :opt].freeze
|
9
|
+
INPUT_PARAMETER_TYPES = [:key, :keyreq, :keyrest].freeze
|
9
10
|
|
10
11
|
attr_reader :name
|
11
12
|
attr_reader :proc
|
@@ -20,34 +21,50 @@ module Dry
|
|
20
21
|
end
|
21
22
|
|
22
23
|
def bind(obj)
|
23
|
-
self.class.new(name, proc, obj,
|
24
|
+
self.class.new(name, proc, obj, options)
|
24
25
|
end
|
25
26
|
|
26
|
-
def
|
27
|
-
|
27
|
+
def dependency_names
|
28
|
+
if proc
|
29
|
+
proc.parameters.each_with_object([]) { |(type, name), names|
|
30
|
+
names << name if EXPOSURE_DEPENDENCY_PARAMETER_TYPES.include?(type)
|
31
|
+
}
|
32
|
+
else
|
33
|
+
[]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def input_keys
|
38
|
+
if proc
|
39
|
+
proc.parameters.each_with_object([]) { |(type, name), keys|
|
40
|
+
keys << name if INPUT_PARAMETER_TYPES.include?(type)
|
41
|
+
}
|
42
|
+
else
|
43
|
+
[]
|
44
|
+
end
|
28
45
|
end
|
29
46
|
|
30
47
|
def private?
|
31
48
|
options.fetch(:private) { false }
|
32
49
|
end
|
33
50
|
|
34
|
-
def
|
35
|
-
|
36
|
-
|
37
|
-
args = dependencies.map.with_index { |name, position|
|
38
|
-
if position.zero?
|
39
|
-
locals.fetch(name) { input }
|
40
|
-
else
|
41
|
-
locals.fetch(name)
|
42
|
-
end
|
43
|
-
}
|
51
|
+
def default_value
|
52
|
+
options[:default]
|
53
|
+
end
|
44
54
|
|
45
|
-
|
55
|
+
def call(input, locals = {})
|
56
|
+
if proc
|
57
|
+
call_proc(input, locals)
|
58
|
+
else
|
59
|
+
input.fetch(name) { default_value }
|
60
|
+
end
|
46
61
|
end
|
47
62
|
|
48
63
|
private
|
49
64
|
|
50
|
-
def call_proc(
|
65
|
+
def call_proc(input, locals)
|
66
|
+
args = proc_args(input, locals)
|
67
|
+
|
51
68
|
if proc.is_a?(Method)
|
52
69
|
proc.(*args)
|
53
70
|
else
|
@@ -55,6 +72,27 @@ module Dry
|
|
55
72
|
end
|
56
73
|
end
|
57
74
|
|
75
|
+
def proc_args(input, locals)
|
76
|
+
dependency_args = proc_dependency_args(locals)
|
77
|
+
input_args = proc_input_args(input)
|
78
|
+
|
79
|
+
if input_args.any?
|
80
|
+
dependency_args << input_args
|
81
|
+
else
|
82
|
+
dependency_args
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def proc_dependency_args(locals)
|
87
|
+
dependency_names.map { |name| locals.fetch(name) }
|
88
|
+
end
|
89
|
+
|
90
|
+
def proc_input_args(input)
|
91
|
+
input_keys.each_with_object({}) { |key, args|
|
92
|
+
args[key] = input[key] if input.key?(key)
|
93
|
+
}
|
94
|
+
end
|
95
|
+
|
58
96
|
def prepare_proc(proc, object)
|
59
97
|
if proc
|
60
98
|
proc
|
data/lib/dry/view/exposures.rb
CHANGED
@@ -21,7 +21,7 @@ module Dry
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def add(name, proc = nil, **options)
|
24
|
-
exposures[name] = Exposure.new(name, proc,
|
24
|
+
exposures[name] = Exposure.new(name, proc, options)
|
25
25
|
end
|
26
26
|
|
27
27
|
def bind(obj)
|
@@ -47,7 +47,7 @@ module Dry
|
|
47
47
|
end
|
48
48
|
|
49
49
|
def tsort_each_child(name, &block)
|
50
|
-
self[name].
|
50
|
+
self[name].dependency_names.each(&block) if exposures.key?(name)
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Dry
|
2
|
+
module View
|
3
|
+
class MissingRendererError < StandardError
|
4
|
+
def initialize(message = "No renderer provided")
|
5
|
+
super
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class MissingRenderer
|
10
|
+
def method_missing(name, *args, &block)
|
11
|
+
raise MissingRendererError
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/dry/view/part.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'dry-equalizer'
|
2
2
|
require 'dry/view/scope'
|
3
|
+
require 'dry/view/missing_renderer'
|
3
4
|
|
4
5
|
module Dry
|
5
6
|
module View
|
@@ -20,7 +21,7 @@ module Dry
|
|
20
21
|
|
21
22
|
attr_reader :_renderer
|
22
23
|
|
23
|
-
def initialize(name:, value:, renderer
|
24
|
+
def initialize(name:, value:, renderer: MissingRenderer.new, context: nil)
|
24
25
|
@_name = name
|
25
26
|
@_value = value
|
26
27
|
@_context = context
|
@@ -28,11 +29,7 @@ module Dry
|
|
28
29
|
end
|
29
30
|
|
30
31
|
def _render(partial_name, as: _name, **locals, &block)
|
31
|
-
_renderer.
|
32
|
-
_partial(partial_name),
|
33
|
-
_render_scope(as, **locals),
|
34
|
-
&block
|
35
|
-
)
|
32
|
+
_renderer.partial(partial_name, _render_scope(as, locals), &block)
|
36
33
|
end
|
37
34
|
|
38
35
|
def to_s
|
@@ -51,10 +48,6 @@ module Dry
|
|
51
48
|
end
|
52
49
|
end
|
53
50
|
|
54
|
-
def _partial(name)
|
55
|
-
_renderer.lookup("_#{name}")
|
56
|
-
end
|
57
|
-
|
58
51
|
def _render_scope(name, **locals)
|
59
52
|
Scope.new(
|
60
53
|
locals: locals.merge(name => self),
|
data/lib/dry/view/renderer.rb
CHANGED
@@ -4,6 +4,9 @@ require 'dry-equalizer'
|
|
4
4
|
module Dry
|
5
5
|
module View
|
6
6
|
class Renderer
|
7
|
+
PARTIAL_PREFIX = "_".freeze
|
8
|
+
PATH_DELIMITER = "/".freeze
|
9
|
+
|
7
10
|
include Dry::Equalizer(:paths, :format)
|
8
11
|
|
9
12
|
TemplateNotFoundError = Class.new(StandardError)
|
@@ -20,17 +23,21 @@ module Dry
|
|
20
23
|
@tilts = self.class.tilts
|
21
24
|
end
|
22
25
|
|
23
|
-
def
|
24
|
-
path = lookup(
|
26
|
+
def template(name, scope, &block)
|
27
|
+
path = lookup(name)
|
25
28
|
|
26
29
|
if path
|
27
30
|
render(path, scope, &block)
|
28
31
|
else
|
29
|
-
msg = "Template #{
|
32
|
+
msg = "Template #{name.inspect} could not be found in paths:\n#{paths.map { |pa| "- #{pa.to_s}" }.join("\n")}"
|
30
33
|
raise TemplateNotFoundError, msg
|
31
34
|
end
|
32
35
|
end
|
33
36
|
|
37
|
+
def partial(name, scope, &block)
|
38
|
+
template(name_for_partial(name), scope, &block)
|
39
|
+
end
|
40
|
+
|
34
41
|
def render(path, scope, &block)
|
35
42
|
tilt(path).render(scope, &block)
|
36
43
|
end
|
@@ -49,6 +56,11 @@ module Dry
|
|
49
56
|
|
50
57
|
private
|
51
58
|
|
59
|
+
def name_for_partial(name)
|
60
|
+
name_segments = name.to_s.split(PATH_DELIMITER)
|
61
|
+
partial_name = name_segments[0..-2].push("#{PARTIAL_PREFIX}#{name_segments[-1]}").join(PATH_DELIMITER)
|
62
|
+
end
|
63
|
+
|
52
64
|
# TODO: make default_encoding configurable
|
53
65
|
def tilt(path)
|
54
66
|
tilts.fetch(path) {
|
data/lib/dry/view/scope.rb
CHANGED
@@ -16,11 +16,7 @@ module Dry
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def render(partial_name, **locals, &block)
|
19
|
-
_renderer.
|
20
|
-
__partial(partial_name),
|
21
|
-
__render_scope(**locals),
|
22
|
-
&block
|
23
|
-
)
|
19
|
+
_renderer.partial(partial_name, __render_scope(locals), &block)
|
24
20
|
end
|
25
21
|
|
26
22
|
private
|
@@ -35,10 +31,6 @@ module Dry
|
|
35
31
|
end
|
36
32
|
end
|
37
33
|
|
38
|
-
def __partial(name)
|
39
|
-
_renderer.lookup("_#{name}")
|
40
|
-
end
|
41
|
-
|
42
34
|
def __render_scope(**locals)
|
43
35
|
if locals.any?
|
44
36
|
self.class.new(renderer: _renderer, context: _context, locals: locals)
|
data/lib/dry/view/version.rb
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
h1 Partial hello
|
@@ -10,8 +10,8 @@ RSpec.describe 'exposures' do
|
|
10
10
|
config.default_format = :html
|
11
11
|
end
|
12
12
|
|
13
|
-
expose :users do |
|
14
|
-
|
13
|
+
expose :users do |users:|
|
14
|
+
users.map { |user|
|
15
15
|
user.merge(name: user[:name].upcase)
|
16
16
|
}
|
17
17
|
end
|
@@ -43,8 +43,8 @@ RSpec.describe 'exposures' do
|
|
43
43
|
@prefix = "My friend "
|
44
44
|
end
|
45
45
|
|
46
|
-
expose :users do |
|
47
|
-
|
46
|
+
expose :users do |users:|
|
47
|
+
users.map { |user|
|
48
48
|
user.merge(name: prefix + user[:name])
|
49
49
|
}
|
50
50
|
end
|
@@ -73,8 +73,8 @@ RSpec.describe 'exposures' do
|
|
73
73
|
|
74
74
|
private
|
75
75
|
|
76
|
-
def users(
|
77
|
-
|
76
|
+
def users(users:)
|
77
|
+
users.map { |user|
|
78
78
|
user.merge(name: user[:name].upcase)
|
79
79
|
}
|
80
80
|
end
|
@@ -112,6 +112,40 @@ RSpec.describe 'exposures' do
|
|
112
112
|
)
|
113
113
|
end
|
114
114
|
|
115
|
+
it 'using default values' do
|
116
|
+
vc = Class.new(Dry::View::Controller) do
|
117
|
+
configure do |config|
|
118
|
+
config.paths = SPEC_ROOT.join('fixtures/templates')
|
119
|
+
config.layout = 'app'
|
120
|
+
config.template = 'users'
|
121
|
+
config.default_format = :html
|
122
|
+
end
|
123
|
+
|
124
|
+
expose :users, default: [{name: 'John', email: 'john@william.org'}]
|
125
|
+
end.new
|
126
|
+
|
127
|
+
expect(vc.(context: context)).to eql(
|
128
|
+
'<!DOCTYPE html><html><head><title>dry-view rocks!</title></head><body><div class="users"><table><tbody><tr><td>John</td><td>john@william.org</td></tr></tbody></table></div><img src="mindblown.jpg" /></body></html>'
|
129
|
+
)
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'having default values but passing nil as value for exposure' do
|
133
|
+
vc = Class.new(Dry::View::Controller) do
|
134
|
+
configure do |config|
|
135
|
+
config.paths = SPEC_ROOT.join('fixtures/templates')
|
136
|
+
config.layout = 'app'
|
137
|
+
config.template = 'greeting'
|
138
|
+
config.default_format = :html
|
139
|
+
end
|
140
|
+
|
141
|
+
expose :greeting, default: 'Hello Dry-rb'
|
142
|
+
end.new
|
143
|
+
|
144
|
+
expect(vc.(greeting: nil, context: context)).to eql(
|
145
|
+
'<!DOCTYPE html><html><head><title>dry-view rocks!</title></head><body><p></p></body></html>'
|
146
|
+
)
|
147
|
+
end
|
148
|
+
|
115
149
|
it 'allows exposures to depend on each other' do
|
116
150
|
vc = Class.new(Dry::View::Controller) do
|
117
151
|
configure do |config|
|
@@ -121,11 +155,9 @@ RSpec.describe 'exposures' do
|
|
121
155
|
config.default_format = :html
|
122
156
|
end
|
123
157
|
|
124
|
-
expose :users
|
125
|
-
input.fetch(:users)
|
126
|
-
end
|
158
|
+
expose :users
|
127
159
|
|
128
|
-
expose :users_count do |users
|
160
|
+
expose :users_count do |users:|
|
129
161
|
"#{users.length} users"
|
130
162
|
end
|
131
163
|
end.new
|
@@ -140,6 +172,75 @@ RSpec.describe 'exposures' do
|
|
140
172
|
)
|
141
173
|
end
|
142
174
|
|
175
|
+
it 'allows exposures to depend on each other and access keywords args from input' do
|
176
|
+
vc = Class.new(Dry::View::Controller) do
|
177
|
+
configure do |config|
|
178
|
+
config.paths = SPEC_ROOT.join('fixtures/templates')
|
179
|
+
config.layout = 'app'
|
180
|
+
config.template = 'greeting'
|
181
|
+
config.default_format = :html
|
182
|
+
end
|
183
|
+
|
184
|
+
expose :greeting do |prefix, greeting:|
|
185
|
+
"#{prefix} #{greeting}"
|
186
|
+
end
|
187
|
+
|
188
|
+
expose :prefix do
|
189
|
+
'Hello'
|
190
|
+
end
|
191
|
+
end.new
|
192
|
+
|
193
|
+
expect(vc.(greeting: 'From dry-view internals', context: context)).to eql(
|
194
|
+
'<!DOCTYPE html><html><head><title>dry-view rocks!</title></head><body><p>Hello From dry-view internals</p></body></html>'
|
195
|
+
)
|
196
|
+
end
|
197
|
+
|
198
|
+
it 'set default values for keyword arguments' do
|
199
|
+
vc = Class.new(Dry::View::Controller) do
|
200
|
+
configure do |config|
|
201
|
+
config.paths = SPEC_ROOT.join('fixtures/templates')
|
202
|
+
config.layout = 'app'
|
203
|
+
config.template = 'greeting'
|
204
|
+
config.default_format = :html
|
205
|
+
end
|
206
|
+
|
207
|
+
expose :greeting do |prefix, greeting: 'From the defaults'|
|
208
|
+
"#{prefix} #{greeting}"
|
209
|
+
end
|
210
|
+
|
211
|
+
expose :prefix do
|
212
|
+
'Hello'
|
213
|
+
end
|
214
|
+
end.new
|
215
|
+
|
216
|
+
expect(vc.(context: context)).to eql(
|
217
|
+
'<!DOCTYPE html><html><head><title>dry-view rocks!</title></head><body><p>Hello From the defaults</p></body></html>'
|
218
|
+
)
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'only pass keywords arguments that are needit in the block and allow for default values' do
|
222
|
+
vc = Class.new(Dry::View::Controller) do
|
223
|
+
configure do |config|
|
224
|
+
config.paths = SPEC_ROOT.join('fixtures/templates')
|
225
|
+
config.layout = 'app'
|
226
|
+
config.template = 'edit'
|
227
|
+
config.default_format = :html
|
228
|
+
end
|
229
|
+
|
230
|
+
expose :pretty_id do |id:|
|
231
|
+
"Beautiful #{id}"
|
232
|
+
end
|
233
|
+
|
234
|
+
expose :errors do |errors: []|
|
235
|
+
errors
|
236
|
+
end
|
237
|
+
end.new
|
238
|
+
|
239
|
+
expect(vc.(id: 1, context: context)).to eql(
|
240
|
+
'<!DOCTYPE html><html><head><title>dry-view rocks!</title></head><body><h1>Edit</h1><p>No Errors</p><p>Beautiful 1</p></body></html>'
|
241
|
+
)
|
242
|
+
end
|
243
|
+
|
143
244
|
it 'supports defining multiple exposures at once' do
|
144
245
|
vc = Class.new(Dry::View::Controller) do
|
145
246
|
configure do |config|
|
@@ -153,11 +254,7 @@ RSpec.describe 'exposures' do
|
|
153
254
|
|
154
255
|
private
|
155
256
|
|
156
|
-
def users
|
157
|
-
input.fetch(:users)
|
158
|
-
end
|
159
|
-
|
160
|
-
def users_count(users)
|
257
|
+
def users_count(users:)
|
161
258
|
"#{users.length} users"
|
162
259
|
end
|
163
260
|
end.new
|
@@ -185,11 +282,9 @@ RSpec.describe 'exposures' do
|
|
185
282
|
"COUNT: "
|
186
283
|
end
|
187
284
|
|
188
|
-
expose :users
|
189
|
-
input.fetch(:users)
|
190
|
-
end
|
285
|
+
expose :users
|
191
286
|
|
192
|
-
expose :users_count do |prefix, users
|
287
|
+
expose :users_count do |prefix, users:|
|
193
288
|
"#{prefix}#{users.length} users"
|
194
289
|
end
|
195
290
|
end.new
|
data/spec/spec_helper.rb
CHANGED
@@ -1,18 +1,13 @@
|
|
1
1
|
RSpec.describe Dry::View::Controller do
|
2
|
-
subject(:
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
config.default_format = :html
|
12
|
-
end
|
13
|
-
|
14
|
-
klass
|
15
|
-
end
|
2
|
+
subject(:controller) {
|
3
|
+
Class.new(Dry::View::Controller) do
|
4
|
+
configure do |config|
|
5
|
+
config.paths = SPEC_ROOT.join('fixtures/templates')
|
6
|
+
config.layout = 'app'
|
7
|
+
config.template = 'user'
|
8
|
+
end
|
9
|
+
end.new
|
10
|
+
}
|
16
11
|
|
17
12
|
let(:page) do
|
18
13
|
double(:page, title: 'Test')
|
@@ -22,15 +17,21 @@ RSpec.describe Dry::View::Controller do
|
|
22
17
|
{ context: page, locals: { user: { name: 'Jane' }, header: { title: 'User' } } }
|
23
18
|
end
|
24
19
|
|
25
|
-
let(:renderer) do
|
26
|
-
layout.class.renderers[:html]
|
27
|
-
end
|
28
|
-
|
29
20
|
describe '#call' do
|
30
21
|
it 'renders template within the layout' do
|
31
|
-
expect(
|
22
|
+
expect(controller.(options)).to eql(
|
32
23
|
'<!DOCTYPE html><html><head><title>Test</title></head><body><h1>User</h1><p>Jane</p></body></html>'
|
33
24
|
)
|
34
25
|
end
|
26
|
+
|
27
|
+
it 'provides a meaningful error if the template name is missing' do
|
28
|
+
controller = Class.new(Dry::View::Controller) do
|
29
|
+
configure do |config|
|
30
|
+
config.paths = SPEC_ROOT.join('fixtures/templates')
|
31
|
+
end
|
32
|
+
end.new
|
33
|
+
|
34
|
+
expect { controller.(options) }.to raise_error Dry::View::Controller::UndefinedTemplateError
|
35
|
+
end
|
35
36
|
end
|
36
37
|
end
|
data/spec/unit/exposure_spec.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
RSpec.describe Dry::View::Exposure do
|
2
|
-
subject(:exposure) { described_class.new(:hello, proc, object) }
|
2
|
+
subject(:exposure) { described_class.new(:hello, proc, object, **options) }
|
3
3
|
|
4
4
|
let(:proc) { -> input { "hi" } }
|
5
5
|
let(:object) { nil }
|
6
|
+
let(:options) { {} }
|
6
7
|
|
7
8
|
describe "initialization and attributes" do
|
8
9
|
describe "#name" do
|
@@ -42,6 +43,17 @@ RSpec.describe Dry::View::Exposure do
|
|
42
43
|
expect(described_class.new(:hello, private: true)).to be_private
|
43
44
|
end
|
44
45
|
end
|
46
|
+
|
47
|
+
describe "#default_value" do
|
48
|
+
it "is nil by default" do
|
49
|
+
expect(exposure.default_value).to be_nil
|
50
|
+
end
|
51
|
+
|
52
|
+
it "can be set on initialization" do
|
53
|
+
exposuse = described_class.new(:hello, default: 'Hi !')
|
54
|
+
expect(exposuse.default_value).to eq('Hi !')
|
55
|
+
end
|
56
|
+
end
|
45
57
|
end
|
46
58
|
|
47
59
|
describe "#bind" do
|
@@ -90,12 +102,12 @@ RSpec.describe Dry::View::Exposure do
|
|
90
102
|
end
|
91
103
|
end
|
92
104
|
|
93
|
-
describe "#
|
105
|
+
describe "#dependency_names" do
|
94
106
|
context "proc provided" do
|
95
107
|
let(:proc) { -> input, foo, bar { "hi" } }
|
96
108
|
|
97
109
|
it "returns an array of exposure dependencies derived from the proc's argument names" do
|
98
|
-
expect(exposure.
|
110
|
+
expect(exposure.dependency_names).to eql [:input, :foo, :bar]
|
99
111
|
end
|
100
112
|
end
|
101
113
|
|
@@ -111,7 +123,7 @@ RSpec.describe Dry::View::Exposure do
|
|
111
123
|
end
|
112
124
|
|
113
125
|
it "returns an array of exposure dependencies derived from the instance method's argument names" do
|
114
|
-
expect(exposure.
|
126
|
+
expect(exposure.dependency_names).to eql [:input, :bar, :baz]
|
115
127
|
end
|
116
128
|
end
|
117
129
|
|
@@ -119,28 +131,56 @@ RSpec.describe Dry::View::Exposure do
|
|
119
131
|
let(:proc) { nil }
|
120
132
|
|
121
133
|
it "returns no dependencies" do
|
122
|
-
expect(exposure.
|
134
|
+
expect(exposure.dependency_names).to eql []
|
123
135
|
end
|
124
136
|
end
|
125
137
|
end
|
126
138
|
|
127
139
|
describe "#call" do
|
128
|
-
let(:input) { "
|
140
|
+
let(:input) { {name: "Jane"} }
|
129
141
|
|
130
142
|
context "proc expects input only" do
|
131
|
-
let(:proc) { ->
|
143
|
+
let(:proc) { -> name: { name } }
|
132
144
|
|
133
145
|
it "sends the input to the proc" do
|
134
|
-
expect(exposure.(input)).to eql "
|
146
|
+
expect(exposure.(input)).to eql "Jane"
|
135
147
|
end
|
136
148
|
end
|
137
149
|
|
138
150
|
context "proc expects input and dependencies" do
|
139
|
-
let(:proc) { ->
|
151
|
+
let(:proc) { -> greeting, name: { "#{greeting}, #{name}" } }
|
140
152
|
let(:locals) { {greeting: "Hola"} }
|
141
153
|
|
142
154
|
it "sends the input and dependency values to the proc" do
|
143
|
-
expect(exposure.(input, locals)).to eq "Hola,
|
155
|
+
expect(exposure.(input, locals)).to eq "Hola, Jane"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
context "Default value" do
|
160
|
+
let(:options) { { default: "John" } }
|
161
|
+
|
162
|
+
context "use default value" do
|
163
|
+
let(:proc) { nil }
|
164
|
+
|
165
|
+
it "use the default value" do
|
166
|
+
expect(exposure.({})).to eq "John"
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
context "use input value instead of default" do
|
171
|
+
let(:proc) { nil }
|
172
|
+
|
173
|
+
it "use the default value" do
|
174
|
+
expect(exposure.({hello: "Jane"})).to eq "Jane"
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
context "use input value over default even when input is nil" do
|
179
|
+
let(:proc) { nil }
|
180
|
+
|
181
|
+
it "use the default value" do
|
182
|
+
expect(exposure.({hello: nil})).to eq nil
|
183
|
+
end
|
144
184
|
end
|
145
185
|
end
|
146
186
|
|
@@ -154,20 +194,20 @@ RSpec.describe Dry::View::Exposure do
|
|
154
194
|
end
|
155
195
|
|
156
196
|
context "proc accesses object instance" do
|
157
|
-
let(:proc) { ->
|
197
|
+
let(:proc) { -> name: { "My name is #{name} but call me #{title} #{name}" } }
|
158
198
|
|
159
199
|
let(:object) do
|
160
200
|
Class.new do
|
161
|
-
attr_reader :
|
201
|
+
attr_reader :title
|
162
202
|
|
163
|
-
def initialize(
|
164
|
-
@
|
203
|
+
def initialize(title)
|
204
|
+
@title = title
|
165
205
|
end
|
166
|
-
end.new("
|
206
|
+
end.new("Dr")
|
167
207
|
end
|
168
208
|
|
169
209
|
it "makes the instance available as self" do
|
170
|
-
expect(exposure.(input)).to eq "
|
210
|
+
expect(exposure.(input)).to eq "My name is Jane but call me Dr Jane"
|
171
211
|
end
|
172
212
|
end
|
173
213
|
|
data/spec/unit/exposures_spec.rb
CHANGED
@@ -9,7 +9,7 @@ RSpec.describe Dry::View::Exposures do
|
|
9
9
|
|
10
10
|
describe "#add" do
|
11
11
|
it "creates and adds an exposure" do
|
12
|
-
proc = -> input { "hi" }
|
12
|
+
proc = -> **input { "hi" }
|
13
13
|
exposures.add :hello, proc
|
14
14
|
|
15
15
|
expect(exposures[:hello].name).to eq :hello
|
@@ -43,7 +43,7 @@ RSpec.describe Dry::View::Exposures do
|
|
43
43
|
|
44
44
|
describe "#locals" do
|
45
45
|
before do
|
46
|
-
exposures.add(:greeting, ->
|
46
|
+
exposures.add(:greeting, -> greeting: { greeting.upcase })
|
47
47
|
exposures.add(:farewell, -> greeting { "#{greeting} and goodbye" })
|
48
48
|
end
|
49
49
|
|
@@ -54,10 +54,40 @@ RSpec.describe Dry::View::Exposures do
|
|
54
54
|
end
|
55
55
|
|
56
56
|
it "does not return any values from private exposures" do
|
57
|
-
exposures.add(:hidden, -> input { "shh" }, private: true)
|
57
|
+
exposures.add(:hidden, -> **input { "shh" }, private: true)
|
58
58
|
|
59
59
|
expect(locals).to include(:greeting, :farewell)
|
60
60
|
expect(locals).not_to include(:hidden)
|
61
61
|
end
|
62
62
|
end
|
63
|
+
|
64
|
+
describe "#locals default value" do
|
65
|
+
it "returns 'default_value' from exposure" do
|
66
|
+
exposures.add(:name, default: 'John')
|
67
|
+
locals = exposures.locals({})
|
68
|
+
|
69
|
+
expect(locals).to eq(:name=>"John")
|
70
|
+
end
|
71
|
+
|
72
|
+
it "returns values from arguments" do
|
73
|
+
exposures.add(:name, default: 'John')
|
74
|
+
locals = exposures.locals(name: 'William')
|
75
|
+
|
76
|
+
expect(locals).to eq(:name=>"William")
|
77
|
+
end
|
78
|
+
|
79
|
+
it "returns values from arguments even when value is nil" do
|
80
|
+
exposures.add(:name, default: 'John')
|
81
|
+
locals = exposures.locals(name: nil)
|
82
|
+
|
83
|
+
expect(locals).to eq(:name=>nil)
|
84
|
+
end
|
85
|
+
|
86
|
+
it "returns value from proc" do
|
87
|
+
exposures.add(:name, -> name: { name.upcase }, default: 'John')
|
88
|
+
locals = exposures.locals(name: 'William')
|
89
|
+
|
90
|
+
expect(locals).to eq(:name=>"WILLIAM")
|
91
|
+
end
|
92
|
+
end
|
63
93
|
end
|
data/spec/unit/part_spec.rb
CHANGED
@@ -5,61 +5,76 @@ RSpec::Matchers.define :template_scope do |locals|
|
|
5
5
|
end
|
6
6
|
|
7
7
|
RSpec.describe Dry::View::Part do
|
8
|
-
|
8
|
+
context 'with a renderer' do
|
9
|
+
subject(:part) { described_class.new(name: name, value: value, renderer: renderer, context: context) }
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
let(:name) { :user }
|
12
|
+
let(:value) { double(:value) }
|
13
|
+
let(:context) { double(:context) }
|
14
|
+
let(:renderer) { spy(:renderer) }
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
describe '#render' do
|
17
|
+
it 'renders a partial with the part available in its scope' do
|
18
|
+
part.render(:info)
|
19
|
+
expect(renderer).to have_received(:partial).with(:info, template_scope(user: part))
|
20
|
+
end
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
it 'allows the part to be made available on a different name' do
|
23
|
+
part.render(:info, as: :admin)
|
24
|
+
expect(renderer).to have_received(:partial).with(:info, template_scope(admin: part))
|
25
|
+
end
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
27
|
+
it 'includes extra locals in the scope' do
|
28
|
+
part.render(:info, extra_local: "hello")
|
29
|
+
expect(renderer).to have_received(:partial).with(:info, template_scope(user: part, extra_local: "hello"))
|
30
|
+
end
|
29
31
|
end
|
30
32
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
end
|
33
|
+
describe '#to_s' do
|
34
|
+
before do
|
35
|
+
allow(value).to receive(:to_s).and_return 'to_s on the value'
|
36
|
+
end
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
|
38
|
+
it 'delegates to the wrapped value' do
|
39
|
+
expect(part.to_s).to eq 'to_s on the value'
|
40
|
+
end
|
40
41
|
end
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
end
|
45
|
-
end
|
43
|
+
describe '#method_missing' do
|
44
|
+
let(:value) { double(greeting: 'hello from value') }
|
46
45
|
|
47
|
-
|
48
|
-
|
46
|
+
it 'calls a matching method on the value' do
|
47
|
+
expect(part.greeting).to eq 'hello from value'
|
48
|
+
end
|
49
49
|
|
50
|
-
|
51
|
-
|
52
|
-
|
50
|
+
it 'forwards all arguments to the method' do
|
51
|
+
blk = -> { }
|
52
|
+
part.greeting 'args', &blk
|
53
53
|
|
54
|
-
|
55
|
-
|
56
|
-
part.greeting 'args', &blk
|
54
|
+
expect(value).to have_received(:greeting).with('args', &blk)
|
55
|
+
end
|
57
56
|
|
58
|
-
|
57
|
+
it 'raises an error if no metho matches' do
|
58
|
+
expect { part.farewell }.to raise_error(NoMethodError)
|
59
|
+
end
|
59
60
|
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'without a renderer' do
|
64
|
+
subject(:part) { described_class.new(name: name, value: value, context: context) }
|
65
|
+
|
66
|
+
let(:name) { :user }
|
67
|
+
let(:value) { double('value') }
|
68
|
+
let(:context) { double('context') }
|
69
|
+
|
70
|
+
describe '#new' do
|
71
|
+
it 'can be initialized' do
|
72
|
+
expect(part).to be_an_instance_of(Dry::View::Part)
|
73
|
+
end
|
60
74
|
|
61
|
-
|
62
|
-
|
75
|
+
it 'raises an exception when render is called' do
|
76
|
+
expect { part.render(:info) }.to raise_error(Dry::View::MissingRendererError).with_message('No renderer provided')
|
77
|
+
end
|
63
78
|
end
|
64
79
|
end
|
65
80
|
end
|
data/spec/unit/renderer_spec.rb
CHANGED
@@ -3,28 +3,55 @@ require 'dry/view/renderer'
|
|
3
3
|
|
4
4
|
RSpec.describe Dry::View::Renderer do
|
5
5
|
subject(:renderer) do
|
6
|
-
Dry::View::Renderer.new(
|
6
|
+
Dry::View::Renderer.new(
|
7
|
+
[Dry::View::Path.new(SPEC_ROOT.join('fixtures/templates'))],
|
8
|
+
format: 'html'
|
9
|
+
)
|
7
10
|
end
|
8
11
|
|
9
12
|
let(:scope) { double(:scope) }
|
10
13
|
|
11
|
-
describe '#
|
12
|
-
it 'renders template' do
|
13
|
-
expect(renderer.(
|
14
|
+
describe '#template' do
|
15
|
+
it 'renders template in current directory' do
|
16
|
+
expect(renderer.template(:hello, scope)).to eql('<h1>Hello</h1>')
|
14
17
|
end
|
15
18
|
|
16
|
-
it '
|
17
|
-
expect(renderer.(
|
19
|
+
it 'renders template in shared/ subdirectory' do
|
20
|
+
expect(renderer.template(:_shared_hello, scope)).to eql('<h1>Hello</h1>')
|
18
21
|
end
|
19
22
|
|
20
|
-
it '
|
21
|
-
expect(renderer.chdir('
|
23
|
+
it 'renders template in upper directory' do
|
24
|
+
expect(renderer.chdir('nested').template(:_shared_hello, scope)).to eql('<h1>Hello</h1>')
|
22
25
|
end
|
23
26
|
|
24
|
-
it 'raises error when template
|
27
|
+
it 'raises error when template cannot be found' do
|
25
28
|
expect {
|
26
|
-
renderer.(
|
27
|
-
}.to raise_error(Dry::View::Renderer::TemplateNotFoundError, /
|
29
|
+
renderer.template(:missing_template, scope)
|
30
|
+
}.to raise_error(Dry::View::Renderer::TemplateNotFoundError, /missing_template/)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '#partial' do
|
35
|
+
it 'renders partial in current directory' do
|
36
|
+
expect(renderer.partial(:hello, scope)).to eql('<h1>Partial hello</h1>')
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'renders partial in shared/ subdirectory' do
|
40
|
+
expect(renderer.partial(:shared_hello, scope)).to eql('<h1>Hello</h1>')
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'renders partial in upper directory' do
|
44
|
+
expect(renderer.chdir('nested').partial(:hello, scope)).to eql('<h1>Partial hello</h1>')
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'renders partial in upper shared/ subdirectory' do
|
48
|
+
expect(renderer.chdir('nested').partial(:shared_hello, scope)).to eql('<h1>Hello</h1>')
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'raises error when partial cannot be found' do
|
52
|
+
expect {
|
53
|
+
renderer.partial(:missing_partial, scope)
|
54
|
+
}.to raise_error(Dry::View::Renderer::TemplateNotFoundError, /_missing_partial/)
|
28
55
|
end
|
29
56
|
end
|
30
57
|
end
|
data/spec/unit/scope_spec.rb
CHANGED
@@ -2,25 +2,20 @@ RSpec.describe Dry::View::Scope do
|
|
2
2
|
subject(:scope) { described_class.new(renderer: renderer, context: context, locals: locals) }
|
3
3
|
|
4
4
|
let(:locals) { {} }
|
5
|
-
let(:context) { double(
|
6
|
-
let(:renderer) {
|
5
|
+
let(:context) { double(:context) }
|
6
|
+
let(:renderer) { spy(:renderer) }
|
7
7
|
|
8
8
|
describe '#render' do
|
9
|
-
before do
|
10
|
-
allow(renderer).to receive(:lookup).with('_info').and_return '_info.html.erb'
|
11
|
-
allow(renderer).to receive(:render)
|
12
|
-
end
|
13
|
-
|
14
9
|
it 'renders a partial with itself as the scope' do
|
15
10
|
scope.render(:info)
|
16
|
-
expect(renderer).to have_received(:
|
11
|
+
expect(renderer).to have_received(:partial).with(:info, scope)
|
17
12
|
end
|
18
13
|
|
19
14
|
it 'renders a partial with provided locals' do
|
20
15
|
scope_with_locals = described_class.new(renderer: renderer, context: context, locals: {foo: 'bar'})
|
21
16
|
|
22
17
|
scope.render(:info, foo: 'bar')
|
23
|
-
expect(renderer).to have_received(:
|
18
|
+
expect(renderer).to have_received(:partial).with(:info, scope_with_locals)
|
24
19
|
end
|
25
20
|
end
|
26
21
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dry-view
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Solnica
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2017-
|
12
|
+
date: 2017-11-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: tilt
|
@@ -121,6 +121,7 @@ files:
|
|
121
121
|
- ".rspec"
|
122
122
|
- ".travis.yml"
|
123
123
|
- CHANGELOG.md
|
124
|
+
- CONTRIBUTING.md
|
124
125
|
- Gemfile
|
125
126
|
- LICENSE.md
|
126
127
|
- README.md
|
@@ -135,13 +136,17 @@ files:
|
|
135
136
|
- lib/dry/view/decorator.rb
|
136
137
|
- lib/dry/view/exposure.rb
|
137
138
|
- lib/dry/view/exposures.rb
|
139
|
+
- lib/dry/view/missing_renderer.rb
|
138
140
|
- lib/dry/view/part.rb
|
139
141
|
- lib/dry/view/path.rb
|
140
142
|
- lib/dry/view/renderer.rb
|
141
143
|
- lib/dry/view/scope.rb
|
142
144
|
- lib/dry/view/version.rb
|
145
|
+
- spec/fixtures/templates/_hello.html.slim
|
143
146
|
- spec/fixtures/templates/decorated_parts.html.slim
|
147
|
+
- spec/fixtures/templates/edit.html.slim
|
144
148
|
- spec/fixtures/templates/empty.html.slim
|
149
|
+
- spec/fixtures/templates/greeting.html.slim
|
145
150
|
- spec/fixtures/templates/hello.html.slim
|
146
151
|
- spec/fixtures/templates/layouts/app.html.slim
|
147
152
|
- spec/fixtures/templates/layouts/app.txt.erb
|
@@ -180,7 +185,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
180
185
|
requirements:
|
181
186
|
- - ">="
|
182
187
|
- !ruby/object:Gem::Version
|
183
|
-
version: 2.
|
188
|
+
version: 2.2.0
|
184
189
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
185
190
|
requirements:
|
186
191
|
- - ">="
|
@@ -188,13 +193,16 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
188
193
|
version: '0'
|
189
194
|
requirements: []
|
190
195
|
rubyforge_project:
|
191
|
-
rubygems_version: 2.6.
|
196
|
+
rubygems_version: 2.6.11
|
192
197
|
signing_key:
|
193
198
|
specification_version: 4
|
194
199
|
summary: Functional view rendering system
|
195
200
|
test_files:
|
201
|
+
- spec/fixtures/templates/_hello.html.slim
|
196
202
|
- spec/fixtures/templates/decorated_parts.html.slim
|
203
|
+
- spec/fixtures/templates/edit.html.slim
|
197
204
|
- spec/fixtures/templates/empty.html.slim
|
205
|
+
- spec/fixtures/templates/greeting.html.slim
|
198
206
|
- spec/fixtures/templates/hello.html.slim
|
199
207
|
- spec/fixtures/templates/layouts/app.html.slim
|
200
208
|
- spec/fixtures/templates/layouts/app.txt.erb
|