showcase 0.1.7 → 0.2.0.beta

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.
@@ -0,0 +1,61 @@
1
+ require 'showcase/helpers/config_object'
2
+ require 'active_support/core_ext/object/to_query'
3
+
4
+ module Showcase
5
+ module Traits
6
+ module Share
7
+ extend ActiveSupport::Concern
8
+ include LinkTo
9
+
10
+ PROVIDERS = {
11
+ twitter: {
12
+ url: "https://twitter.com/intent/tweet",
13
+ params: { url: :url, text: :text },
14
+ label: 'Tweet it!'
15
+ },
16
+ gplus: {
17
+ url: "https://plus.google.com/share",
18
+ params: { url: :url },
19
+ label: 'Share it on Google Plus!'
20
+ },
21
+ facebook: {
22
+ url: "http://www.facebook.com/sharer/sharer.php",
23
+ params: { u: :url },
24
+ label: 'Share it on Facebook!'
25
+ },
26
+ linkedin: {
27
+ url: "http://www.linkedin.com/shareArticle",
28
+ params: { url: :url, title: :text },
29
+ label: 'Share it on LinkedIn!'
30
+ },
31
+ pinterest: {
32
+ url: "http://www.pinterest.com/pin/create/button/",
33
+ params: { url: :url, media: :image_url, title: :text },
34
+ label: 'Pin it!'
35
+ }
36
+ }
37
+
38
+ module ClassMethods
39
+ def share(name = nil, &block)
40
+ PROVIDERS.each do |social, settings|
41
+ link_name = [ name, social, "share" ].map(&:presence).compact.join("_")
42
+
43
+ link_to link_name do |c|
44
+ meta = Helpers::ConfigObject.new(self, &block).to_struct
45
+ params = Hash[
46
+ settings[:params].map do |param, meta_key|
47
+ [ param, meta.send(meta_key) ]
48
+ end
49
+ ]
50
+ c.url "#{settings[:url]}?#{params.to_query}"
51
+ c.label settings[:label]
52
+ c.html_options = { target: :blank }
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ end
59
+ end
60
+ end
61
+
@@ -0,0 +1,11 @@
1
+ require 'showcase/traits/base'
2
+ require 'showcase/traits/record'
3
+ require 'showcase/traits/seo'
4
+ require 'showcase/traits/link_to'
5
+ require 'showcase/traits/share'
6
+
7
+ module Showcase
8
+ module Traits
9
+ end
10
+ end
11
+
@@ -1,4 +1,4 @@
1
1
  module Showcase
2
- VERSION = "0.1.7"
2
+ VERSION = "0.2.0.beta"
3
3
  end
4
4
 
data/lib/showcase.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  require 'showcase/version'
2
2
  require 'showcase/presenter'
3
+ require 'showcase/railtie' if defined?(Rails)
3
4
 
4
5
  module Showcase
5
6
  end
7
+
data/showcase.gemspec CHANGED
@@ -18,7 +18,10 @@ Gem::Specification.new do |gem|
18
18
  gem.require_paths = ['lib']
19
19
 
20
20
  gem.add_dependency 'activesupport'
21
+
21
22
  gem.add_development_dependency 'rspec'
22
23
  gem.add_development_dependency 'coveralls'
24
+ gem.add_development_dependency 'rails'
25
+ gem.add_development_dependency 'rspec-html-matchers'
23
26
  end
24
27
 
data/spec/fixtures.rb CHANGED
@@ -1,3 +1,19 @@
1
+ class RailsViewContext < ActionView::Base
2
+ include ActionView::Helpers::TagHelper
3
+
4
+ def capture(*args, &block)
5
+ block.call(*args)
6
+ end
7
+ end
8
+
9
+ class Model
10
+ extend ActiveModel::Naming
11
+
12
+ def to_key
13
+ Array('1')
14
+ end
15
+ end
16
+
1
17
  class Person < Struct.new(:name)
2
18
  end
