dry-view 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/lib/dry/view/controller.rb +1 -1
- data/lib/dry/view/exposure.rb +19 -19
- data/lib/dry/view/version.rb +1 -1
- data/spec/integration/exposures_spec.rb +35 -2
- data/spec/unit/exposure_spec.rb +91 -54
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f4a41e09f937605f77be24092d9da6ff653da34d
|
4
|
+
data.tar.gz: 5bde51853d38d892bbbba62f42acacfebcfd71b4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b5121bec86b8fa020f4e46dd12beae722fee4eb135a000efff37926061e376206ca507aaea6a3334707df618d9368ca5201af041581fe6f4fedc626ed643df0e
|
7
|
+
data.tar.gz: 422541634a6634adfdac9cb2fa8e82e0b8cc35efc8aaf9dfe669a08394020ead0ce776a5564bb5819c701a43959f95c8d638a51d4ba389433c7b1fc09f88a3c7
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
# 0.2.1 / 2017-01-30
|
2
|
+
|
3
|
+
### Fixed
|
4
|
+
|
5
|
+
- Exposure blocks now have access to the view controller instance when they're called (timriley)
|
6
|
+
|
1
7
|
# 0.2.0 / 2017-01-30
|
2
8
|
|
3
9
|
This release is a major reorientation for dry-view, and it should allow for more natural, straightforward template authoring.
|
data/lib/dry/view/controller.rb
CHANGED
data/lib/dry/view/exposure.rb
CHANGED
@@ -5,28 +5,30 @@ module Dry
|
|
5
5
|
|
6
6
|
attr_reader :name
|
7
7
|
attr_reader :proc
|
8
|
+
attr_reader :object
|
8
9
|
attr_reader :to_view
|
9
10
|
|
10
|
-
def initialize(name, proc = nil, to_view: true)
|
11
|
-
ensure_proc_parameters(proc) if proc
|
12
|
-
|
11
|
+
def initialize(name, proc = nil, object = nil, to_view: true)
|
13
12
|
@name = name
|
14
|
-
@proc = proc
|
13
|
+
@proc = prepare_proc(proc, object)
|
14
|
+
@object = object
|
15
15
|
@to_view = to_view
|
16
16
|
end
|
17
17
|
|
18
18
|
def bind(obj)
|
19
|
-
proc
|
19
|
+
self.class.new(name, proc, obj, to_view: to_view)
|
20
20
|
end
|
21
21
|
|
22
22
|
def dependencies
|
23
|
-
proc.parameters.map(&:last)
|
23
|
+
proc ? proc.parameters.map(&:last) : []
|
24
24
|
end
|
25
25
|
|
26
26
|
alias_method :to_view?, :to_view
|
27
27
|
|
28
28
|
def call(input, locals = {})
|
29
|
-
|
29
|
+
return input.fetch(name) unless proc
|
30
|
+
|
31
|
+
args = dependencies.map.with_index { |name, position|
|
30
32
|
if position.zero?
|
31
33
|
locals.fetch(name) { input }
|
32
34
|
else
|
@@ -34,26 +36,24 @@ module Dry
|
|
34
36
|
end
|
35
37
|
}
|
36
38
|
|
37
|
-
|
39
|
+
call_proc(*args)
|
38
40
|
end
|
39
41
|
|
40
42
|
private
|
41
43
|
|
42
|
-
def
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
def build_default_proc(obj)
|
47
|
-
if obj.respond_to?(name, _include_private = true)
|
48
|
-
obj.method(name)
|
44
|
+
def call_proc(*args)
|
45
|
+
if proc.is_a?(Method)
|
46
|
+
proc.(*args)
|
49
47
|
else
|
50
|
-
|
48
|
+
object.instance_exec(*args, &proc)
|
51
49
|
end
|
52
50
|
end
|
53
51
|
|
54
|
-
def
|
55
|
-
if proc
|
56
|
-
|
52
|
+
def prepare_proc(proc, object)
|
53
|
+
if proc
|
54
|
+
proc
|
55
|
+
elsif object.respond_to?(name, _include_private = true)
|
56
|
+
object.method(name)
|
57
57
|
end
|
58
58
|
end
|
59
59
|
end
|
data/lib/dry/view/version.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
RSpec.describe 'exposures' do
|
2
2
|
let(:context) { Struct.new(:title, :assets).new('dry-view rocks!', -> input { "#{input}.jpg" }) }
|
3
3
|
|
4
|
-
it 'uses exposures to build view locals' do
|
4
|
+
it 'uses exposures with blocks to build view locals' do
|
5
5
|
vc = Class.new(Dry::View::Controller) do
|
6
6
|
configure do |config|
|
7
7
|
config.paths = SPEC_ROOT.join('fixtures/templates')
|
@@ -27,7 +27,40 @@ RSpec.describe 'exposures' do
|
|
27
27
|
)
|
28
28
|
end
|
29
29
|
|
30
|
-
it '
|
30
|
+
it 'gives the exposure blocks access to the view controller instance' do
|
31
|
+
vc = Class.new(Dry::View::Controller) do
|
32
|
+
configure do |config|
|
33
|
+
config.paths = SPEC_ROOT.join('fixtures/templates')
|
34
|
+
config.layout = 'app'
|
35
|
+
config.template = 'users'
|
36
|
+
config.default_format = :html
|
37
|
+
end
|
38
|
+
|
39
|
+
attr_reader :prefix
|
40
|
+
|
41
|
+
def initialize
|
42
|
+
super
|
43
|
+
@prefix = "My friend "
|
44
|
+
end
|
45
|
+
|
46
|
+
expose :users do |input|
|
47
|
+
input.fetch(:users).map { |user|
|
48
|
+
user.merge(name: prefix + user[:name])
|
49
|
+
}
|
50
|
+
end
|
51
|
+
end.new
|
52
|
+
|
53
|
+
users = [
|
54
|
+
{ name: 'Jane', email: 'jane@doe.org' },
|
55
|
+
{ name: 'Joe', email: 'joe@doe.org' }
|
56
|
+
]
|
57
|
+
|
58
|
+
expect(vc.(users: users, context: context)).to eql(
|
59
|
+
'<!DOCTYPE html><html><head><title>dry-view rocks!</title></head><body><div class="users"><table><tbody><tr><td>My friend Jane</td><td>jane@doe.org</td></tr><tr><td>My friend Joe</td><td>joe@doe.org</td></tr></tbody></table></div><img src="mindblown.jpg" /></body></html>'
|
60
|
+
)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'supports instance methods as exposures' do
|
31
64
|
vc = Class.new(Dry::View::Controller) do
|
32
65
|
configure do |config|
|
33
66
|
config.paths = SPEC_ROOT.join('fixtures/templates')
|
data/spec/unit/exposure_spec.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
RSpec.describe Dry::View::Exposure do
|
2
|
-
subject(:exposure) { described_class.new(:hello, proc) }
|
2
|
+
subject(:exposure) { described_class.new(:hello, proc, object) }
|
3
3
|
|
4
4
|
let(:proc) { -> input { "hi" } }
|
5
|
+
let(:object) { nil }
|
5
6
|
|
6
7
|
describe "initialization and attributes" do
|
7
8
|
describe "#name" do
|
@@ -18,18 +19,17 @@ RSpec.describe Dry::View::Exposure do
|
|
18
19
|
it "allows a nil proc" do
|
19
20
|
expect(described_class.new(:hello).proc).to be_nil
|
20
21
|
end
|
22
|
+
end
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
-
expect { described_class.new(:hello, proc) }.not_to raise_error
|
25
|
-
end
|
24
|
+
describe "#object" do
|
25
|
+
let(:object) { Object.new }
|
26
26
|
|
27
|
-
it "
|
28
|
-
|
29
|
-
|
27
|
+
it "accepts an object" do
|
28
|
+
expect(exposure.object).to eq object
|
29
|
+
end
|
30
30
|
|
31
|
-
|
32
|
-
expect
|
31
|
+
it "allows a nil object" do
|
32
|
+
expect(described_class.new(:hello).object).to be_nil
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
@@ -45,25 +45,29 @@ RSpec.describe Dry::View::Exposure do
|
|
45
45
|
end
|
46
46
|
|
47
47
|
describe "#bind" do
|
48
|
-
|
49
|
-
subject(:bound_exposure) { exposure.bind(Object.new) }
|
48
|
+
subject(:bound_exposure) { exposure.bind(bind_object) }
|
50
49
|
|
51
|
-
|
52
|
-
expect(bound_exposure).to eql exposure
|
53
|
-
end
|
50
|
+
let(:bind_object) { Object.new }
|
54
51
|
|
55
|
-
|
52
|
+
it "returns a new object" do
|
53
|
+
expect(bound_exposure).not_to eql exposure
|
54
|
+
end
|
55
|
+
|
56
|
+
it "retains the bind object" do
|
57
|
+
expect(bound_exposure.object).to eq bind_object
|
58
|
+
end
|
59
|
+
|
60
|
+
context "proc is set" do
|
61
|
+
it "retains the existing proc" do
|
56
62
|
expect(bound_exposure.proc).to eql proc
|
57
63
|
end
|
58
64
|
end
|
59
65
|
|
60
|
-
context "
|
61
|
-
|
62
|
-
|
63
|
-
let(:exposure) { described_class.new(:hello) }
|
66
|
+
context "proc is nil" do
|
67
|
+
let(:proc) { nil }
|
64
68
|
|
65
69
|
context "matching instance method" do
|
66
|
-
let(:
|
70
|
+
let(:bind_object) do
|
67
71
|
Class.new do
|
68
72
|
def hello(input)
|
69
73
|
"hi there, #{input.fetch(:name)}"
|
@@ -71,75 +75,108 @@ RSpec.describe Dry::View::Exposure do
|
|
71
75
|
end.new
|
72
76
|
end
|
73
77
|
|
74
|
-
it "returns a new object" do
|
75
|
-
expect(bound_exposure).not_to eql exposure
|
76
|
-
end
|
77
|
-
|
78
78
|
it "sets the proc to the method on the object matching the exposure's name" do
|
79
|
-
expect(bound_exposure.proc).to eql
|
79
|
+
expect(bound_exposure.proc).to eql bind_object.method(:hello)
|
80
80
|
end
|
81
81
|
end
|
82
82
|
|
83
83
|
context "no matching instance method" do
|
84
84
|
let(:object) { Object.new }
|
85
85
|
|
86
|
-
it "
|
87
|
-
expect(bound_exposure).
|
88
|
-
end
|
89
|
-
|
90
|
-
it "builds a proc that passes through data from a matching key in the input" do
|
91
|
-
expect(bound_exposure.proc.(hello: "hello in input")).to eq "hello in input"
|
86
|
+
it "leaves proc as nil" do
|
87
|
+
expect(bound_exposure.proc).to be_nil
|
92
88
|
end
|
93
89
|
end
|
94
90
|
end
|
95
91
|
end
|
96
92
|
|
97
93
|
describe "#dependencies" do
|
98
|
-
|
94
|
+
context "proc provided" do
|
95
|
+
let(:proc) { -> input, foo, bar { "hi" } }
|
99
96
|
|
100
|
-
|
101
|
-
|
97
|
+
it "returns an array of exposure dependencies derived from the proc's argument names" do
|
98
|
+
expect(exposure.dependencies).to eql [:input, :foo, :bar]
|
99
|
+
end
|
102
100
|
end
|
103
|
-
end
|
104
101
|
|
105
|
-
|
106
|
-
|
102
|
+
context "matching instance method" do
|
103
|
+
let(:proc) { nil }
|
104
|
+
|
105
|
+
let(:object) do
|
106
|
+
Class.new do
|
107
|
+
def hello(input, bar, baz)
|
108
|
+
"hi there, #{input.fetch(:name)}"
|
109
|
+
end
|
110
|
+
end.new
|
111
|
+
end
|
107
112
|
|
108
|
-
|
109
|
-
|
113
|
+
it "returns an array of exposure dependencies derived from the instance method's argument names" do
|
114
|
+
expect(exposure.dependencies).to eql [:input, :bar, :baz]
|
115
|
+
end
|
110
116
|
end
|
111
117
|
|
118
|
+
context "proc is nil" do
|
119
|
+
let(:proc) { nil }
|
120
|
+
|
121
|
+
it "returns no dependencies" do
|
122
|
+
expect(exposure.dependencies).to eql []
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
describe "#call" do
|
128
|
+
let(:input) { "input" }
|
129
|
+
|
112
130
|
context "proc expects input only" do
|
113
|
-
|
114
|
-
exposure.(input)
|
131
|
+
let(:proc) { -> input { input } }
|
115
132
|
|
116
|
-
|
133
|
+
it "sends the input to the proc" do
|
134
|
+
expect(exposure.(input)).to eql "input"
|
117
135
|
end
|
118
136
|
end
|
119
137
|
|
120
138
|
context "proc expects input and dependencies" do
|
121
|
-
let(:proc) { -> input, greeting { "#{greeting}, #{input
|
139
|
+
let(:proc) { -> input, greeting { "#{greeting}, #{input}" } }
|
122
140
|
let(:locals) { {greeting: "Hola"} }
|
123
141
|
|
124
|
-
before do
|
125
|
-
exposure.(input, locals)
|
126
|
-
end
|
127
|
-
|
128
142
|
it "sends the input and dependency values to the proc" do
|
129
|
-
expect(
|
143
|
+
expect(exposure.(input, locals)).to eq "Hola, input"
|
130
144
|
end
|
131
145
|
end
|
132
146
|
|
133
147
|
context "proc expects dependencies only" do
|
134
|
-
let(:proc) { -> greeting, farewell { "#{greeting}, #{
|
148
|
+
let(:proc) { -> greeting, farewell { "#{greeting}, #{farewell}" } }
|
135
149
|
let(:locals) { {greeting: "Hola", farewell: "Adios"} }
|
136
150
|
|
137
|
-
|
138
|
-
exposure.(input, locals)
|
151
|
+
it "sends the dependency values to the proc" do
|
152
|
+
expect(exposure.(input, locals)).to eq "Hola, Adios"
|
139
153
|
end
|
154
|
+
end
|
140
155
|
|
141
|
-
|
142
|
-
|
156
|
+
context "proc accesses object instance" do
|
157
|
+
let(:proc) { -> input { "#{input} from #{name}" } }
|
158
|
+
|
159
|
+
let(:object) do
|
160
|
+
Class.new do
|
161
|
+
attr_reader :name
|
162
|
+
|
163
|
+
def initialize(name)
|
164
|
+
@name = name
|
165
|
+
end
|
166
|
+
end.new("Jane")
|
167
|
+
end
|
168
|
+
|
169
|
+
it "makes the instance available as self" do
|
170
|
+
expect(exposure.(input)).to eq "input from Jane"
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
context "no proc" do
|
175
|
+
let(:proc) { nil }
|
176
|
+
let(:input) { {hello: "hi there"} }
|
177
|
+
|
178
|
+
it "returns a matching key from the input" do
|
179
|
+
expect(exposure.(input)).to eq "hi there"
|
143
180
|
end
|
144
181
|
end
|
145
182
|
end
|