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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +143 -18
  3. data/LICENSE +20 -0
  4. data/README.md +22 -14
  5. data/dry-view.gemspec +29 -21
  6. data/lib/dry-view.rb +3 -1
  7. data/lib/dry/view.rb +514 -2
  8. data/lib/dry/view/context.rb +80 -0
  9. data/lib/dry/view/decorated_attributes.rb +82 -0
  10. data/lib/dry/view/errors.rb +29 -0
  11. data/lib/dry/view/exposure.rb +35 -14
  12. data/lib/dry/view/exposures.rb +18 -6
  13. data/lib/dry/view/part.rb +166 -53
  14. data/lib/dry/view/part_builder.rb +140 -0
  15. data/lib/dry/view/path.rb +35 -7
  16. data/lib/dry/view/render_environment.rb +62 -0
  17. data/lib/dry/view/render_environment_missing.rb +44 -0
  18. data/lib/dry/view/rendered.rb +55 -0
  19. data/lib/dry/view/renderer.rb +36 -29
  20. data/lib/dry/view/scope.rb +160 -14
  21. data/lib/dry/view/scope_builder.rb +98 -0
  22. data/lib/dry/view/tilt.rb +78 -0
  23. data/lib/dry/view/tilt/erb.rb +26 -0
  24. data/lib/dry/view/tilt/erbse.rb +21 -0
  25. data/lib/dry/view/tilt/haml.rb +26 -0
  26. data/lib/dry/view/version.rb +5 -2
  27. metadata +78 -115
  28. data/.gitignore +0 -26
  29. data/.rspec +0 -2
  30. data/.travis.yml +0 -23
  31. data/CONTRIBUTING.md +0 -29
  32. data/Gemfile +0 -22
  33. data/LICENSE.md +0 -10
  34. data/Rakefile +0 -6
  35. data/benchmarks/templates/button.html.erb +0 -1
  36. data/benchmarks/view.rb +0 -24
  37. data/bin/console +0 -7
  38. data/lib/dry/view/controller.rb +0 -155
  39. data/lib/dry/view/decorator.rb +0 -45
  40. data/lib/dry/view/missing_renderer.rb +0 -15
  41. data/spec/fixtures/templates/_hello.html.slim +0 -1
  42. data/spec/fixtures/templates/decorated_parts.html.slim +0 -4
  43. data/spec/fixtures/templates/edit.html.slim +0 -11
  44. data/spec/fixtures/templates/empty.html.slim +0 -1
  45. data/spec/fixtures/templates/greeting.html.slim +0 -2
  46. data/spec/fixtures/templates/hello.html.slim +0 -1
  47. data/spec/fixtures/templates/layouts/app.html.slim +0 -6
  48. data/spec/fixtures/templates/layouts/app.txt.erb +0 -3
  49. data/spec/fixtures/templates/parts_with_args.html.slim +0 -3
  50. data/spec/fixtures/templates/parts_with_args/_box.html.slim +0 -3
  51. data/spec/fixtures/templates/shared/_index_table.html.slim +0 -2
  52. data/spec/fixtures/templates/shared/_shared_hello.html.slim +0 -1
  53. data/spec/fixtures/templates/tasks.html.slim +0 -3
  54. data/spec/fixtures/templates/user.html.slim +0 -2
  55. data/spec/fixtures/templates/users.html.slim +0 -5
  56. data/spec/fixtures/templates/users.txt.erb +0 -3
  57. data/spec/fixtures/templates/users/_row.html.slim +0 -2
  58. data/spec/fixtures/templates/users/_tbody.html.slim +0 -5
  59. data/spec/fixtures/templates/users_with_count.html.slim +0 -5
  60. data/spec/fixtures/templates/users_with_count_inherit.html.slim +0 -6
  61. data/spec/fixtures/templates_override/_hello.html.slim +0 -1
  62. data/spec/fixtures/templates_override/users.html.slim +0 -5
  63. data/spec/integration/decorator_spec.rb +0 -80
  64. data/spec/integration/exposures_spec.rb +0 -392
  65. data/spec/integration/part/decorated_attributes_spec.rb +0 -157
  66. data/spec/integration/view_spec.rb +0 -133
  67. data/spec/spec_helper.rb +0 -46
  68. data/spec/unit/controller_spec.rb +0 -37
  69. data/spec/unit/decorator_spec.rb +0 -61
  70. data/spec/unit/exposure_spec.rb +0 -227
  71. data/spec/unit/exposures_spec.rb +0 -103
  72. data/spec/unit/part_spec.rb +0 -90
  73. data/spec/unit/renderer_spec.rb +0 -57
  74. data/spec/unit/scope_spec.rb +0 -53
@@ -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
@@ -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
@@ -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
@@ -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