3
19
 
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ module Showcase::Helpers
4
+ describe ConfigObject do
5
+
6
+ let(:context_class) {
7
+ Class.new do
8
+ def foo
9
+ 'foo'
10
+ end
11
+
12
+ def bar
13
+ 'bar'
14
+ end
15
+ end
16
+ }
17
+ let(:context) { context_class.new }
18
+
19
+ describe 'to_hash' do
20
+ it 'accepts attr=() notation' do
21
+ result = ConfigObject.new(context) do |c|
22
+ c.first = foo
23
+ c.second = bar
24
+ c.third = '3rd'
25
+ end.to_hash
26
+
27
+ hash = { first: 'foo', second: 'bar', third: '3rd' }
28
+ expect(result).to eq hash
29
+ end
30
+
31
+ it 'accepts attr() notation' do
32
+ result = ConfigObject.new(context) do |c|
33
+ c.first foo
34
+ c.second bar
35
+ c.third '3rd'
36
+ end.to_hash
37
+
38
+ hash = { first: 'foo', second: 'bar', third: '3rd' }
39
+ expect(result).to eq hash
40
+ end
41
+ end
42
+
43
+ end
44
+ end
45
+
@@ -0,0 +1,95 @@
1
+ require 'spec_helper'
2
+
3
+ module Showcase::Helpers
4
+ describe SeoMetaBuilder do
5
+
6
+ let(:view) { RailsViewContext.new }
7
+ let(:builder) { double('SeoMetaBuilder') }
8
+
9
+ subject { SeoMetaBuilder.new(view) }
10
+
11
+ describe '#title' do
12
+ it 'produces a <title/> tag' do
13
+ expect(subject.title('foo')).to have_tag(:title, text: 'foo')
14
+ end
15
+
16
+ it 'produces a og:title meta tag' do
17
+ expect(subject.title('foo')).to have_tag(:meta, with: { property: 'og:title', content: 'foo' })
18
+ end
19
+
20
+ it 'produces a twitter:title meta tag' do
21
+ expect(subject.title('foo')).to have_tag(:meta, with: { name: 'twitter:title', content: 'foo' })
22
+ end
23
+
24
+ context 'with multiple values' do
25
+ it 'uses the first non-blank' do
26
+ expect(subject.title(['', nil, 'foo'])).to have_tag(:title, text: 'foo')
27
+ end
28
+ end
29
+
30
+ context 'with a :title_suffix option' do
31
+ it 'produces a <title/> tag with the suffix' do
32
+ expect(subject.title('foo', title_suffix: ' - bar')).to have_tag(:title, text: 'foo - bar')
33
+ end
34
+ it 'does not suffix meta tags' do
35
+ expect(subject.title('foo')).to have_tag(:meta, with: { property: 'og:title', content: 'foo' })
36
+ expect(subject.title('foo')).to have_tag(:meta, with: { name: 'twitter:title', content: 'foo' })
37
+ end
38
+ end
39
+ end
40
+
41
+ describe '#description' do
42
+ it 'produces a description meta tag' do
43
+ expect(subject.description('foo')).to have_tag(:meta, with: { name: 'description', content: 'foo' })
44
+ end
45
+
46
+ it 'produces a og:description meta tag' do
47
+ expect(subject.description('foo')).to have_tag(:meta, with: { property: 'og:description', content: 'foo' })
48
+ end
49
+
50
+ it 'produces a twitter:description meta tag' do
51
+ expect(subject.description('foo')).to have_tag(:meta, with: { name: 'twitter:description', content: 'foo' })
52
+ end
53
+
54
+ context 'with multiple values' do
55
+ it 'uses the first non-blank' do
56
+ expect(subject.description(['', nil, 'foo'])).to have_tag(:meta, with: { name: 'description', content: 'foo' })
57
+ end
58
+ end
59
+ end
60
+
61
+ describe '#image_url' do
62
+ it 'produces a og:image meta tag' do
63
+ expect(subject.image_url('foo')).to have_tag(:meta, with: { property: 'og:image', content: 'foo' })
64
+ end
65
+
66
+ it 'produces a twitter:image meta tag' do
67
+ expect(subject.image_url('foo')).to have_tag(:meta, with: { name: 'twitter:image', content: 'foo' })
68
+ end
69
+
70
+ context 'with multiple values' do
71
+ it 'uses the first non-blank' do
72
+ expect(subject.image_url(['', nil, 'foo'])).to have_tag(:meta, with: { property: 'og:image', content: 'foo' })
73
+ end
74
+ end
75
+ end
76
+
77
+ describe '#canonical_url' do
78
+ it 'produces a og:url meta tag' do
79
+ expect(subject.canonical_url('foo')).to have_tag(:meta, with: { property: 'og:url', content: 'foo' })
80
+ end
81
+
82
+ it 'produces a canonical link tag' do
83
+ expect(subject.canonical_url('foo')).to have_tag(:link, with: { rel: 'canonical', href: 'foo' })
84
+ end
85
+
86
+ context 'with multiple values' do
87
+ it 'uses the first non-blank' do
88
+ expect(subject.canonical_url(['', nil, 'foo'])).to have_tag(:meta, with: { property: 'og:url', content: 'foo' })
89
+ end
90
+ end
91
+ end
92
+
93
+ end
94
+ end
95
+
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ describe Showcase::Helpers do
4
+ let(:object) { Person.new('Steve Ballmer') }
5
+ let(:context) { Context.new }
6
+
7
+ describe '.present' do
8
+ it 'instanciate a new presenter, inferring the class' do
9
+ PersonPresenter.stub(:new).with(object, context).and_return 'Presenter'
10
+ context.present(object, PersonPresenter).should == 'Presenter'
11
+ end
12
+ it 'the presenter class to use can be specified as the second parameter' do
13
+ ProjectPresenter.stub(:new).with(object, context).and_return 'Presenter'
14
+ context.present(object, ProjectPresenter).should == 'Presenter'
15
+ end
16
+ it 'the context to use can be specified as third parameter' do
17
+ different_context = double
18
+ context.present(object, ProjectPresenter, different_context).view_context.should == different_context
19
+ end
20
+ end
21
+
22
+ describe '.present_collection' do
23
+ it 'returns a presenter for each object in the collection' do
24
+ collection = [ Person.new('Mark'), Person.new('Luke') ]
25
+
26
+ PersonPresenter.stub(:new).with(collection[0], context).and_return 'foo'
27
+ PersonPresenter.stub(:new).with(collection[1], context).and_return 'bar'
28
+
29
+ presented_collection = context.present_collection(collection)
30
+ presented_collection.should == [ 'foo', 'bar' ]
31
+ end
32
+ end
33
+ end
34
+
@@ -1,8 +1,4 @@
1
- require 'coveralls'
2
- Coveralls.wear!
3
-
4
- require 'showcase'
5
- require_relative './fixtures'
1
+ require 'spec_helper'
6
2
 
