dry-view 0.5.1 → 0.7.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +143 -18
- data/LICENSE +20 -0
- data/README.md +22 -14
- data/dry-view.gemspec +29 -21
- data/lib/dry-view.rb +3 -1
- data/lib/dry/view.rb +514 -2
- data/lib/dry/view/context.rb +80 -0
- data/lib/dry/view/decorated_attributes.rb +82 -0
- data/lib/dry/view/errors.rb +29 -0
- data/lib/dry/view/exposure.rb +35 -14
- data/lib/dry/view/exposures.rb +18 -6
- data/lib/dry/view/part.rb +166 -53
- data/lib/dry/view/part_builder.rb +140 -0
- data/lib/dry/view/path.rb +35 -7
- data/lib/dry/view/render_environment.rb +62 -0
- data/lib/dry/view/render_environment_missing.rb +44 -0
- data/lib/dry/view/rendered.rb +55 -0
- data/lib/dry/view/renderer.rb +36 -29
- data/lib/dry/view/scope.rb +160 -14
- data/lib/dry/view/scope_builder.rb +98 -0
- data/lib/dry/view/tilt.rb +78 -0
- data/lib/dry/view/tilt/erb.rb +26 -0
- data/lib/dry/view/tilt/erbse.rb +21 -0
- data/lib/dry/view/tilt/haml.rb +26 -0
- data/lib/dry/view/version.rb +5 -2
- metadata +78 -115
- data/.gitignore +0 -26
- data/.rspec +0 -2
- data/.travis.yml +0 -23
- data/CONTRIBUTING.md +0 -29
- data/Gemfile +0 -22
- data/LICENSE.md +0 -10
- data/Rakefile +0 -6
- data/benchmarks/templates/button.html.erb +0 -1
- data/benchmarks/view.rb +0 -24
- data/bin/console +0 -7
- data/lib/dry/view/controller.rb +0 -155
- data/lib/dry/view/decorator.rb +0 -45
- data/lib/dry/view/missing_renderer.rb +0 -15
- data/spec/fixtures/templates/_hello.html.slim +0 -1
- data/spec/fixtures/templates/decorated_parts.html.slim +0 -4
- data/spec/fixtures/templates/edit.html.slim +0 -11
- data/spec/fixtures/templates/empty.html.slim +0 -1
- data/spec/fixtures/templates/greeting.html.slim +0 -2
- data/spec/fixtures/templates/hello.html.slim +0 -1
- data/spec/fixtures/templates/layouts/app.html.slim +0 -6
- data/spec/fixtures/templates/layouts/app.txt.erb +0 -3
- data/spec/fixtures/templates/parts_with_args.html.slim +0 -3
- data/spec/fixtures/templates/parts_with_args/_box.html.slim +0 -3
- data/spec/fixtures/templates/shared/_index_table.html.slim +0 -2
- data/spec/fixtures/templates/shared/_shared_hello.html.slim +0 -1
- data/spec/fixtures/templates/tasks.html.slim +0 -3
- data/spec/fixtures/templates/user.html.slim +0 -2
- data/spec/fixtures/templates/users.html.slim +0 -5
- data/spec/fixtures/templates/users.txt.erb +0 -3
- data/spec/fixtures/templates/users/_row.html.slim +0 -2
- data/spec/fixtures/templates/users/_tbody.html.slim +0 -5
- data/spec/fixtures/templates/users_with_count.html.slim +0 -5
- data/spec/fixtures/templates/users_with_count_inherit.html.slim +0 -6
- data/spec/fixtures/templates_override/_hello.html.slim +0 -1
- data/spec/fixtures/templates_override/users.html.slim +0 -5
- data/spec/integration/decorator_spec.rb +0 -80
- data/spec/integration/exposures_spec.rb +0 -392
- data/spec/integration/part/decorated_attributes_spec.rb +0 -157
- data/spec/integration/view_spec.rb +0 -133
- data/spec/spec_helper.rb +0 -46
- data/spec/unit/controller_spec.rb +0 -37
- data/spec/unit/decorator_spec.rb +0 -61
- data/spec/unit/exposure_spec.rb +0 -227
- data/spec/unit/exposures_spec.rb +0 -103
- data/spec/unit/part_spec.rb +0 -90
- data/spec/unit/renderer_spec.rb +0 -57
- data/spec/unit/scope_spec.rb +0 -53
data/spec/unit/exposures_spec.rb
DELETED
@@ -1,103 +0,0 @@
|
|
1
|
-
RSpec.describe Dry::View::Exposures do
|
2
|
-
subject(:exposures) { described_class.new }
|
3
|
-
|
4
|
-
describe "#exposures" do
|
5
|
-
it "is empty by defalut" do
|
6
|
-
expect(exposures.exposures).to be_empty
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
describe "#add" do
|
11
|
-
it "creates and adds an exposure" do
|
12
|
-
proc = -> **input { "hi" }
|
13
|
-
exposures.add :hello, proc
|
14
|
-
|
15
|
-
expect(exposures[:hello].name).to eq :hello
|
16
|
-
expect(exposures[:hello].proc).to eq proc
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
describe "#bind" do
|
21
|
-
subject(:bound_exposures) { exposures.bind(object) }
|
22
|
-
|
23
|
-
let(:object) do
|
24
|
-
Class.new do
|
25
|
-
def hello(input)
|
26
|
-
"hi"
|
27
|
-
end
|
28
|
-
end.new
|
29
|
-
end
|
30
|
-
|
31
|
-
before do
|
32
|
-
exposures.add(:hello)
|
33
|
-
end
|
34
|
-
|
35
|
-
it "binds each of the exposures" do
|
36
|
-
expect(bound_exposures[:hello].proc).to eq object.method(:hello)
|
37
|
-
end
|
38
|
-
|
39
|
-
it "returns a new copy of the exposures" do
|
40
|
-
expect(exposures.exposures).not_to eql(bound_exposures.exposures)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
describe "#locals" do
|
45
|
-
before do
|
46
|
-
exposures.add(:greeting, -> greeting: { greeting.upcase })
|
47
|
-
exposures.add(:farewell, -> greeting { "#{greeting} and goodbye" })
|
48
|
-
end
|
49
|
-
|
50
|
-
subject(:locals) { exposures.locals(greeting: "hello") }
|
51
|
-
|
52
|
-
it "returns the values from the exposures' procs" do
|
53
|
-
expect(locals).to eq(greeting: "HELLO", farewell: "HELLO and goodbye")
|
54
|
-
end
|
55
|
-
|
56
|
-
it "does not return any values from private exposures" do
|
57
|
-
exposures.add(:hidden, -> **input { "shh" }, private: true)
|
58
|
-
|
59
|
-
expect(locals).to include(:greeting, :farewell)
|
60
|
-
expect(locals).not_to include(:hidden)
|
61
|
-
end
|
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
|
93
|
-
|
94
|
-
describe "#import" do
|
95
|
-
it "imports a exposure to the exposures" do
|
96
|
-
exposures_b = described_class.new
|
97
|
-
exposures.add(:name, -> name: { name.upcase }, default: 'John')
|
98
|
-
exposures_b.import(:name, exposures[:name])
|
99
|
-
|
100
|
-
expect(exposures_b[:name]).to eq(exposures[:name])
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
data/spec/unit/part_spec.rb
DELETED
@@ -1,90 +0,0 @@
|
|
1
|
-
RSpec::Matchers.define :template_scope do |locals|
|
2
|
-
match do |actual|
|
3
|
-
locals == locals.map { |k,v| [k, actual.send(k)] }.to_h
|
4
|
-
end
|
5
|
-
end
|
6
|
-
|
7
|
-
RSpec.describe Dry::View::Part do
|
8
|
-
context 'with a renderer' do
|
9
|
-
subject(:part) { described_class.new(name: name, value: value, renderer: renderer, context: context) }
|
10
|
-
|
11
|
-
let(:name) { :user }
|
12
|
-
let(:value) { double(:value) }
|
13
|
-
let(:context) { double(:context) }
|
14
|
-
let(:renderer) { spy(:renderer) }
|
15
|
-
|
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
|
21
|
-
|
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
|
26
|
-
|
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
|
31
|
-
end
|
32
|
-
|
33
|
-
describe '#to_s' do
|
34
|
-
before do
|
35
|
-
allow(value).to receive(:to_s).and_return 'to_s on the value'
|
36
|
-
end
|
37
|
-
|
38
|
-
it 'delegates to the wrapped value' do
|
39
|
-
expect(part.to_s).to eq 'to_s on the value'
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
describe '#new' do
|
44
|
-
it 'preserves decorator, renderer, and context' do
|
45
|
-
new_part = part.new(value: 'new value')
|
46
|
-
|
47
|
-
expect(new_part._decorator).to eql part._decorator
|
48
|
-
expect(new_part._renderer).to eql part._renderer
|
49
|
-
expect(new_part._context).to eql part._context
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
describe '#method_missing' do
|
54
|
-
let(:value) { double(greeting: 'hello from value') }
|
55
|
-
|
56
|
-
it 'calls a matching method on the value' do
|
57
|
-
expect(part.greeting).to eq 'hello from value'
|
58
|
-
end
|
59
|
-
|
60
|
-
it 'forwards all arguments to the method' do
|
61
|
-
blk = -> { }
|
62
|
-
part.greeting 'args', &blk
|
63
|
-
|
64
|
-
expect(value).to have_received(:greeting).with('args', &blk)
|
65
|
-
end
|
66
|
-
|
67
|
-
it 'raises an error if no metho matches' do
|
68
|
-
expect { part.farewell }.to raise_error(NoMethodError)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
context 'without a renderer' do
|
74
|
-
subject(:part) { described_class.new(name: name, value: value, context: context) }
|
75
|
-
|
76
|
-
let(:name) { :user }
|
77
|
-
let(:value) { double('value') }
|
78
|
-
let(:context) { double('context') }
|
79
|
-
|
80
|
-
describe '#initialize' do
|
81
|
-
it 'can be initialized' do
|
82
|
-
expect(part).to be_an_instance_of(Dry::View::Part)
|
83
|
-
end
|
84
|
-
|
85
|
-
it 'raises an exception when render is called' do
|
86
|
-
expect { part.render(:info) }.to raise_error(Dry::View::MissingRendererError).with_message('No renderer provided')
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
data/spec/unit/renderer_spec.rb
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
require 'dry/view/path'
|
2
|
-
require 'dry/view/renderer'
|
3
|
-
|
4
|
-
RSpec.describe Dry::View::Renderer do
|
5
|
-
subject(:renderer) do
|
6
|
-
Dry::View::Renderer.new(
|
7
|
-
[Dry::View::Path.new(SPEC_ROOT.join('fixtures/templates'))],
|
8
|
-
format: 'html'
|
9
|
-
)
|
10
|
-
end
|
11
|
-
|
12
|
-
let(:scope) { double(:scope) }
|
13
|
-
|
14
|
-
describe '#template' do
|
15
|
-
it 'renders template in current directory' do
|
16
|
-
expect(renderer.template(:hello, scope)).to eql('<h1>Hello</h1>')
|
17
|
-
end
|
18
|
-
|
19
|
-
it 'renders template in shared/ subdirectory' do
|
20
|
-
expect(renderer.template(:_shared_hello, scope)).to eql('<h1>Hello</h1>')
|
21
|
-
end
|
22
|
-
|
23
|
-
it 'renders template in upper directory' do
|
24
|
-
expect(renderer.chdir('nested').template(:_shared_hello, scope)).to eql('<h1>Hello</h1>')
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'raises error when template cannot be found' do
|
28
|
-
expect {
|
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/)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
data/spec/unit/scope_spec.rb
DELETED
@@ -1,53 +0,0 @@
|
|
1
|
-
RSpec.describe Dry::View::Scope do
|
2
|
-
subject(:scope) { described_class.new(renderer: renderer, context: context, locals: locals) }
|
3
|
-
|
4
|
-
let(:locals) { {} }
|
5
|
-
let(:context) { double(:context) }
|
6
|
-
let(:renderer) { spy(:renderer) }
|
7
|
-
|
8
|
-
describe '#render' do
|
9
|
-
it 'renders a partial with itself as the scope' do
|
10
|
-
scope.render(:info)
|
11
|
-
expect(renderer).to have_received(:partial).with(:info, scope)
|
12
|
-
end
|
13
|
-
|
14
|
-
it 'renders a partial with provided locals' do
|
15
|
-
scope_with_locals = described_class.new(renderer: renderer, context: context, locals: {foo: 'bar'})
|
16
|
-
|
17
|
-
scope.render(:info, foo: 'bar')
|
18
|
-
expect(renderer).to have_received(:partial).with(:info, scope_with_locals)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
describe '#method_missing' do
|
23
|
-
context 'matching locals' do
|
24
|
-
let(:locals) { {greeting: 'hello from locals'} }
|
25
|
-
let(:context) { double('context', greeting: 'hello from context') }
|
26
|
-
|
27
|
-
it 'returns a matching value from the locals, in favour of a matching method on the context' do
|
28
|
-
expect(scope.greeting).to eq 'hello from locals'
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
context 'matching context' do
|
33
|
-
let(:context) { double('context', greeting: 'hello from context') }
|
34
|
-
|
35
|
-
it 'calls the matching method on the context' do
|
36
|
-
expect(scope.greeting).to eq 'hello from context'
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'forwards all arguments to the method' do
|
40
|
-
blk = -> { }
|
41
|
-
scope.greeting 'args', &blk
|
42
|
-
|
43
|
-
expect(context).to have_received(:greeting).with('args', &blk)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
describe 'no matches' do
|
48
|
-
it 'raises an error' do
|
49
|
-
expect { scope.greeting }.to raise_error(NoMethodError)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|