showcase 0.2.0.pre → 0.2.0.rc.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.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.travis.yml +7 -1
- data/Appraisals +8 -0
- data/Gemfile +3 -0
- data/README.md +40 -20
- data/Rakefile +14 -1
- data/gemfiles/rails_32.gemfile +8 -0
- data/gemfiles/rails_4.gemfile +8 -0
- data/lib/showcase/helpers/html_options.rb +22 -0
- data/lib/showcase/helpers/module_method_builder.rb +19 -0
- data/lib/showcase/helpers/present.rb +35 -0
- data/lib/showcase/helpers/seo_meta_builder.rb +38 -7
- data/lib/showcase/presenter.rb +12 -13
- data/lib/showcase/railtie.rb +1 -1
- data/lib/showcase/traits/base.rb +2 -13
- data/lib/showcase/traits/link_to.rb +8 -14
- data/lib/showcase/traits/record.rb +35 -11
- data/lib/showcase/traits/seo.rb +18 -4
- data/lib/showcase/traits/share.rb +6 -2
- data/lib/showcase/version.rb +1 -1
- data/showcase.gemspec +1 -1
- data/spec/fixtures.rb +1 -1
- data/spec/helpers/seo_meta_builder_spec.rb +59 -8
- data/spec/traits/base_spec.rb +20 -4
- data/spec/traits/link_to_spec.rb +16 -3
- data/spec/traits/record_spec.rb +9 -0
- data/spec/traits/seo_spec.rb +20 -5
- data/spec/traits/share_spec.rb +12 -1
- metadata +9 -4
- data/lib/showcase/helpers.rb +0 -33
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 987858bde075b1173d6c229fd861b25c165ca851
|
4
|
+
data.tar.gz: daf57836d8e3159f20d2b2034368eb49d9e28c5d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1893aeaf728470b953c32d835cfbff594a835d97f9af45c63cd80ed0d1afa16f867daab34a6c2051552c0c8c19580e75ffcd12f5727b031b622242fccfd39272
|
7
|
+
data.tar.gz: 0a673a3d06105364974135115fe9b3c99de98d9945ce8b3c7a74bee4d2180bb03b03c4cd43fc7235601eacbd48f1d4be7cc6f6c5da661742e3e06de985f54d47
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/Appraisals
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -3,36 +3,42 @@
|
|
3
3
|
A simple (< 100 lines of code) but powerful exhibit/presenter implementation.
|
4
4
|
It's framework agnostic: works with Rails, Padrino or just Sinatra.
|
5
5
|
|
6
|
-
Since version 0.2.0 Showcase is bundled with [a set of "traits"](https://github.com/stefanoverna/showcase#traits)
|
6
|
+
Since version 0.2.0 Showcase is bundled with [a set of optional "traits"](https://github.com/stefanoverna/showcase#traits)
|
7
7
|
you can pick and choose to augment your presenters with additional sugar
|
8
|
-
(available in Rails only).
|
8
|
+
(available in Rails 3+ only).
|
9
9
|
|
10
|
-
## Why should I use
|
10
|
+
## Why should I use presenters in my Rails app?
|
11
11
|
|
12
|
-
See [Avdi's introductory post](http://devblog.avdi.org/2012/06/04/displaycase-gem-now-available/).
|
12
|
+
See [Avdi's Exhibits introductory post](http://devblog.avdi.org/2012/06/04/displaycase-gem-now-available/).
|
13
13
|
|
14
14
|
## Installation
|
15
15
|
|
16
16
|
Add this line to your application's Gemfile:
|
17
17
|
|
18
|
-
|
18
|
+
```ruby
|
19
|
+
gem 'showcase'
|
20
|
+
```
|
19
21
|
|
20
22
|
And then execute:
|
21
23
|
|
22
|
-
|
24
|
+
```
|
25
|
+
$ bundle
|
26
|
+
```
|
23
27
|
|
24
28
|
Or install it yourself as:
|
25
29
|
|
26
|
-
|
30
|
+
```
|
31
|
+
$ gem install showcase
|
32
|
+
```
|
27
33
|
|
28
34
|
## Usage
|
29
35
|
|
30
|
-
With Rails, you're already set, move on! With Padrino, include `Showcase::Helpers`
|
36
|
+
With Rails, you're already set, move on! With Padrino, include `Showcase::Helpers::Present`
|
31
37
|
in your app `helpers` block.
|
32
38
|
|
33
39
|
```ruby
|
34
40
|
helpers do
|
35
|
-
include Showcase::Helpers
|
41
|
+
include Showcase::Helpers::Present
|
36
42
|
end
|
37
43
|
```
|
38
44
|
|
@@ -82,16 +88,15 @@ end
|
|
82
88
|
|
83
89
|
### Generators
|
84
90
|
|
85
|
-
Showcase comes with a generator to
|
86
|
-
faster:
|
91
|
+
Showcase comes with a generator to create new presenters a little faster:
|
87
92
|
|
88
93
|
```
|
89
94
|
rails generate showcase:presenter User
|
90
95
|
```
|
91
96
|
|
92
|
-
Will generate `app/presenters/user_presenter.rb`. If your app has
|
97
|
+
Will generate `app/presenters/user_presenter.rb`. If your Rails app has the file
|
93
98
|
`app/presenters/base_presenter.rb`, the newly created presenter will inherit
|
94
|
-
|
99
|
+
from `BasePresenter` instead of `Showcase::Presenter`.
|
95
100
|
|
96
101
|
### Traits
|
97
102
|
|
@@ -127,7 +132,7 @@ Super useful in acceptance testing to check the presence of a record inside a
|
|
127
132
|
view:
|
128
133
|
|
129
134
|
```erb
|
130
|
-
<% present(@project).box do %>
|
135
|
+
<% present(@project, class: 'big').box do %>
|
131
136
|
<p>Hi there!</p>
|
132
137
|
<% end %>
|
133
138
|
```
|
@@ -135,11 +140,24 @@ view:
|
|
135
140
|
Produces the following:
|
136
141
|
|
137
142
|
```html
|
138
|
-
<div class="project" id="project_12">
|
143
|
+
<div class="project big" id="project_12">
|
139
144
|
<p>Hi there</p>
|
140
145
|
</div>
|
141
146
|
```
|
142
147
|
|
148
|
+
Additional HTML attributes can be optionally specified within a config block
|
149
|
+
inside the presenter:
|
150
|
+
|
151
|
+
```ruby
|
152
|
+
class ProjectPresenter < Showcase::Presenter
|
153
|
+
include Showcase::Traits::Record
|
154
|
+
|
155
|
+
box do |c|
|
156
|
+
c.html_options class: 'another-class', role: 'project'
|
157
|
+
end
|
158
|
+
end
|
159
|
+
```
|
160
|
+
|
143
161
|
#### `Showcase::Traits::LinkTo`
|
144
162
|
|
145
163
|
Adds a nice DSL to declare links within your presenter.
|
@@ -149,15 +167,16 @@ class ProjectPresenter < Showcase::Presenter
|
|
149
167
|
include Showcase::Traits::LinkTo
|
150
168
|
|
151
169
|
link_to do |c|
|
152
|
-
c.url
|
153
|
-
c.label
|
154
|
-
c.active
|
170
|
+
c.url h.project_path(self)
|
171
|
+
c.label name
|
172
|
+
c.active h.controller_name == 'projects'
|
173
|
+
c.active_class 'current'
|
174
|
+
c.html_options role: 'label'
|
155
175
|
end
|
156
176
|
|
157
177
|
link_to :tasks do
|
158
178
|
c.url h.project_tasks_path(self)
|
159
179
|
c.label "Tasks"
|
160
|
-
c.active h.controller_name == 'tasks'
|
161
180
|
end
|
162
181
|
end
|
163
182
|
```
|
@@ -216,7 +235,7 @@ In your views:
|
|
216
235
|
#### `Showcase::Traits::Seo`
|
217
236
|
|
218
237
|
Useful to produce SEO meta tags (title, description, Facebook OpenGraph,
|
219
|
-
Twitter cards, and canonical
|
238
|
+
Twitter cards, and canonical URLs):
|
220
239
|
|
221
240
|
```ruby
|
222
241
|
class ProjectPresenter < Showcase::Presenter
|
@@ -230,6 +249,7 @@ class ProjectPresenter < Showcase::Presenter
|
|
230
249
|
end
|
231
250
|
end
|
232
251
|
```
|
252
|
+
|
233
253
|
In your views:
|
234
254
|
|
235
255
|
```erb
|
data/Rakefile
CHANGED
@@ -1 +1,14 @@
|
|
1
|
-
require
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'appraisal'
|
4
|
+
|
5
|
+
desc 'Default: run specs'
|
6
|
+
task default: :spec
|
7
|
+
|
8
|
+
require 'rspec/core/rake_task'
|
9
|
+
RSpec::Core::RakeTask.new do |t|
|
10
|
+
t.pattern = "spec/**/*_spec.rb"
|
11
|
+
end
|
12
|
+
|
13
|
+
Bundler::GemHelper.install_tasks
|
14
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class HtmlOptions
|
2
|
+
def initialize(options = {})
|
3
|
+
@options = (options || {}).symbolize_keys
|
4
|
+
end
|
5
|
+
|
6
|
+
def add_class!(css_class)
|
7
|
+
@options[:class] ||= ""
|
8
|
+
css_classes = @options[:class].split(/\s+/)
|
9
|
+
css_classes << css_class
|
10
|
+
@options[:class] = css_classes.join(" ")
|
11
|
+
end
|
12
|
+
|
13
|
+
def merge_attrs!(options = {})
|
14
|
+
options = (options || {}).symbolize_keys
|
15
|
+
@options.merge!(options)
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_h
|
19
|
+
@options.dup
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Showcase
|
2
|
+
module Helpers
|
3
|
+
module ModuleMethodBuilder
|
4
|
+
def define_module_method(name_chunks, &block)
|
5
|
+
method_name = Array(name_chunks).map(&:to_s).map(&:presence).compact.join("_")
|
6
|
+
if method_defined?(method_name)
|
7
|
+
false
|
8
|
+
else
|
9
|
+
method_module = Module.new do
|
10
|
+
define_method(method_name, &block)
|
11
|
+
end
|
12
|
+
include(method_module)
|
13
|
+
true
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
require 'active_support/inflector'
|
3
|
+
require 'active_support/core_ext/hash/keys'
|
4
|
+
|
5
|
+
module Showcase
|
6
|
+
module Helpers
|
7
|
+
module Present
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
def presenter_context
|
11
|
+
if respond_to? :view_context
|
12
|
+
view_context
|
13
|
+
else
|
14
|
+
self
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def present(obj, klass = nil, context = presenter_context, options = {})
|
19
|
+
options.assert_valid_keys(:nil_presenter)
|
20
|
+
|
21
|
+
if obj || options.fetch(:nil_presenter, false)
|
22
|
+
klass ||= "#{obj.class.name}Presenter".constantize
|
23
|
+
klass.new(obj, context)
|
24
|
+
else
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def present_collection(obj, klass = nil, context = presenter_context, options = {})
|
30
|
+
obj.map { |o| present(o, klass, context, options) }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
@@ -12,26 +12,51 @@ module Showcase
|
|
12
12
|
title += options[:title_suffix] if options[:title_suffix]
|
13
13
|
|
14
14
|
context.content_tag(:title, title) <<
|
15
|
-
seo_meta_tags(:
|
15
|
+
seo_meta_tags('og:title', 'twitter:title', values)
|
16
16
|
end
|
17
17
|
|
18
18
|
def description(values, options = {})
|
19
|
-
seo_meta_tags(
|
19
|
+
seo_meta_tags('description', 'og:description', 'twitter:description', values)
|
20
20
|
end
|
21
21
|
|
22
22
|
def image_url(image_url, options = {})
|
23
|
-
seo_meta_tags(:
|
23
|
+
seo_meta_tags('og:image', 'twitter:image', image_url)
|
24
|
+
end
|
25
|
+
|
26
|
+
def iframe_video_url(video_url, options = {})
|
27
|
+
seo_meta_tags('og:video:url', video_url) <<
|
28
|
+
seo_meta_tags('og:video:type', 'text/html') <<
|
29
|
+
seo_meta_tags('twitter:player', video_url)
|
30
|
+
end
|
31
|
+
|
32
|
+
def stream_video_url(video_url, options = {})
|
33
|
+
seo_meta_tags('og:video:url', video_url) <<
|
34
|
+
seo_meta_tags('og:video:type', 'video/mp4') <<
|
35
|
+
seo_meta_tags('twitter:player:stream', video_url)
|
36
|
+
end
|
37
|
+
|
38
|
+
def card_type(type, options = {})
|
39
|
+
seo_meta_tags('twitter:card', type)
|
40
|
+
end
|
41
|
+
|
42
|
+
def video_size(size, options = {})
|
43
|
+
seo_meta_tags('twitter:player:width', size.first) <<
|
44
|
+
seo_meta_tags('twitter:player:height', size.last)
|
45
|
+
end
|
46
|
+
|
47
|
+
def site_name(name, options = {})
|
48
|
+
seo_meta_tags('og:site_name', name)
|
24
49
|
end
|
25
50
|
|
26
51
|
def canonical_url(url, options = {})
|
27
|
-
seo_meta_tags(:
|
52
|
+
seo_meta_tags('og:url', 'twitter:url', url) <<
|
28
53
|
context.tag(:link, rel: "canonical", "href" => url)
|
29
54
|
end
|
30
55
|
|
31
56
|
private
|
32
57
|
|
33
58
|
def first_nonblank(values)
|
34
|
-
Array(values).
|
59
|
+
Array(values).find(&:presence)
|
35
60
|
end
|
36
61
|
|
37
62
|
def seo_meta_tags(*args)
|
@@ -40,8 +65,14 @@ module Showcase
|
|
40
65
|
return nil unless value.present?
|
41
66
|
|
42
67
|
args.map do |name|
|
43
|
-
|
44
|
-
|
68
|
+
chunks = name.to_s.split(":")
|
69
|
+
attr_name = if chunks.first == 'og'
|
70
|
+
'property'
|
71
|
+
else
|
72
|
+
'name'
|
73
|
+
end
|
74
|
+
name = chunks.join(':')
|
75
|
+
context.tag(:meta, attr_name => name, content: value)
|
45
76
|
end.join.html_safe
|
46
77
|
end
|
47
78
|
end
|
data/lib/showcase/presenter.rb
CHANGED
@@ -1,17 +1,20 @@
|
|
1
1
|
require 'delegate'
|
2
|
-
require 'showcase/helpers'
|
2
|
+
require 'showcase/helpers/present'
|
3
|
+
require 'showcase/helpers/module_method_builder'
|
3
4
|
require 'active_support/core_ext/array/extract_options'
|
4
5
|
require 'active_support/core_ext/hash/keys'
|
5
6
|
|
6
7
|
module Showcase
|
7
8
|
class Presenter < SimpleDelegator
|
8
|
-
include Helpers
|
9
|
+
include Helpers::Present
|
10
|
+
extend Helpers::ModuleMethodBuilder
|
9
11
|
|
10
12
|
attr_reader :view_context
|
11
13
|
|
12
14
|
alias_method :object, :__getobj__
|
13
15
|
alias_method :h, :view_context
|
14
16
|
alias_method :try, :__send__
|
17
|
+
alias_method :__decorator_class__, :class
|
15
18
|
|
16
19
|
def initialize(obj, context)
|
17
20
|
super(obj)
|
@@ -46,19 +49,15 @@ module Showcase
|
|
46
49
|
options.assert_valid_keys(:with, :nil_presenter)
|
47
50
|
presenter_klass = options.fetch(:with, nil)
|
48
51
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
options.slice(:nil_presenter))
|
57
|
-
end
|
52
|
+
args.each do |attr|
|
53
|
+
define_module_method attr do
|
54
|
+
send(method,
|
55
|
+
object.send(attr),
|
56
|
+
presenter_klass,
|
57
|
+
view_context,
|
58
|
+
options.slice(:nil_presenter))
|
58
59
|
end
|
59
60
|
end
|
60
|
-
|
61
|
-
include(methods_module)
|
62
61
|
end
|
63
62
|
end
|
64
63
|
end
|
data/lib/showcase/railtie.rb
CHANGED
@@ -4,7 +4,7 @@ module Showcase
|
|
4
4
|
class Railtie < Rails::Railtie
|
5
5
|
initializer "action_view.initialize_showcase" do
|
6
6
|
ActiveSupport.on_load(:action_view) do
|
7
|
-
ActionView::Base.send :include, Showcase::Helpers
|
7
|
+
ActionView::Base.send :include, Showcase::Helpers::Present
|
8
8
|
end
|
9
9
|
end
|
10
10
|
end
|
data/lib/showcase/traits/base.rb
CHANGED
@@ -3,20 +3,9 @@ module Showcase
|
|
3
3
|
module Base
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
def define_method?(name_chunks, &block)
|
10
|
-
method_name = Array(name_chunks).map(&:to_s).map(&:presence).compact.join("_")
|
11
|
-
if method_defined?(method_name)
|
12
|
-
false
|
13
|
-
else
|
14
|
-
define_method(method_name, &block)
|
15
|
-
true
|
16
|
-
end
|
17
|
-
end
|
6
|
+
included do
|
7
|
+
extend Helpers::ModuleMethodBuilder
|
18
8
|
end
|
19
|
-
|
20
9
|
end
|
21
10
|
end
|
22
11
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'showcase/helpers/config_object'
|
2
|
+
require 'showcase/helpers/html_options'
|
2
3
|
|
3
4
|
module Showcase
|
4
5
|
module Traits
|
@@ -9,31 +10,24 @@ module Showcase
|
|
9
10
|
|
10
11
|
module ClassMethods
|
11
12
|
def link_to(name = nil, &block)
|
12
|
-
|
13
|
-
define_method? [name, :url] do
|
13
|
+
define_module_method [name, :url] do
|
14
14
|
Helpers::ConfigObject.new(self, &block).to_struct.url
|
15
15
|
end
|
16
16
|
|
17
|
-
|
17
|
+
define_module_method [name, :link_active?] do
|
18
18
|
Helpers::ConfigObject.new(self, &block).to_struct.active
|
19
19
|
end
|
20
20
|
|
21
|
-
|
21
|
+
define_module_method [name, :link] do |*args, &link_block|
|
22
22
|
config = Helpers::ConfigObject.new(self, &block).to_struct
|
23
|
-
options = args.extract_options!.symbolize_keys
|
24
|
-
options.reverse_merge!(config.html_options) if config.html_options
|
25
23
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
css_classes << "active"
|
30
|
-
options[:class] = css_classes.join(" ")
|
31
|
-
end
|
24
|
+
html_options = HtmlOptions.new(config.html_options)
|
25
|
+
html_options.merge_attrs!(args.extract_options!)
|
26
|
+
html_options.add_class!(config.active_class || 'active') if config.active
|
32
27
|
|
33
28
|
args = Array(config.label) if args.empty? && !link_block
|
34
|
-
h.link_to *args, config.url,
|
29
|
+
h.link_to *args, config.url, html_options.to_h, &link_block
|
35
30
|
end
|
36
|
-
|
37
31
|
end
|
38
32
|
end
|
39
33
|
end
|
@@ -1,35 +1,59 @@
|
|
1
|
-
require 'action_view/record_identifier'
|
2
|
-
|
3
1
|
module Showcase
|
4
2
|
module Traits
|
5
3
|
|
6
4
|
module Record
|
7
5
|
extend ActiveSupport::Concern
|
8
6
|
|
7
|
+
module ClassMethods
|
8
|
+
def box(&block)
|
9
|
+
@box_config_block = block
|
10
|
+
end
|
11
|
+
|
12
|
+
def __box_config_block__
|
13
|
+
@box_config_block
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
9
17
|
def dom_id
|
10
|
-
|
18
|
+
record_identifier.dom_id(self)
|
11
19
|
end
|
12
20
|
|
13
21
|
def dom_class
|
14
|
-
|
22
|
+
record_identifier.dom_class(self)
|
15
23
|
end
|
16
24
|
|
17
25
|
def box(*args, &block)
|
18
26
|
options = args.extract_options!
|
19
|
-
options.symbolize_keys!
|
20
|
-
|
21
27
|
tag = args.pop || :div
|
22
28
|
|
23
|
-
|
24
|
-
|
25
|
-
|
29
|
+
config_block = self.__decorator_class__.__box_config_block__
|
30
|
+
config_options = if config_block
|
31
|
+
Helpers::ConfigObject.new(self, &config_block).to_struct.html_options
|
32
|
+
else
|
33
|
+
{}
|
34
|
+
end
|
26
35
|
|
27
|
-
|
36
|
+
html_options = HtmlOptions.new(config_options)
|
37
|
+
html_options.merge_attrs!(options)
|
38
|
+
html_options.add_class!(dom_class)
|
39
|
+
html_options.merge_attrs!(id: dom_id)
|
28
40
|
|
29
|
-
h.content_tag(tag,
|
41
|
+
h.content_tag(tag, html_options.to_h) do
|
30
42
|
h.capture(self, &block)
|
31
43
|
end
|
32
44
|
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def record_identifier
|
49
|
+
if defined?(ActionView::RecordIdentifier)
|
50
|
+
ActionView::RecordIdentifier
|
51
|
+
elsif defined?(ActionController::RecordIdentifier)
|
52
|
+
ActionController::RecordIdentifier
|
53
|
+
else
|
54
|
+
raise 'No RecordIdentifier found!'
|
55
|
+
end
|
56
|
+
end
|
33
57
|
end
|
34
58
|
|
35
59
|
end
|
data/lib/showcase/traits/seo.rb
CHANGED
@@ -9,13 +9,27 @@ module Showcase
|
|
9
9
|
|
10
10
|
module ClassMethods
|
11
11
|
|
12
|
+
def default_seo_options(&block)
|
13
|
+
define_module_method :default_seo_options do
|
14
|
+
Helpers::ConfigObject.new(self, &block).to_hash
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
12
18
|
def seo(name = nil, options = {}, &block)
|
13
|
-
|
14
|
-
meta =
|
19
|
+
define_module_method [name, :seo_tags] do |options = {}|
|
20
|
+
meta = respond_to?(:default_seo_options) ? default_seo_options : {}
|
21
|
+
meta.merge!(Helpers::ConfigObject.new(self, &block).to_hash)
|
22
|
+
meta.merge!(options.symbolize_keys) if options
|
23
|
+
|
15
24
|
builder = Helpers::SeoMetaBuilder.new(view_context)
|
16
|
-
parts = %w(
|
25
|
+
parts = %w(
|
26
|
+
title description site_name
|
27
|
+
canonical_url
|
28
|
+
image_url iframe_video_url stream_video_url
|
29
|
+
).map(&:to_sym)
|
30
|
+
|
17
31
|
parts.map do |tag|
|
18
|
-
builder.send(tag, meta[tag],
|
32
|
+
builder.send(tag, meta[tag], meta.except(*parts)) if meta[tag]
|
19
33
|
end.compact.join.html_safe
|
20
34
|
end
|
21
35
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'showcase/helpers/config_object'
|
2
|
+
require 'active_support/core_ext/object/to_query'
|
2
3
|
|
3
4
|
module Showcase
|
4
5
|
module Traits
|
@@ -41,14 +42,17 @@ module Showcase
|
|
41
42
|
|
42
43
|
link_to link_name do |c|
|
43
44
|
meta = Helpers::ConfigObject.new(self, &block).to_struct
|
45
|
+
html_options = meta.html_options || {}
|
44
46
|
params = Hash[
|
45
47
|
settings[:params].map do |param, meta_key|
|
46
|
-
[
|
48
|
+
values = [:"#{social}_#{meta_key}", meta_key].map { |key| meta.send(key) }
|
49
|
+
[ param, values.find(&:presence) ]
|
47
50
|
end
|
48
51
|
]
|
52
|
+
|
49
53
|
c.url "#{settings[:url]}?#{params.to_query}"
|
50
54
|
c.label settings[:label]
|
51
|
-
c.html_options =
|
55
|
+
c.html_options = html_options.reverse_merge(target: '_blank')
|
52
56
|
end
|
53
57
|
end
|
54
58
|
end
|
data/lib/showcase/version.rb
CHANGED
data/showcase.gemspec
CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |gem|
|
|
7
7
|
gem.name = 'showcase'
|
8
8
|
gem.version = Showcase::VERSION
|
9
9
|
gem.authors = ['Stefano Verna']
|
10
|
-
gem.email = ['stefano.verna@
|
10
|
+
gem.email = ['stefano.verna@gmail.com']
|
11
11
|
gem.description = %q{A barebone and framework agnostic presenter implementation}
|
12
12
|
gem.summary = %q{A barebone and framework agnostic presenter implementation}
|
13
13
|
gem.homepage = 'https://github.com/welaika/showcase'
|
data/spec/fixtures.rb
CHANGED
@@ -13,8 +13,8 @@ module Showcase::Helpers
|
|
13
13
|
expect(subject.title('foo')).to have_tag(:title, text: 'foo')
|
14
14
|
end
|
15
15
|
|
16
|
-
it 'produces a
|
17
|
-
expect(subject.title('foo')).to have_tag(:meta, with: {
|
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
18
|
end
|
19
19
|
|
20
20
|
it 'produces a twitter:title meta tag' do
|
@@ -32,7 +32,7 @@ module Showcase::Helpers
|
|
32
32
|
expect(subject.title('foo', title_suffix: ' - bar')).to have_tag(:title, text: 'foo - bar')
|
33
33
|
end
|
34
34
|
it 'does not suffix meta tags' do
|
35
|
-
expect(subject.title('foo')).to have_tag(:meta, with: {
|
35
|
+
expect(subject.title('foo')).to have_tag(:meta, with: { property: 'og:title', content: 'foo' })
|
36
36
|
expect(subject.title('foo')).to have_tag(:meta, with: { name: 'twitter:title', content: 'foo' })
|
37
37
|
end
|
38
38
|
end
|
@@ -44,7 +44,7 @@ module Showcase::Helpers
|
|
44
44
|
end
|
45
45
|
|
46
46
|
it 'produces a og:description meta tag' do
|
47
|
-
expect(subject.description('foo')).to have_tag(:meta, with: {
|
47
|
+
expect(subject.description('foo')).to have_tag(:meta, with: { property: 'og:description', content: 'foo' })
|
48
48
|
end
|
49
49
|
|
50
50
|
it 'produces a twitter:description meta tag' do
|
@@ -60,7 +60,7 @@ module Showcase::Helpers
|
|
60
60
|
|
61
61
|
describe '#image_url' do
|
62
62
|
it 'produces a og:image meta tag' do
|
63
|
-
expect(subject.image_url('foo')).to have_tag(:meta, with: {
|
63
|
+
expect(subject.image_url('foo')).to have_tag(:meta, with: { property: 'og:image', content: 'foo' })
|
64
64
|
end
|
65
65
|
|
66
66
|
it 'produces a twitter:image meta tag' do
|
@@ -69,14 +69,18 @@ module Showcase::Helpers
|
|
69
69
|
|
70
70
|
context 'with multiple values' do
|
71
71
|
it 'uses the first non-blank' do
|
72
|
-
expect(subject.image_url(['', nil, 'foo'])).to have_tag(:meta, with: {
|
72
|
+
expect(subject.image_url(['', nil, 'foo'])).to have_tag(:meta, with: { property: 'og:image', content: 'foo' })
|
73
73
|
end
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
77
|
describe '#canonical_url' do
|
78
78
|
it 'produces a og:url meta tag' do
|
79
|
-
expect(subject.canonical_url('foo')).to have_tag(:meta, with: {
|
79
|
+
expect(subject.canonical_url('foo')).to have_tag(:meta, with: { property: 'og:url', content: 'foo' })
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'produces a twitter:url meta tag' do
|
83
|
+
expect(subject.canonical_url('foo')).to have_tag(:meta, with: { name: 'twitter:url', content: 'foo' })
|
80
84
|
end
|
81
85
|
|
82
86
|
it 'produces a canonical link tag' do
|
@@ -85,11 +89,58 @@ module Showcase::Helpers
|
|
85
89
|
|
86
90
|
context 'with multiple values' do
|
87
91
|
it 'uses the first non-blank' do
|
88
|
-
expect(subject.canonical_url(['', nil, 'foo'])).to have_tag(:meta, with: {
|
92
|
+
expect(subject.canonical_url(['', nil, 'foo'])).to have_tag(:meta, with: { property: 'og:url', content: 'foo' })
|
89
93
|
end
|
90
94
|
end
|
91
95
|
end
|
92
96
|
|
97
|
+
describe '#iframe_video_url' do
|
98
|
+
it 'produces a og:video:url meta tag' do
|
99
|
+
expect(subject.iframe_video_url('foo')).to have_tag(:meta, with: { property: 'og:video:url', content: 'foo' })
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'produces a twitter:player meta tag' do
|
103
|
+
expect(subject.iframe_video_url('foo')).to have_tag(:meta, with: { name: 'twitter:player', content: 'foo' })
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'produces a og:video:type meta tag' do
|
107
|
+
expect(subject.iframe_video_url('foo')).to have_tag(:meta, with: { property: 'og:video:type', content: 'text/html' })
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe '#stream_video_url' do
|
112
|
+
it 'produces a og:video:url meta tag' do
|
113
|
+
expect(subject.stream_video_url('foo')).to have_tag(:meta, with: { property: 'og:video:url', content: 'foo' })
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'produces a twitter:player:stream meta tag' do
|
117
|
+
expect(subject.stream_video_url('foo')).to have_tag(:meta, with: { name: 'twitter:player:stream', content: 'foo' })
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'produces a og:video:type meta tag' do
|
121
|
+
expect(subject.stream_video_url('foo')).to have_tag(:meta, with: { property: 'og:video:type', content: 'video/mp4' })
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe '#site_name' do
|
126
|
+
it 'produces a og:site_name meta tag' do
|
127
|
+
expect(subject.site_name('foo')).to have_tag(:meta, with: { property: 'og:site_name', content: 'foo' })
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe '#card_type' do
|
132
|
+
it 'produces a twitter:card meta tag' do
|
133
|
+
expect(subject.card_type('foo')).to have_tag(:meta, with: { name: 'twitter:card', content: 'foo' })
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe '#video_size' do
|
138
|
+
it 'produces twitter:player meta tags' do
|
139
|
+
result = subject.video_size([10, 20])
|
140
|
+
expect(result).to have_tag(:meta, with: { name: 'twitter:player:width', content: '10' })
|
141
|
+
expect(result).to have_tag(:meta, with: { name: 'twitter:player:height', content: '20' })
|
142
|
+
end
|
143
|
+
end
|
93
144
|
end
|
94
145
|
end
|
95
146
|
|
data/spec/traits/base_spec.rb
CHANGED
@@ -2,12 +2,12 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
module Showcase::Traits
|
4
4
|
describe Base do
|
5
|
-
describe '.
|
5
|
+
describe '.define_module_method' do
|
6
6
|
|
7
7
|
it 'defines an instance method' do
|
8
8
|
klass = Class.new do
|
9
9
|
include Base
|
10
|
-
|
10
|
+
define_module_method :foo do
|
11
11
|
true
|
12
12
|
end
|
13
13
|
end
|
@@ -15,6 +15,22 @@ module Showcase::Traits
|
|
15
15
|
expect(klass.new.foo).to be_true
|
16
16
|
end
|
17
17
|
|
18
|
+
it 'overriding the method allows to call super' do
|
19
|
+
klass = Class.new do
|
20
|
+
include Base
|
21
|
+
|
22
|
+
define_module_method :foo do
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
def foo
|
27
|
+
super
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
expect(klass.new.foo).to be_true
|
32
|
+
end
|
33
|
+
|
18
34
|
context 'if the method is already present' do
|
19
35
|
it 'no-ops ' do
|
20
36
|
klass = Class.new do
|
@@ -30,7 +46,7 @@ module Showcase::Traits
|
|
30
46
|
it 'joins them in snake case' do
|
31
47
|
klass = Class.new do
|
32
48
|
include Base
|
33
|
-
|
49
|
+
define_module_method [:foo, :bar] do
|
34
50
|
true
|
35
51
|
end
|
36
52
|
end
|
@@ -41,7 +57,7 @@ module Showcase::Traits
|
|
41
57
|
it 'ignores blank chunks' do
|
42
58
|
klass = Class.new do
|
43
59
|
include Base
|
44
|
-
|
60
|
+
define_module_method ["", :bar] do
|
45
61
|
true
|
46
62
|
end
|
47
63
|
end
|
data/spec/traits/link_to_spec.rb
CHANGED
@@ -20,10 +20,13 @@ module Showcase::Traits
|
|
20
20
|
c.url = url
|
21
21
|
c.label = 'Label'
|
22
22
|
c.active = active
|
23
|
+
c.html_options role: 'label'
|
23
24
|
end
|
24
25
|
|
25
|
-
link_to :foo do
|
26
|
+
link_to :foo do |c|
|
26
27
|
c.url = '#foo'
|
28
|
+
c.active_class = 'current'
|
29
|
+
c.active = active
|
27
30
|
end
|
28
31
|
|
29
32
|
def url
|
@@ -43,6 +46,10 @@ module Showcase::Traits
|
|
43
46
|
expect(subject.link).to have_tag(:a, text: 'Label')
|
44
47
|
end
|
45
48
|
|
49
|
+
it 'with the specified html attributes' do
|
50
|
+
expect(subject.link).to have_tag(:a, with: { role: 'label' })
|
51
|
+
end
|
52
|
+
|
46
53
|
context 'with a different label as parameter' do
|
47
54
|
it 'uses it' do
|
48
55
|
expect(subject.link('Foo')).to have_tag(:a, text: 'Foo')
|
@@ -65,12 +72,18 @@ module Showcase::Traits
|
|
65
72
|
let(:active) { true }
|
66
73
|
|
67
74
|
it 'adds an active class to the link' do
|
68
|
-
expect(subject.link).to have_tag(:a, with: { class: 'active' })
|
75
|
+
expect(subject.link('label')).to have_tag(:a, with: { class: 'active' })
|
69
76
|
end
|
70
77
|
|
71
78
|
context 'with additional classes' do
|
72
79
|
it 'it sums them' do
|
73
|
-
expect(subject.link(class: 'extra')).to have_tag(:a, with: { class: 'extra active' })
|
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' })
|
74
87
|
end
|
75
88
|
end
|
76
89
|
end
|
data/spec/traits/record_spec.rb
CHANGED
@@ -8,6 +8,10 @@ module Showcase::Traits
|
|
8
8
|
let(:presenter) {
|
9
9
|
Class.new(Showcase::Presenter) do
|
10
10
|
include Record
|
11
|
+
|
12
|
+
box do |c|
|
13
|
+
c.html_options role: 'actor', class: 'first'
|
14
|
+
end
|
11
15
|
end
|
12
16
|
}
|
13
17
|
subject { presenter.new(record, view) }
|
@@ -30,6 +34,11 @@ module Showcase::Traits
|
|
30
34
|
expect(result).to have_tag(:div, with: { class: 'model', id: 'model_1' })
|
31
35
|
end
|
32
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
|
+
|
33
42
|
context 'with a specified tag' do
|
34
43
|
it 'uses it' do
|
35
44
|
result = subject.box(:span) { "foo" }
|
data/spec/traits/seo_spec.rb
CHANGED
@@ -12,6 +12,10 @@ module Showcase::Traits
|
|
12
12
|
Class.new(Showcase::Presenter) do
|
13
13
|
include Seo
|
14
14
|
|
15
|
+
default_seo_options do |c|
|
16
|
+
c.title_suffix = ' - qux'
|
17
|
+
end
|
18
|
+
|
15
19
|
seo do |c|
|
16
20
|
c.title = 'foo'
|
17
21
|
c.description 'bar'
|
@@ -19,16 +23,27 @@ module Showcase::Traits
|
|
19
23
|
end
|
20
24
|
}
|
21
25
|
|
22
|
-
describe '
|
23
|
-
let(:
|
26
|
+
describe '.seo' do
|
27
|
+
let(:expected_options) { { title_suffix: ' - qux' } }
|
28
|
+
let(:expected_description) { 'bar' }
|
29
|
+
let(:expected_title) { 'foo' }
|
30
|
+
|
24
31
|
before do
|
25
32
|
Showcase::Helpers::SeoMetaBuilder.stub(:new).with(view).and_return(builder)
|
26
|
-
builder.stub(:title).with(
|
27
|
-
builder.stub(:description).with(
|
33
|
+
builder.stub(:title).with(expected_title, expected_options).and_return('<title>')
|
34
|
+
builder.stub(:description).with(expected_description, expected_options).and_return('<description>')
|
28
35
|
end
|
29
36
|
|
30
37
|
it 'defines a seo_tags method that ouputs seo meta tags' do
|
31
|
-
expect(subject.seo_tags
|
38
|
+
expect(subject.seo_tags).to eq '<title><description>'
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '#seo_tags' do
|
42
|
+
let(:expected_title) { 'other' }
|
43
|
+
|
44
|
+
it 'allows to override options' do
|
45
|
+
expect(subject.seo_tags(title: 'other')).to eq '<title><description>'
|
46
|
+
end
|
32
47
|
end
|
33
48
|
end
|
34
49
|
|
data/spec/traits/share_spec.rb
CHANGED
@@ -14,7 +14,9 @@ module Showcase::Traits
|
|
14
14
|
share do |c|
|
15
15
|
c.url = 'url'
|
16
16
|
c.text = 'text'
|
17
|
+
c.twitter_text = 'twitter text'
|
17
18
|
c.image_url = 'image'
|
19
|
+
c.html_options = { role: 'share' }
|
18
20
|
end
|
19
21
|
|
20
22
|
share :foo do |c|
|
@@ -28,7 +30,7 @@ module Showcase::Traits
|
|
28
30
|
|
29
31
|
describe '#social_share' do
|
30
32
|
expected_urls = {
|
31
|
-
twitter: "https://twitter.com/intent/tweet?text=text&url=url",
|
33
|
+
twitter: "https://twitter.com/intent/tweet?text=twitter+text&url=url",
|
32
34
|
facebook: "http://www.facebook.com/sharer/sharer.php?u=url",
|
33
35
|
gplus: "https://plus.google.com/share?url=url",
|
34
36
|
pinterest: "http://www.pinterest.com/pin/create/button/?media=image&title=text&url=url",
|
@@ -39,10 +41,19 @@ module Showcase::Traits
|
|
39
41
|
it "produces a #{provider} share link" do
|
40
42
|
expect(subject.send("#{provider}_share_link")).to have_tag(:a)
|
41
43
|
end
|
44
|
+
|
42
45
|
it "produces a #{provider} share url" do
|
43
46
|
expect(subject.send("#{provider}_share_url")).to eq url
|
44
47
|
end
|
45
48
|
|
49
|
+
it "adds a target :blank to the link" do
|
50
|
+
expect(subject.send("#{provider}_share_link")).to have_tag(:a, with: { target: '_blank' })
|
51
|
+
end
|
52
|
+
|
53
|
+
it "merges additional html_options" do
|
54
|
+
expect(subject.send("#{provider}_share_link")).to have_tag(:a, with: { role: 'share' })
|
55
|
+
end
|
56
|
+
|
46
57
|
context 'with prefix' do
|
47
58
|
it 'prefixes link method' do
|
48
59
|
expect(subject).to respond_to "foo_#{provider}_share_link"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: showcase
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.0.
|
4
|
+
version: 0.2.0.rc.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stefano Verna
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-11-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -82,7 +82,7 @@ dependencies:
|
|
82
82
|
version: '0'
|
83
83
|
description: A barebone and framework agnostic presenter implementation
|
84
84
|
email:
|
85
|
-
- stefano.verna@
|
85
|
+
- stefano.verna@gmail.com
|
86
86
|
executables: []
|
87
87
|
extensions: []
|
88
88
|
extra_rdoc_files: []
|
@@ -90,16 +90,21 @@ files:
|
|
90
90
|
- .gitignore
|
91
91
|
- .rspec
|
92
92
|
- .travis.yml
|
93
|
+
- Appraisals
|
93
94
|
- Gemfile
|
94
95
|
- LICENSE.txt
|
95
96
|
- README.md
|
96
97
|
- Rakefile
|
98
|
+
- gemfiles/rails_32.gemfile
|
99
|
+
- gemfiles/rails_4.gemfile
|
97
100
|
- lib/generators/showcase/presenter/USAGE
|
98
101
|
- lib/generators/showcase/presenter/presenter_generator.rb
|
99
102
|
- lib/generators/showcase/presenter/templates/presenter.rb
|
100
103
|
- lib/showcase.rb
|
101
|
-
- lib/showcase/helpers.rb
|
102
104
|
- lib/showcase/helpers/config_object.rb
|
105
|
+
- lib/showcase/helpers/html_options.rb
|
106
|
+
- lib/showcase/helpers/module_method_builder.rb
|
107
|
+
- lib/showcase/helpers/present.rb
|
103
108
|
- lib/showcase/helpers/seo_meta_builder.rb
|
104
109
|
- lib/showcase/presenter.rb
|
105
110
|
- lib/showcase/railtie.rb
|
data/lib/showcase/helpers.rb
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
require 'active_support/concern'
|
2
|
-
require 'active_support/inflector'
|
3
|
-
require 'active_support/core_ext/hash/keys'
|
4
|
-
|
5
|
-
module Showcase
|
6
|
-
module Helpers
|
7
|
-
extend ActiveSupport::Concern
|
8
|
-
|
9
|
-
def presenter_context
|
10
|
-
if respond_to? :view_context
|
11
|
-
view_context
|
12
|
-
else
|
13
|
-
self
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def present(obj, klass = nil, context = presenter_context, options = {})
|
18
|
-
options.assert_valid_keys(:nil_presenter)
|
19
|
-
|
20
|
-
if obj || options.fetch(:nil_presenter, false)
|
21
|
-
klass ||= "#{obj.class.name}Presenter".constantize
|
22
|
-
klass.new(obj, context)
|
23
|
-
else
|
24
|
-
nil
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def present_collection(obj, klass = nil, context = presenter_context, options = {})
|
29
|
-
obj.map { |o| present(o, klass, context, options) }
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|