7
3
  describe Showcase::Presenter do
8
4
  let(:context) { Context.new }
@@ -73,35 +69,3 @@ describe Showcase::Presenter do
73
69
  end
74
70
  end
75
71
 
76
- describe Showcase::Helpers do
77
- let(:object) { Person.new('Steve Ballmer') }
78
- let(:context) { Context.new }
79
-
80
- describe '.present' do
81
- it 'instanciate a new presenter, inferring the class' do
82
- PersonPresenter.stub(:new).with(object, context).and_return 'Presenter'
83
- context.present(object, PersonPresenter).should == 'Presenter'
84
- end
85
- it 'the presenter class to use can be specified as the second parameter' do
86
- ProjectPresenter.stub(:new).with(object, context).and_return 'Presenter'
87
- context.present(object, ProjectPresenter).should == 'Presenter'
88
- end
89
- it 'the context to use can be specified as third parameter' do
90
- different_context = double
91
- context.present(object, ProjectPresenter, different_context).view_context.should == different_context
92
- end
93
- end
94
-
95
- describe '.present_collection' do
96
- it 'returns a presenter for each object in the collection' do
97
- collection = [ Person.new('Mark'), Person.new('Luke') ]
98
-
99
- PersonPresenter.stub(:new).with(collection[0], context).and_return 'foo'
100
- PersonPresenter.stub(:new).with(collection[1], context).and_return 'bar'
101
-
102
- presented_collection = context.present_collection(collection)
103
- presented_collection.should == [ 'foo', 'bar' ]
104
- end
105
- end
106
- end
107
-
@@ -0,0 +1,12 @@
1
+ require 'coveralls'
2
+ Coveralls.wear!
3
+
4
+ require 'rspec-html-matchers'
5
+
6
+ require 'rails'
7
+ require 'showcase'
8
+ require 'active_model'
9
+ require 'action_view'
10
+
11
+ require_relative './fixtures'
12
+
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+
3
+ module Showcase::Traits
4
+ describe Base do
5
+ describe '.define_method?' do
6
+
7
+ it 'defines an instance method' do
8
+ klass = Class.new do
9
+ include Base
10
+ define_method? :foo do
11
+ true
12
+ end
13
+ end
14
+
15
+ expect(klass.new.foo).to be_true
16
+ end
17
+
18
+ context 'if the method is already present' do
19
+ it 'no-ops ' do
20
+ klass = Class.new do
21
+ include Base
22
+ def foo; false; end
23
+ end
24
+
25
+ expect(klass.new.foo).to be_false
26
+ end
27
+ end
28
+
29
+ context 'if method name is an array of chunks' do
30
+ it 'joins them in snake case' do
31
+ klass = Class.new do
32
+ include Base
33
+ define_method? [:foo, :bar] do
34
+ true
35
+ end
36
+ end
37
+
38
+ expect(klass.new.foo_bar).to be_true
39
+ end
40
+
41
+ it 'ignores blank chunks' do
42
+ klass = Class.new do
43
+ include Base
44
+ define_method? ["", :bar] do
45
+ true
46
+ end
47
+ end
48
+
49
+ expect(klass.new.bar).to be_true
50
+ end
51
+ end
52
+
53
+ end
54
+ end
55
+ end
56
+
@@ -0,0 +1,123 @@
1
+ require 'spec_helper'
2
+
3
+ module Showcase::Traits
4
+ describe LinkTo do
5
+
6
+ let(:view) { RailsViewContext.new }
7
+ let(:record) { Model.new }
8
+ subject { presenter.new(record, view) }
9
+
10
+ let(:active) { false }
11
+ before do
12
+ record.stub(:active).and_return(active)
13
+ end
14
+
15
+ let(:presenter) {
16
+ Class.new(Showcase::Presenter) do
17
+ include LinkTo
18
+
19
+ link_to do |c|
20
+ c.url = url
21
+ c.label = 'Label'
22
+ c.active = active
23
+ c.html_options role: 'label'
24
+ end
25
+
26
+ link_to :foo do |c|
27
+ c.url = '#foo'
28
+ c.active_class = 'current'
29
+ c.active = active
30
+ end
31
+
32
+ def url
33
+ '#bar'
34
+ end
35
+ end
36
+ }
37
+
38
+ describe '#link_to' do
39
+
40
+ context 'defines a link method' do
41
+ it 'pointing to the specified url' do
42
+ expect(subject.link).to have_tag(:a, with: { href: '#bar' })
43
+ end
44
+
45
+ it 'with the specified label' do
46
+ expect(subject.link).to have_tag(:a, text: 'Label')
47
+ end
48
+
49
+ it 'with the specified html attributes' do
50
+ expect(subject.link).to have_tag(:a, with: { role: 'label' })
51
+ end
52
+
53
+ context 'with a different label as parameter' do
54
+ it 'uses it' do
55
+ expect(subject.link('Foo')).to have_tag(:a, text: 'Foo')
56
+ end
57
+ end
58
+
59
+ context 'with additional options' do
60
+ it 'uses them as html options' do
61
+ end
62
+ end
63
+
64
+ context 'with a block' do
65
+ it 'uses it instead of the label' do
66
+ result = subject.link { 'Foo' }
67
+ expect(result).to have_tag(:a, text: 'Foo')
68
+ end
69
+ end
70
+
71
+ context 'if active' do
72
+ let(:active) { true }
73
+
74
+ it 'adds an active class to the link' do
75
+ expect(subject.link('label')).to have_tag(:a, with: { class: 'active' })
76
+ end
77
+
78
+ context 'with additional classes' do
79
+ it 'it sums them' do
80
+ expect(subject.link('label', class: 'extra')).to have_tag(:a, with: { class: 'extra active' })
81
+ end
82
+ end
83
+
84
+ context 'if a different CSS class was specified' do
85
+ it 'adds it to the link' do
86
+ expect(subject.foo_link('label')).to have_tag(:a, with: { class: 'current' })
87
+ end
88
+ end
89
+ end
90
+ end
91
+
92
+ context 'defines an link_active? method' do
93
+ let(:active) { double }
94
+
95
+ it 'returns the active flag' do
96
+ expect(subject.link_active?).to eq active
97
+ end
98
+ end
99
+
100
+ context 'defines an url method' do
101
+ it 'returns the url' do
102
+ expect(subject.url).to eq '#bar'
103
+ end
104
+ end
105
+
106
+ context 'with prefix' do
107
+ it 'prefixes link method' do
108
+ expect(subject).to respond_to :foo_link
109
+ end
110
+
111
+ it 'prefixes link_active? method' do
112
+ expect(subject).to respond_to :foo_link_active?
113
+ end
114
+
115
+ it 'prefixes url method' do
116
+ expect(subject).to respond_to :foo_url
117
+ end
118
+ end
119
+ end
120
+
121
+ end
122
+ end
123
+
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ module Showcase::Traits
4
+ describe Record do
5
+
6
+ let(:view) { RailsViewContext.new }
7
+ let(:record) { Model.new }
8
+ let(:presenter) {
9
+ Class.new(Showcase::Presenter) do
10
+ include Record
11
+
12
+ box do |c|
13
+ c.html_options role: 'actor', class: 'first'
14
+ end
15
+ end
16
+ }
17
+ subject { presenter.new(record, view) }
18
+
19
+ describe '#dom_id' do
20
+ it 'returns a CSS ID for the model' do
21
+ expect(subject.dom_id).to eq 'model_1'
22
+ end
23
+ end
24
+
25
+ describe '#dom_class' do
26
+ it 'returns a CSS class for model' do
27
+ expect(subject.dom_class).to eq 'model'
28
+ end
29
+ end
30
+
31
+ describe '#box' do
32
+ it 'wraps content inside an element that uniquely identifies the record' do
33
+ result = subject.box { "foo" }
34
+ expect(result).to have_tag(:div, with: { class: 'model', id: 'model_1' })
35
+ end
36
+
37
+ it 'adds attributes specified within box block' do
38
+ result = subject.box { "foo" }
39
+ expect(result).to have_tag(:div, with: { role: 'actor', class: 'first' })
40
+ end
41
+
42
+ context 'with a specified tag' do
43
+ it 'uses it' do
44
+ result = subject.box(:span) { "foo" }
45
+ expect(result).to have_tag(:span)
46
+ end
47
+ end
48
+
49
+ context 'with some class' do
50
+ it 'uses it' do
51
+ result = subject.box(class: 'bar') { "foo" }
52
+ expect(result).to have_tag(:div, with: { class: 'model bar'})
53
+ end
54
+ end
55
+ end
56
+
57
+ end
58
+ end
59
+
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ module Showcase::Traits
4
+ describe Seo do
5
+
6
+ let(:view) { RailsViewContext.new }
7
+ let(:record) { Model.new }
8
+ let(:builder) { double('SeoMetaBuilder') }
9
+ subject { presenter.new(record, view) }
10
+
11
+ let(:presenter) {
12
+ Class.new(Showcase::Presenter) do
13
+ include Seo
14
+
15
+ seo do |c|
16
+ c.title = 'foo'
17
+ c.description 'bar'
18
+ end
19
+ end
20
+ }
21
+
22
+ describe '#seo' do
23
+ let(:options) { double('options') }
24
+ before do
25
+ Showcase::Helpers::SeoMetaBuilder.stub(:new).with(view).and_return(builder)
26
+ builder.stub(:title).with('foo', options).and_return('<title>')
27
+ builder.stub(:description).with('bar', options).and_return('<description>')
28
+ end
29
+
30
+ it 'defines a seo_tags method that ouputs seo meta tags' do
31
+ expect(subject.seo_tags(options)).to eq '<title><description>'
32
+ end
33
+ end
34
+
35
+ end
36
+ end
37
+
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+
3
+ module Showcase::Traits
4
+ describe Share do
5
+
6
+ let(:view) { RailsViewContext.new }
7
+ let(:record) { Model.new }
8
+ subject { presenter.new(record, view) }
9
+
10
+ let(:presenter) {
11
+ Class.new(Showcase::Presenter) do
12
+ include Share
13
+
14
+ share do |c|
15
+ c.url = 'url'
16
+ c.text = 'text'
17
+ c.image_url = 'image'
18
+ end
19
+
20
+ share :foo do |c|
21
+ c.url = 'url'
22
+ c.text = 'text'
23
+ c.image_url = 'image'
24
+ end
25
+
26
+ end
27
+ }
28
+
29
+ describe '#social_share' do
30
+ expected_urls = {
31
+ twitter: "https://twitter.com/intent/tweet?text=text&url=url",
32
+ facebook: "http://www.facebook.com/sharer/sharer.php?u=url",
33
+ gplus: "https://plus.google.com/share?url=url",
34
+ pinterest: "http://www.pinterest.com/pin/create/button/?media=image&title=text&url=url",
35
+ linkedin: "http://www.linkedin.com/shareArticle?title=text&url=url",
36
+ }
37
+
38
+ expected_urls.each do |provider, url|
39
+ it "produces a #{provider} share link" do
40
+ expect(subject.send("#{provider}_share_link")).to have_tag(:a)
41
+ end
42
+ it "produces a #{provider} share url" do
43
+ expect(subject.send("#{provider}_share_url")).to eq url
44
+ end
45
+
46
+ context 'with prefix' do
47
+ it 'prefixes link method' do
48
+ expect(subject).to respond_to "foo_#{provider}_share_link"
49
+ end
50
+
51
+ it 'prefixes link_active? method' do
52
+ expect(subject).to respond_to "foo_#{provider}_share_url"
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ end
59
+ end
60
+