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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 72574756357dcfeea3882c9cc85310c932bc272d
4
- data.tar.gz: 98f5d60b67e5dba3f0d870ae033b9dacc6ffad28
3
+ metadata.gz: 987858bde075b1173d6c229fd861b25c165ca851
4
+ data.tar.gz: daf57836d8e3159f20d2b2034368eb49d9e28c5d
5
5
  SHA512:
6
- metadata.gz: 7b49b695ea0301b22c47239c144ceaf4ccfa7a22c6ec1ab809f7660581792c196953060183064a7a9e2d61a230d2fbd7ceccc3ce9ce2289e617f6457e39d1b86
7
- data.tar.gz: dcfd53204bc986fc2389707a130afe5d7395b110f34d30b63cd562375f12140a7f03474f07c2d88a987304da6bc9fac29d81875eec3dcc8e45c25ba624886a2a
6
+ metadata.gz: 1893aeaf728470b953c32d835cfbff594a835d97f9af45c63cd80ed0d1afa16f867daab34a6c2051552c0c8c19580e75ffcd12f5727b031b622242fccfd39272
7
+ data.tar.gz: 0a673a3d06105364974135115fe9b3c99de98d9945ce8b3c7a74bee4d2180bb03b03c4cd43fc7235601eacbd48f1d4be7cc6f6c5da661742e3e06de985f54d47
data/.gitignore CHANGED
@@ -15,3 +15,5 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
+ gemfiles/*.gemfile.lock
19
+
data/.travis.yml CHANGED
@@ -1,6 +1,12 @@
1
1
  language: ruby
2
+
2
3
  rvm:
3
4
  - "1.9.3"
4
5
  - "2.0.0"
5
- script: "bundle exec rspec spec"
6
+
7
+ gemfile:
8
+ - "gemfiles/rails_32.gemfile"
9
+ - "gemfiles/rails_4.gemfile"
10
+
11
+ script: "bundle exec rake spec"
6
12
 
data/Appraisals ADDED
@@ -0,0 +1,8 @@
1
+ appraise "rails-32" do
2
+ gem "rails", "3.2.14"
3
+ end
4
+
5
+ appraise "rails-4" do
6
+ gem "rails", "4.0.0"
7
+ end
8
+
data/Gemfile CHANGED
@@ -2,3 +2,6 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in basic_presenter.gemspec
4
4
  gemspec
5
+
6
+ gem "appraisal"
7
+
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 the Exhibit pattern in my Rails app?
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
- gem 'showcase'
18
+ ```ruby
19
+ gem 'showcase'
20
+ ```
19
21
 
20
22
  And then execute:
21
23
 
22
- $ bundle
24
+ ```
25
+ $ bundle
26
+ ```
23
27
 
24
28
  Or install it yourself as:
25
29
 
26
- $ gem install showcase
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 make the Presenter creation process a little
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 a file called
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
- form `BasePresenter` instead of `Shocase::Presenter`.
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 h.project_path(self)
153
- c.label name
154
- c.active h.controller_name == 'projects'
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 URL):
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 "bundler/gem_tasks"
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,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "appraisal"
6
+ gem "rails", "3.2.14"
7
+
8
+ gemspec :path=>"../"
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "appraisal"
6
+ gem "rails", "4.0.0"
7
+
8
+ gemspec :path=>"../"
@@ -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(:og_title, :twitter_title, values)
15
+ seo_meta_tags('og:title', 'twitter:title', values)
16
16
  end
17
17
 
18
18
  def description(values, options = {})
19
- seo_meta_tags(:description, :og_description, :twitter_description, values)
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(:og_image, :twitter_image, image_url)
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(:og_url, url) <<
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).map(&:presence).compact.first
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
- name = name.to_s.sub(/_/, ":")
44
- context.tag(:meta, name: name, content: value)
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
@@ -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
- methods_module = Module.new do
50
- args.each do |attr|
51
- define_method attr do
52
- send(method,
53
- object.send(attr),
54
- presenter_klass,
55
- view_context,
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
@@ -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
@@ -3,20 +3,9 @@ module Showcase
3
3
  module Base
4
4
  extend ActiveSupport::Concern
5
5
 
6
- module ClassMethods
7
- private
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
- define_method? [name, :link_active?] do
17
+ define_module_method [name, :link_active?] do
18
18
  Helpers::ConfigObject.new(self, &block).to_struct.active
19
19
  end
20
20
 
21
- define_method? [name, :link] do |*args, &link_block|
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
- if config.active
27
- options[:class] ||= ""
28
- css_classes = options[:class].split(/\s+/)
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, options, &link_block
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
- ActionView::RecordIdentifier.dom_id(self)
18
+ record_identifier.dom_id(self)
11
19
  end
12
20
 
13
21
  def dom_class
14
- ActiveModel::Naming.param_key(self)
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
- options[:class] ||= ""
24
- css_classes = options[:class].split(/\s+/) << dom_class
25
- options[:class] = css_classes.join(" ")
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
- options[:id] = dom_id
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, options) do
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
@@ -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
- define_method? [name, :seo_tags] do |options = {}|
14
- meta = Helpers::ConfigObject.new(self, &block).to_hash
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(title description canonical_url image_url canonical_url).map(&:to_sym)
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], options) if 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
- [ param, meta.send(meta_key) ]
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 = { target: :blank }
55
+ c.html_options = html_options.reverse_merge(target: '_blank')
52
56
  end
53
57
  end
54
58
  end
@@ -1,4 +1,4 @@
1
1
  module Showcase
2
- VERSION = "0.2.0.pre"
2
+ VERSION = "0.2.0.rc.1"
3
3
  end
4
4
 
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@welaika.com']
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
@@ -87,7 +87,7 @@ class NilClassPresenter < Showcase::Presenter
87
87
  end
88
88
 
89
89
  class Context
90
- include Showcase::Helpers
90
+ include Showcase::Helpers::Present
91
91
 
92
92
  def bold(text)
93
93
  "**#{text}**"
@@ -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 ug:title meta tag' do
17
- expect(subject.title('foo')).to have_tag(:meta, with: { name: 'og:title', content: 'foo' })
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: { name: 'og:title', content: 'foo' })
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: { name: 'og:description', content: 'foo' })
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: { name: 'og:image', content: 'foo' })
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: { name: 'og:image', content: 'foo' })
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: { name: 'og:url', content: 'foo' })
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: { name: 'og:url', content: 'foo' })
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
 
@@ -2,12 +2,12 @@ require 'spec_helper'
2
2
 
3
3
  module Showcase::Traits
4
4
  describe Base do
5
- describe '.define_method?' do
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
- define_method? :foo do
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
- define_method? [:foo, :bar] do
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
- define_method? ["", :bar] do
60
+ define_module_method ["", :bar] do
45
61
  true
46
62
  end
47
63
  end
@@ -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
@@ -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" }
@@ -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 '#seo' do
23
- let(:options) { double('options') }
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('foo', options).and_return('<title>')
27
- builder.stub(:description).with('bar', options).and_return('<description>')
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(options)).to eq '<title><description>'
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
 
@@ -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.pre
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-09-21 00:00:00.000000000 Z
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@welaika.com
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
@@ -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
-