-
Notifications
You must be signed in to change notification settings - Fork 29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Component presenter class #26
Changes from 10 commits
28386a4
8181e18
b8e8cba
2e30bc5
53fb802
89eed1e
9da1b65
2ca764e
a7dadc3
861e9d1
4dd2cb3
1a5727a
a0adcec
c7021f3
683f9c2
00f75d6
c64c8e5
e0eab2d
422a279
ca3bf20
bf12ab0
728363a
df31920
383a056
cdf1845
1cf37a4
692f606
070e4bf
17cafd5
b4f6748
a15192a
9aa58a0
6036a8d
4c24333
286d77b
9882966
84d614e
bdb2c9c
3dd5821
b46365a
dabb6c7
1c59089
9dcaabb
baf1c08
897a5c4
8bc298c
16662fe
13eeeaa
636b6b2
6502d0d
1ade24d
c80984f
e255d33
682021a
678f022
2176069
2a458b3
0698f5f
33b208b
c6e6ea2
2449dcc
a7625d8
166906e
c0c9ea5
cde8031
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,8 @@ | ||
module MountainView | ||
module ComponentHelper | ||
def render_component(slug, properties = {}) | ||
render "#{slug}/#{slug}", properties: properties | ||
component = MountainView::Presenter.component_for(slug, properties) | ||
render partial: component.partial, locals: component.locals | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
module MountainView | ||
class Presenter | ||
class_attribute :_attributes, instance_accessor: false | ||
self._attributes = {} | ||
|
||
attr_reader :slug, :properties | ||
alias_method :props, :properties | ||
|
||
def initialize(slug, properties={}) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Surrounding space missing in default value assignment. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Surrounding space missing in default value assignment. |
||
@slug = slug | ||
@properties = properties | ||
end | ||
|
||
def partial | ||
"#{slug}/#{slug}" | ||
end | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you think of naming this method It's a bit more Rails-y, and that way we can use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Very nice solution, hadn't even thought of that! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, unfortunately Rails does something a bit special with The only way I can see to prevent this behaviour would be to override There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, didn't know about that! Thanks for the research! |
||
|
||
def locals | ||
locals = build_hash | ||
locals.merge(properties: locals) | ||
end | ||
|
||
def attributes | ||
@attributes ||= properties.keys.inject({}) do |sum, name| | ||
sum[name] = {} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is the default a hash here? |
||
sum | ||
end.merge(self.class._attributes) | ||
end | ||
|
||
private | ||
|
||
def build_hash | ||
attributes.inject({}) do|sum, (k, v)| | ||
sum[k] = attribute_value(k) | ||
sum | ||
end | ||
end | ||
|
||
def attribute_value(key) | ||
attribute = attributes[key] || return | ||
value = respond_to?(key) ? send(key) : properties[key] | ||
value || attribute[:default] | ||
end | ||
|
||
class << self | ||
def attributes(*args) | ||
opts = args.extract_options! | ||
attributes = args.inject({}) do |sum, name| | ||
sum[name] = opts | ||
sum | ||
end | ||
self._attributes = self._attributes.merge(attributes) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Redundant |
||
end | ||
|
||
alias_method :attribute, :attributes | ||
end | ||
|
||
def self.component_for(slug, properties={}) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Surrounding space missing in default value assignment. |
||
klass = descendants.find{|d| d.to_s.demodulize == "#{slug.to_s.classify}Component" } | ||
klass ||= self | ||
klass.new(slug, properties) | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
class CardComponent < MountainView::Presenter | ||
attributes :title, :description, :link, :image_url | ||
attribute :data, default: [] | ||
attribute :foobar | ||
|
||
def title | ||
['Foobar', properties[:title]].join(' - ') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping. |
||
end | ||
|
||
def foobar | ||
h.content_tag(:p, "Foobar!!") | ||
end | ||
|
||
private | ||
|
||
def h | ||
ActionController::Base.helpers | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
MountainView.configure do |config| | ||
config.included_stylesheets = ["global"] | ||
end | ||
|
||
# include component classes | ||
Dir.glob('app/components/**/*.rb') { |f| require_relative "../../#{f}" } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it'd be possible to add a line to the Something in the lines of the following should work: (haven't tested it) # in lib/mountain_view/engine.rb
initializer "mountain_view.append_component_paths" do |app|
app.autoload_paths += [MountainView.configuration.components_path]
end It'd probably have to include the sub-directories, so Rails doesn't fail to load the files because there's no namespace. What do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Totally agree, to be honest I'd put that in temporarily and totally forgotten about it. Thanks for the pointer. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
require "test_helper" | ||
class InheritedPresenter < MountainView::Presenter | ||
attributes :title, :description | ||
attribute :data, default: [] | ||
|
||
def title | ||
"Foo#{properties[:title].downcase}" | ||
end | ||
end | ||
|
||
class MountainViewPresenterTest < ActiveSupport::TestCase | ||
def test_partial | ||
presenter = MountainView::Presenter.new("header") | ||
assert_equal "header/header", presenter.partial | ||
end | ||
|
||
def test_locals | ||
properties = {name: 'Foo', title: 'Bar'} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Space inside { missing. |
||
presenter = MountainView::Presenter.new('header', properties) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping. |
||
assert_equal add_properties(properties), presenter.locals | ||
end | ||
|
||
def test_attributes | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah yes, I hastily made the |
||
properties = {name: 'Foo', title: 'Bar'} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Space inside { missing. |
||
presenter = MountainView::Presenter.new('header', properties) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping. |
||
assert_equal({name: {}, title: {}}, presenter.attributes) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Space inside { missing. |
||
end | ||
|
||
def test_inherited_locals | ||
properties = {name: 'Foo', title: 'Bar'} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Space inside { missing. |
||
presenter = InheritedPresenter.new('header', properties) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping. |
||
presenter_properties = {title: 'Foobar', description: nil, data: []} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Space inside { missing. |
||
expected_properties = properties.merge(presenter_properties) | ||
assert_equal add_properties(expected_properties), presenter.locals | ||
end | ||
|
||
def test_inherited_attributes | ||
properties = {name: 'Foo', title: 'Bar'} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Space inside { missing. |
||
presenter = InheritedPresenter.new('header', properties) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping. |
||
presenter_attributes = {title: {}, description: {}, data: {default: []}} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Space inside { missing. |
||
expected_attributes = {name: {}, title: {}}.merge(presenter_attributes) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Space inside { missing. |
||
assert_equal expected_attributes, presenter.attributes | ||
end | ||
|
||
def add_properties(properties) | ||
properties.merge(properties: properties) | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this alias being used anywhere? Does it make sense to keep it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The component classes end up with a lot of references to the
properties
hash and I found I wanted a shorter alias. I think it does, but maybe I'm just being lazy 😉There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see! I think I'd be fine to remove it, and people can always alias in in their inherited presenters if they want.