rafters 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +9 -30
- data/lib/rafters/component.rb +12 -34
- data/lib/rafters/component_context.rb +25 -0
- data/lib/rafters/version.rb +1 -1
- data/spec/dummy/app/components/author/author_component.rb +0 -3
- data/spec/dummy/app/components/heading/heading_component.rb +1 -2
- data/spec/dummy/app/components/post/post_component.rb +1 -6
- data/spec/dummy/app/components/posts/posts_component.rb +1 -1
- data/spec/rafters/component_context_spec.rb +0 -2
- data/spec/rafters/component_spec.rb +24 -29
- 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: 1ac7e06cae8eb40c60138562dca5806c7e7c91a9
|
4
|
+
data.tar.gz: 27e6adca0f5e3859ab26c2ec2a6dcb84c0be4a20
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e5f25e71ba70d5b4953a70ec870701b1a82a1d84394fc5f3ebdaa394c6d9291a6deb869d3436f038f4103025f91501c999a14d4a114cade086da3eeaf921b959
|
7
|
+
data.tar.gz: 01891c2592c824bc5da723fa63f9b7b8bbe659d8909975328e10d56376ca4b9d1ce45b7a7d772379564aa205d70565a2a84034eae2c2990ff6851c1ff170d85a
|
data/README.md
CHANGED
@@ -74,7 +74,7 @@ You can render components anywhere - in your view, in your controller, in anothe
|
|
74
74
|
|
75
75
|
### Adding an attribute to a component
|
76
76
|
|
77
|
-
Each component exposes `attributes` to it's view as locals. The `attributes` are simply a collection of methods that you explicitly declare as `attributes` in your component, using the
|
77
|
+
Each component exposes `attributes` to it's view as locals. The `attributes` are simply a collection of methods that you explicitly declare as `attributes` in your component, using the Rafters::Component.attribute` or `Rafters::Component.attributes` methods.
|
78
78
|
|
79
79
|
For instance, let's say we have a HeadingComponent that exposes a title attribute:
|
80
80
|
|
@@ -104,7 +104,7 @@ You can access the method in your component view using the name of the attribute
|
|
104
104
|
|
105
105
|
### Accessing information from the controller in your components
|
106
106
|
|
107
|
-
There will often be times when you need to access data in your component that is only available as an instance variable or method in your controller. Rafters provides a convenience method that lets you get to that data in a uniform way - `Rafters::Component#
|
107
|
+
There will often be times when you need to access data in your component that is only available as an instance variable or method in your controller. Rafters provides a convenience method that lets you get to that data in a uniform way - `Rafters::Component#controller`:
|
108
108
|
|
109
109
|
```ruby
|
110
110
|
class PostController
|
@@ -128,7 +128,7 @@ class RelatedPostsComponent
|
|
128
128
|
...
|
129
129
|
|
130
130
|
def related_posts
|
131
|
-
@related_posts ||=
|
131
|
+
@related_posts ||= controller(:post).related_posts.where(author_id: controller(:current_user))
|
132
132
|
end
|
133
133
|
end
|
134
134
|
```
|
@@ -136,23 +136,13 @@ end
|
|
136
136
|
You can also access the controller's params using this method:
|
137
137
|
|
138
138
|
```ruby
|
139
|
-
|
139
|
+
controller(:params)[:id]
|
140
140
|
```
|
141
141
|
|
142
|
-
###
|
142
|
+
### Specifying settings for a component instance
|
143
143
|
|
144
|
-
In order to build components in a way that allows for re-use, you'll want to
|
144
|
+
In order to build components in a way that allows for re-use, you'll want to use settings that allow individual instances of the component to be configured. These settings will likely be used throughout your component view and controller for any number of purposes, like values in query conditions, section titles, turning on or off specific features of a component, etc.
|
145
145
|
|
146
|
-
Adding a setting is very similar to adding an attribute, except they don't point at methods:
|
147
|
-
|
148
|
-
```ruby
|
149
|
-
class PostsComponent
|
150
|
-
include Rafters::Component
|
151
|
-
|
152
|
-
setting :published
|
153
|
-
end
|
154
|
-
```
|
155
|
-
|
156
146
|
Setting values are specified when rendering a component:
|
157
147
|
|
158
148
|
```erb
|
@@ -187,22 +177,11 @@ class PostsComponent
|
|
187
177
|
end
|
188
178
|
```
|
189
179
|
|
190
|
-
Default values can be provided for settings using
|
180
|
+
Default values can be provided for settings using `Rafters::Component.defaults` and `Rafters::Component.default`:
|
191
181
|
|
192
182
|
```ruby
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
Required settings can be specified using the `required` option:
|
197
|
-
|
198
|
-
```ruby
|
199
|
-
setting :user_id, required: true
|
200
|
-
```
|
201
|
-
|
202
|
-
If you want to restrict the possible values of a setting to a known list, use the `accepts` option:
|
203
|
-
|
204
|
-
```ruby
|
205
|
-
setting :type, accepts: %w(post reply comment)
|
183
|
+
defaults type: "comment", filter: "none"
|
184
|
+
default :published, false
|
206
185
|
```
|
207
186
|
|
208
187
|
## Contributing
|
data/lib/rafters/component.rb
CHANGED
@@ -30,49 +30,23 @@ module Rafters::Component
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def settings
|
33
|
-
|
34
|
-
|
35
|
-
@_settings ||= Hashie::Mash.new.tap do |_settings|
|
36
|
-
self.class._settings.each do |name, options|
|
37
|
-
_settings[name] = value_for_setting(name, options)
|
38
|
-
end
|
39
|
-
end
|
33
|
+
@_settings ||= Hashie::Mash.new(@settings.reverse_merge(self.class._defaults || {}))
|
40
34
|
end
|
41
35
|
|
42
|
-
def
|
36
|
+
def controller(variable_or_method_name)
|
43
37
|
if @controller.instance_variable_defined?("@#{variable_or_method_name}")
|
44
38
|
@controller.instance_variable_get("@#{variable_or_method_name}")
|
45
39
|
elsif @controller.respond_to?(variable_or_method_name, true)
|
46
40
|
@controller.send(variable_or_method_name)
|
47
41
|
else
|
48
|
-
raise
|
42
|
+
raise ControllerMethodOrVariableMissing, "#{variable_or_method_name.to_s} not found in #{@controller.class.name}"
|
49
43
|
end
|
50
44
|
end
|
51
45
|
|
52
46
|
private
|
53
47
|
|
54
|
-
def value_for_setting(name, options)
|
55
|
-
value = @settings.has_key?(name) ? @settings[name] : options[:default]
|
56
|
-
validate_setting(name, value, options) && value
|
57
|
-
end
|
58
|
-
|
59
|
-
def validate_setting(name, value, options)
|
60
|
-
validate_setting_required(name, value, options[:required])
|
61
|
-
validate_setting_accepts(name, value, options[:accepts])
|
62
|
-
end
|
63
|
-
|
64
|
-
def validate_setting_required(name, value, required)
|
65
|
-
return true unless !!required
|
66
|
-
raise SettingRequired, "#{name} is required but not provided" if value.nil?
|
67
|
-
end
|
68
|
-
|
69
|
-
def validate_setting_accepts(name, value, accepts)
|
70
|
-
return true unless !!accepts
|
71
|
-
raise InvalidSetting, "#{value} is not a valid value for #{name}. Accepts: #{accepts.join(', ')}" unless accepts.include?(value)
|
72
|
-
end
|
73
|
-
|
74
48
|
module ClassMethods
|
75
|
-
attr_accessor :_attributes, :
|
49
|
+
attr_accessor :_attributes, :_defaults, :_template_name
|
76
50
|
|
77
51
|
def attribute(name)
|
78
52
|
self._attributes ||= []
|
@@ -83,9 +57,13 @@ module Rafters::Component
|
|
83
57
|
names.each { |name| attribute(name) }
|
84
58
|
end
|
85
59
|
|
86
|
-
def
|
87
|
-
self.
|
88
|
-
self.
|
60
|
+
def default(name, value)
|
61
|
+
self._defaults ||= {}
|
62
|
+
self._defaults[name] = value
|
63
|
+
end
|
64
|
+
|
65
|
+
def defaults(settings = {})
|
66
|
+
settings.each { |name, value| default(name, value) }
|
89
67
|
end
|
90
68
|
|
91
69
|
def template_name(name)
|
@@ -93,7 +71,7 @@ module Rafters::Component
|
|
93
71
|
end
|
94
72
|
end
|
95
73
|
|
96
|
-
class
|
74
|
+
class ControllerMethodOrVariableMissing < StandardError; end
|
97
75
|
class SettingRequired < StandardError; end
|
98
76
|
class InvalidSetting < StandardError; end
|
99
77
|
end
|
@@ -3,6 +3,7 @@ module Rafters::ComponentContext
|
|
3
3
|
|
4
4
|
included do
|
5
5
|
helper_method :render_component
|
6
|
+
alias_method_chain :render, :component
|
6
7
|
end
|
7
8
|
|
8
9
|
def render_component(name, settings = {}, template_name = nil)
|
@@ -11,6 +12,30 @@ module Rafters::ComponentContext
|
|
11
12
|
component_renderer.render(component, template_name)
|
12
13
|
end
|
13
14
|
|
15
|
+
def render_component_attributes(name, settings = {})
|
16
|
+
component_klass = "#{name}_component".classify.constantize
|
17
|
+
component = component_klass.new(settings)
|
18
|
+
{ :"#{name}" => component.attributes }.as_json
|
19
|
+
end
|
20
|
+
|
21
|
+
def render_with_component(*args, &block)
|
22
|
+
if params[:component]
|
23
|
+
component, settings = params[:component], params[:settings]
|
24
|
+
|
25
|
+
respond_to do |format|
|
26
|
+
format.html do
|
27
|
+
render_without_component(text: render_component(component, settings)) and return
|
28
|
+
end
|
29
|
+
|
30
|
+
format.json do
|
31
|
+
render_without_component(json: render_component_attributes(component, settings)) and return
|
32
|
+
end
|
33
|
+
end
|
34
|
+
else
|
35
|
+
render_without_component(*args, &block)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
14
39
|
private
|
15
40
|
|
16
41
|
def component_renderer
|
data/lib/rafters/version.rb
CHANGED
@@ -1,16 +1,11 @@
|
|
1
1
|
class PostComponent
|
2
2
|
include Rafters::Component
|
3
3
|
|
4
|
-
# Settings
|
5
|
-
setting :post
|
6
|
-
setting :link_to_post, accepts: [true, false], default: false
|
7
|
-
|
8
|
-
# Attributes
|
9
4
|
attribute :post
|
10
5
|
|
11
6
|
private
|
12
7
|
|
13
8
|
def post
|
14
|
-
@post ||= (settings.post ||
|
9
|
+
@post ||= (settings.post || controller(:post))
|
15
10
|
end
|
16
11
|
end
|
@@ -22,30 +22,24 @@ describe Rafters::Component do
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
describe ".
|
26
|
-
it "adds
|
27
|
-
HeadingComponent.
|
25
|
+
describe ".attributes" do
|
26
|
+
it "adds a list of methods to the components attributes" do
|
27
|
+
HeadingComponent.send(:define_method, :title, -> { "Lorem Ipsum" })
|
28
|
+
HeadingComponent.send(:define_method, :subtitle, -> { "Dolor Sit Amet" })
|
29
|
+
HeadingComponent.attributes(:title, :subtitle)
|
28
30
|
|
29
31
|
heading = HeadingComponent.new
|
30
|
-
heading.
|
31
|
-
|
32
|
-
|
33
|
-
context "with a :default value" do
|
34
|
-
it "sets the setting's value to the provided value when no value is available" do
|
35
|
-
HeadingComponent.setting(:type, default: "h1")
|
36
|
-
|
37
|
-
heading = HeadingComponent.new
|
38
|
-
heading.settings.type.should == "h1"
|
39
|
-
end
|
32
|
+
heading.attributes.keys.map(&:to_sym).should include(:title)
|
33
|
+
heading.attributes.keys.map(&:to_sym).should include(:subtitle)
|
40
34
|
end
|
35
|
+
end
|
41
36
|
|
42
|
-
|
43
|
-
|
44
|
-
|
37
|
+
describe ".defaults" do
|
38
|
+
it "adds default values to the component settings" do
|
39
|
+
HeadingComponent.defaults(foo: "bar")
|
45
40
|
|
46
|
-
|
47
|
-
|
48
|
-
end
|
41
|
+
heading = HeadingComponent.new
|
42
|
+
heading.settings.foo.should == "bar"
|
49
43
|
end
|
50
44
|
end
|
51
45
|
|
@@ -63,15 +57,16 @@ describe Rafters::Component do
|
|
63
57
|
end
|
64
58
|
|
65
59
|
describe "#settings" do
|
66
|
-
before do
|
67
|
-
HeadingComponent.setting(:type)
|
68
|
-
end
|
69
|
-
|
70
60
|
subject { HeadingComponent.new({ type: "h2" }) }
|
71
61
|
|
72
|
-
it "returns the
|
62
|
+
it "returns the provided settings" do
|
73
63
|
subject.settings.should == Hashie::Mash.new({ type: "h2" })
|
74
64
|
end
|
65
|
+
|
66
|
+
it "gives provided settings precedence over default settings" do
|
67
|
+
HeadingComponent.default(:type, "h1")
|
68
|
+
subject.settings[:type].should == "h2"
|
69
|
+
end
|
75
70
|
end
|
76
71
|
|
77
72
|
describe "#template_name" do
|
@@ -107,7 +102,7 @@ describe Rafters::Component do
|
|
107
102
|
end
|
108
103
|
end
|
109
104
|
|
110
|
-
describe "#
|
105
|
+
describe "#controller" do
|
111
106
|
subject { HeadingComponent.new }
|
112
107
|
|
113
108
|
let(:controller) { Object.new }
|
@@ -122,7 +117,7 @@ describe Rafters::Component do
|
|
122
117
|
end
|
123
118
|
|
124
119
|
it "returns the value of the instance variable" do
|
125
|
-
subject.
|
120
|
+
subject.controller(:foo_bar).should == "lorem ipsum"
|
126
121
|
end
|
127
122
|
end
|
128
123
|
|
@@ -132,13 +127,13 @@ describe Rafters::Component do
|
|
132
127
|
end
|
133
128
|
|
134
129
|
it "returns the value of the method" do
|
135
|
-
subject.
|
130
|
+
subject.controller(:lorem_ipsum).should == "foo bar"
|
136
131
|
end
|
137
132
|
end
|
138
133
|
|
139
134
|
context "when there is neither a method nor an instance variable with the given name in the controller" do
|
140
135
|
it "raises an error" do
|
141
|
-
-> { subject.
|
136
|
+
-> { subject.controller(:doesnt_exist) }.should raise_error(Rafters::Component::ControllerMethodOrVariableMissing)
|
142
137
|
end
|
143
138
|
end
|
144
139
|
end
|
@@ -147,7 +142,7 @@ describe Rafters::Component do
|
|
147
142
|
# A little housekeeping after each spec runs, so that
|
148
143
|
# we have fresh values for each class attribute
|
149
144
|
HeadingComponent._attributes = [:settings]
|
150
|
-
HeadingComponent.
|
145
|
+
HeadingComponent._defaults = {}
|
151
146
|
HeadingComponent._template_name = nil
|
152
147
|
end
|
153
148
|
end
|