middleman-dato 0.0.1.rc2 → 0.0.1.rc3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2662bb3c2b38f4f37124b6ea9eb18de9db52b121
4
- data.tar.gz: f798ff90cad69d1eb951dc3d95d345d9bc9b30a7
3
+ metadata.gz: 9e9b62c5c0b856590c2086fc8eb5f7c881fdee83
4
+ data.tar.gz: ada1e157192adfb35b34f62ddbfa89828c5afad0
5
5
  SHA512:
6
- metadata.gz: 935e93b6a99c6c7a244b7f48184f3af845f8252d04cf696d8a94c00971fbd8e1a5c906ead27407ca39e0fedc2a4ed91a6888e22d1f046e734d02de9bdbf41895
7
- data.tar.gz: 88393186cced3a657979a04fefafb21a482791dbfb4a5f060935f8c10d7286b9d43d7af4f45006729e79bb9617a2d511436da953e8cac65f00587d945cd5dedb
6
+ metadata.gz: a6929b598351b0a444326ccba3e879215f4594378559e17674f5ae691348f1d4db32d29b7a49ffa7d9595b8db20b1f781831c61be389066686b2398bfa132904
7
+ data.tar.gz: 25b452a1e01c2034d6d8c046f906baf42605ae598d41d26f806b011b2c8705433a55b2d607cf550bb595b51176cd809a76b90b4915173932e67ca300efbbbd61
data/Gemfile CHANGED
@@ -12,8 +12,5 @@ group :development do
12
12
  end
13
13
 
14
14
  group :test do
15
- gem 'cucumber'
16
- gem 'fivemat'
17
- gem 'aruba'
18
15
  gem 'rspec'
19
16
  end
@@ -0,0 +1,20 @@
1
+ require 'dato/meta_tags/og_meta_tag'
2
+ require 'time'
3
+
4
+ module Dato
5
+ module MetaTags
6
+ class ArticleModifiedTime < OgMetaTag
7
+ def buildable?
8
+ record && !record.singleton?
9
+ end
10
+
11
+ def name
12
+ "article:modified_time"
13
+ end
14
+
15
+ def value
16
+ record.updated_at.iso8601
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,21 @@
1
+ require 'dato/meta_tags/og_meta_tag'
2
+ require 'time'
3
+
4
+ module Dato
5
+ module MetaTags
6
+ class ArticlePublisher < OgMetaTag
7
+ def buildable?
8
+ record && !record.singleton? &&
9
+ global_seo_field(:facebook_page_url).present?
10
+ end
11
+
12
+ def name
13
+ "article:publisher"
14
+ end
15
+
16
+ def value
17
+ global_seo_field(:facebook_page_url)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,80 @@
1
+ require 'forwardable'
2
+ require 'dato/seo'
3
+
4
+ module Dato
5
+ module MetaTags
6
+ class Base
7
+ attr_reader :builder, :base_url, :space, :content_type, :record
8
+
9
+ def initialize(builder, base_url, space, record)
10
+ @space = space
11
+ @base_url = base_url
12
+ @record = record
13
+ @builder = builder
14
+ end
15
+
16
+ def seo_field_with_fallback(attribute, alternative = nil, &block)
17
+ seo = first_record_field_of_type(:seo)
18
+
19
+ alternatives = []
20
+
21
+ alternatives << seo.send(attribute) if seo
22
+ alternatives << alternative if alternative
23
+ alternatives << fallback_seo.send(attribute) if fallback_seo
24
+
25
+ alternatives = alternatives.select(&:present?)
26
+ alternatives = alternatives.select(&block) if block
27
+
28
+ alternatives.first
29
+ end
30
+
31
+ def title_suffix
32
+ global_seo_field(:title_suffix)
33
+ end
34
+
35
+ def no_index?
36
+ space && space[:attributes][:no_index]
37
+ end
38
+
39
+ def global_seo_field(attribute)
40
+ if global_seo
41
+ global_seo[attribute]
42
+ end
43
+ end
44
+
45
+ def first_record_field_of_type(type)
46
+ return nil unless record
47
+
48
+ field = record.fields.find do |name, field|
49
+ field[:field_type] == type.to_s
50
+ end
51
+
52
+ if field
53
+ field_name = field.first
54
+ record.send(field_name)
55
+ end
56
+ end
57
+
58
+ def fallback_seo
59
+ @fallback_seo ||= begin
60
+ if global_seo
61
+ Seo.new(global_seo[:fallback_seo])
62
+ end
63
+ end
64
+ end
65
+
66
+ def global_seo
67
+ @global_seo ||= begin
68
+ if space && space[:attributes][:global_seo]
69
+ global_seo = space[:attributes][:global_seo]
70
+ if space[:attributes][:locales].size > 1
71
+ global_seo[I18n.locale]
72
+ else
73
+ global_seo
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,24 @@
1
+ require 'dato/meta_tags/base'
2
+
3
+ module Dato
4
+ module MetaTags
5
+ class Description < Base
6
+
7
+ def build
8
+ if description.present?
9
+ [
10
+ builder.tag(:meta, name: "description", content: description),
11
+ builder.tag(:meta, property: "og:description", content: description),
12
+ builder.tag(:meta, name: "twitter:description", content: description)
13
+ ]
14
+ end
15
+ end
16
+
17
+ def description
18
+ @description ||= seo_field_with_fallback(:description)
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+
@@ -0,0 +1,33 @@
1
+ require 'dato/meta_tags/base'
2
+
3
+ module Dato
4
+ module MetaTags
5
+ class Image < Base
6
+
7
+ def build
8
+ if image.present?
9
+ [
10
+ builder.tag(:meta, property: "og:image", content: image),
11
+ builder.tag(:meta, name: "twitter:image", content: image)
12
+ ]
13
+ end
14
+ end
15
+
16
+ def image
17
+ image = seo_field_with_fallback(
18
+ :image,
19
+ first_record_field_of_type(:image)
20
+ ) do |image|
21
+ image.attributes[:width] >= 200 &&
22
+ image.attributes[:height] >= 200
23
+ end
24
+
25
+ if image
26
+ image.file.format("jpg").to_url
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+
@@ -0,0 +1,20 @@
1
+ require 'dato/meta_tags/og_meta_tag'
2
+
3
+ module Dato
4
+ module MetaTags
5
+ class OgLocale < OgMetaTag
6
+ def buildable?
7
+ true
8
+ end
9
+
10
+ def name
11
+ "og:locale"
12
+ end
13
+
14
+ def value
15
+ locale = I18n.locale
16
+ "#{locale}_#{locale.upcase}"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,25 @@
1
+ require 'dato/meta_tags/base'
2
+
3
+ module Dato
4
+ module MetaTags
5
+ class OgMetaTag < Base
6
+ def buildable?
7
+ false
8
+ end
9
+
10
+ def build
11
+ if buildable?
12
+ builder.tag(:meta, property: name, content: value)
13
+ end
14
+ end
15
+
16
+ def name
17
+ raise NotImplementedError
18
+ end
19
+
20
+ def value
21
+ raise NotImplementedError
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ require 'dato/meta_tags/og_meta_tag'
2
+
3
+ module Dato
4
+ module MetaTags
5
+ class OgSiteName < OgMetaTag
6
+ def buildable?
7
+ global_seo_field(:site_name).present?
8
+ end
9
+
10
+ def name
11
+ "og:site_name"
12
+ end
13
+
14
+ def value
15
+ global_seo_field(:site_name)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,25 @@
1
+ require 'dato/meta_tags/og_meta_tag'
2
+
3
+ module Dato
4
+ module MetaTags
5
+ class OgType < OgMetaTag
6
+ def buildable?
7
+ true
8
+ end
9
+
10
+ def name
11
+ "og:type"
12
+ end
13
+
14
+ def value
15
+ if !record
16
+ "website"
17
+ elsif record.singleton?
18
+ "website"
19
+ else
20
+ "article"
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,16 @@
1
+ require 'dato/meta_tags/base'
2
+
3
+ module Dato
4
+ module MetaTags
5
+ class Robots < Base
6
+ def build
7
+ if no_index?
8
+ builder.tag(:meta, name: "robots", content: "noindex")
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
14
+
15
+
16
+
@@ -0,0 +1,37 @@
1
+ require 'dato/meta_tags/base'
2
+
3
+ module Dato
4
+ module MetaTags
5
+ class Title < Base
6
+
7
+ def build
8
+ if title.present?
9
+ [
10
+ builder.content_tag(:title, title_with_suffix),
11
+ builder.tag(:meta, property: "og:title", content: title),
12
+ builder.tag(:meta, name: "twitter:title", content: title)
13
+ ]
14
+ end
15
+ end
16
+
17
+ def title
18
+ @title ||= seo_field_with_fallback(
19
+ :title,
20
+ first_record_field_of_type(:title)
21
+ )
22
+ end
23
+
24
+ def title_with_suffix
25
+ title_plus_suffix = title + title_suffix
26
+
27
+ if title_plus_suffix.size <= 60
28
+ title_plus_suffix
29
+ else
30
+ title
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+
@@ -0,0 +1,19 @@
1
+ require 'dato/meta_tags/twitter_meta_tag'
2
+
3
+ module Dato
4
+ module MetaTags
5
+ class TwitterCard < TwitterMetaTag
6
+ def buildable?
7
+ true
8
+ end
9
+
10
+ def name
11
+ "twitter:card"
12
+ end
13
+
14
+ def value
15
+ "summary"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,26 @@
1
+ require 'dato/meta_tags/base'
2
+
3
+ module Dato
4
+ module MetaTags
5
+ class TwitterMetaTag < Base
6
+ def buildable?
7
+ false
8
+ end
9
+
10
+ def build
11
+ if buildable?
12
+ builder.tag(:meta, name: name, content: value)
13
+ end
14
+ end
15
+
16
+ def name
17
+ raise NotImplementedError
18
+ end
19
+
20
+ def value
21
+ raise NotImplementedError
22
+ end
23
+ end
24
+ end
25
+ end
26
+
@@ -0,0 +1,19 @@
1
+ require 'dato/meta_tags/twitter_meta_tag'
2
+
3
+ module Dato
4
+ module MetaTags
5
+ class TwitterSite < TwitterMetaTag
6
+ def buildable?
7
+ global_seo_field(:twitter_account).present?
8
+ end
9
+
10
+ def name
11
+ "twitter:site"
12
+ end
13
+
14
+ def value
15
+ global_seo_field(:twitter_account)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,24 @@
1
+ require 'dato/meta_tags/base'
2
+
3
+ module Dato
4
+ module MetaTags
5
+ class Url < Base
6
+
7
+ def build
8
+ if url.present?
9
+ [
10
+ builder.tag(:link, rel: "canonical", href: url),
11
+ builder.tag(:meta, property: "og:url", content: url),
12
+ builder.tag(:meta, name: "twitter:url", content: url)
13
+ ]
14
+ end
15
+ end
16
+
17
+ def url
18
+ base_url + builder.current_page.url
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+
@@ -0,0 +1,41 @@
1
+ require 'dato/meta_tags/title'
2
+ require 'dato/meta_tags/description'
3
+ require 'dato/meta_tags/image'
4
+ require 'dato/meta_tags/url'
5
+ require 'dato/meta_tags/robots'
6
+ require 'dato/meta_tags/og_locale'
7
+ require 'dato/meta_tags/og_type'
8
+ require 'dato/meta_tags/og_site_name'
9
+ require 'dato/meta_tags/article_modified_time'
10
+ require 'dato/meta_tags/article_publisher'
11
+ require 'dato/meta_tags/twitter_card'
12
+ require 'dato/meta_tags/twitter_site'
13
+
14
+ module Dato
15
+ class MetaTagsBuilder
16
+ META_TAGS = [
17
+ MetaTags::Title,
18
+ MetaTags::Description,
19
+ MetaTags::Image,
20
+ MetaTags::Url,
21
+ MetaTags::Robots,
22
+ MetaTags::OgLocale,
23
+ MetaTags::OgType,
24
+ MetaTags::OgSiteName,
25
+ MetaTags::ArticleModifiedTime,
26
+ MetaTags::ArticlePublisher,
27
+ MetaTags::TwitterCard,
28
+ MetaTags::TwitterSite
29
+ ]
30
+
31
+ def initialize(*args)
32
+ @args = args
33
+ end
34
+
35
+ def meta_tags
36
+ META_TAGS.map do |klass|
37
+ klass.new(*@args).build
38
+ end.flatten.compact.join("\n")
39
+ end
40
+ end
41
+ end
@@ -1,5 +1,6 @@
1
1
  require 'middleman-core'
2
2
  require 'dato/repo'
3
+ require 'dato/meta_tags_builder'
3
4
  require 'ostruct'
4
5
 
5
6
  module Dato
@@ -7,6 +8,7 @@ module Dato
7
8
  option :domain, nil, 'Space domain'
8
9
  option :token, nil, 'Space API token'
9
10
  option :api_host, 'http://dato-api.herokuapp.com', 'Space API token'
11
+ option :base_url, nil, 'Website base URL'
10
12
 
11
13
  attr_reader :records
12
14
 
@@ -38,6 +40,21 @@ module Dato
38
40
  def dato
39
41
  OpenStruct.new(Repo.instance.records_per_content_type)
40
42
  end
43
+
44
+ def dato_meta_tags(record)
45
+ begin
46
+ builder = MetaTagsBuilder.new(
47
+ self,
48
+ Repo.instance.connection_options[:base_url],
49
+ Repo.instance.space,
50
+ record
51
+ )
52
+ builder.meta_tags
53
+ rescue Exception => e
54
+ puts e.message
55
+ puts e.backtrace.join("\n")
56
+ end
57
+ end
41
58
  end
42
59
  end
43
60
  end
data/lib/dato/record.rb CHANGED
@@ -1,15 +1,21 @@
1
1
  require "dato/file"
2
+ require "dato/seo"
3
+ require "time"
2
4
 
3
5
  module Dato
4
6
  class Record
5
- attr_reader :attributes, :fields, :singleton
7
+ attr_reader :attributes, :fields, :content_type
6
8
 
7
9
  def initialize(attributes, content_type)
8
10
  @attributes = attributes.with_indifferent_access
9
- @singleton = content_type[:singleton]
11
+ @content_type = content_type
10
12
  @fields = content_type[:fields].with_indifferent_access
11
13
  end
12
14
 
15
+ def singleton?
16
+ @singleton = content_type[:singleton]
17
+ end
18
+
13
19
  def respond_to?(method, include_private = false)
14
20
  if @attributes.has_key?(method)
15
21
  true
@@ -27,10 +33,14 @@ module Dato
27
33
  attribute
28
34
  end
29
35
 
36
+ return nil if !attribute
37
+
30
38
  if %w(image file).include? fields[name][:field_type]
31
39
  Dato::File.new(attribute)
32
40
  elsif fields[name][:field_type] == "date"
33
41
  Date.parse(attribute)
42
+ elsif fields[name][:field_type] == "seo"
43
+ Dato::Seo.new(attribute)
34
44
  else
35
45
  attribute
36
46
  end
@@ -40,6 +50,10 @@ module Dato
40
50
  @attributes[:id]
41
51
  end
42
52
 
53
+ def updated_at
54
+ Time.parse(@attributes[:updated_at])
55
+ end
56
+
43
57
  def method_missing(method, *arguments, &block)
44
58
  if @attributes.has_key?(method) && arguments.size == 0
45
59
  read_attribute(method.to_sym)
data/lib/dato/repo.rb CHANGED
@@ -7,9 +7,11 @@ module Dato
7
7
  class Repo
8
8
  include Singleton
9
9
 
10
- attr_reader :client, :content_types, :records_per_content_type
10
+ attr_reader :client, :space, :content_types, :records_per_content_type,
11
+ :connection_options
11
12
 
12
13
  def connection_options=(options)
14
+ @connection_options = options
13
15
  @client = Client.new(
14
16
  options[:api_host],
15
17
  options[:domain],
@@ -18,7 +20,9 @@ module Dato
18
20
  end
19
21
 
20
22
  def sync!
21
- @content_types = prepare_content_types(client.space)
23
+ space_response = client.space.with_indifferent_access
24
+ @space = space_response[:data]
25
+ @content_types = prepare_content_types(space_response)
22
26
  @records_per_content_type = group_by_content_type(client.records)
23
27
  end
24
28
 
data/lib/dato/seo.rb ADDED
@@ -0,0 +1,31 @@
1
+ require "imgix"
2
+
3
+ module Dato
4
+ class Seo
5
+ attr_reader :attributes
6
+
7
+ def initialize(data)
8
+ @attributes = data.with_indifferent_access
9
+ end
10
+
11
+ def image
12
+ @attributes[:image] && File.new(@attributes[:image])
13
+ end
14
+
15
+ def respond_to?(method, include_private = false)
16
+ if @attributes.has_key?(method)
17
+ true
18
+ else
19
+ super
20
+ end
21
+ end
22
+
23
+ def method_missing(method, *arguments, &block)
24
+ if @attributes.has_key?(method) && arguments.size == 0
25
+ @attributes[method.to_sym]
26
+ else
27
+ super
28
+ end
29
+ end
30
+ end
31
+ end
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "middleman-dato"
6
- s.version = "0.0.1.rc2"
6
+ s.version = "0.0.1.rc3"
7
7
  s.platform = Gem::Platform::RUBY
8
8
  s.authors = ["Stefano Verna"]
9
9
  s.email = ["s.verna@cantierecreativo.net"]
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ module Dato::MetaTags
4
+ RSpec.describe ArticleModifiedTime do
5
+ subject(:meta_tag) { described_class.new(builder, space, record) }
6
+ let(:builder) { MockBuilder.new }
7
+ let(:space) { nil }
8
+ let(:record) do
9
+ double("Record", updated_at: Time.now, singleton?: false)
10
+ end
11
+
12
+ describe '.value' do
13
+ context 'if record is not singleton' do
14
+ it 'returns an ISO 8601 time representation' do
15
+ expect(meta_tag.value).not_to be_nil
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ module Dato::MetaTags
4
+ RSpec.describe OgLocale do
5
+ subject(:meta_tag) { described_class.new(builder, space, record) }
6
+ let(:builder) { MockBuilder.new }
7
+ let(:space) { nil }
8
+ let(:record) { nil }
9
+
10
+ describe '.value' do
11
+ it "returns the current locale" do
12
+ I18n.with_locale(:it) do
13
+ expect(meta_tag.value).to eq "it_IT"
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,31 @@
1
+ require 'active_support/dependencies'
2
+
3
+ require 'i18n'
4
+
5
+ I18n.available_locales = [:it, :en]
6
+
7
+ ActiveSupport::Dependencies.autoload_paths.unshift(
8
+ File.join(__dir__, "../lib")
9
+ )
10
+
11
+ Dir["spec/support/**/*.rb"].each do |f|
12
+ require_relative "../" + f
13
+ end
14
+
15
+ RSpec.configure do |config|
16
+ config.expect_with :rspec do |expectations|
17
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
18
+ end
19
+
20
+ config.mock_with :rspec do |mocks|
21
+ mocks.verify_partial_doubles = true
22
+ end
23
+
24
+ config.filter_run :focus
25
+ config.run_all_when_everything_filtered = true
26
+ config.disable_monkey_patching!
27
+
28
+ config.order = :random
29
+
30
+ Kernel.srand config.seed
31
+ end
@@ -0,0 +1,5 @@
1
+ class MockBuilder
2
+ def tag(*args)
3
+ args
4
+ end
5
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: middleman-dato
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.rc2
4
+ version: 0.0.1.rc3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stefano Verna
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-25 00:00:00.000000000 Z
11
+ date: 2015-05-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: middleman-core
@@ -78,12 +78,33 @@ files:
78
78
  - Rakefile
79
79
  - lib/dato/client.rb
80
80
  - lib/dato/file.rb
81
+ - lib/dato/meta_tags/article_modified_time.rb
82
+ - lib/dato/meta_tags/article_publisher.rb
83
+ - lib/dato/meta_tags/base.rb
84
+ - lib/dato/meta_tags/description.rb
85
+ - lib/dato/meta_tags/image.rb
86
+ - lib/dato/meta_tags/og_locale.rb
87
+ - lib/dato/meta_tags/og_meta_tag.rb
88
+ - lib/dato/meta_tags/og_site_name.rb
89
+ - lib/dato/meta_tags/og_type.rb
90
+ - lib/dato/meta_tags/robots.rb
91
+ - lib/dato/meta_tags/title.rb
92
+ - lib/dato/meta_tags/twitter_card.rb
93
+ - lib/dato/meta_tags/twitter_meta_tag.rb
94
+ - lib/dato/meta_tags/twitter_site.rb
95
+ - lib/dato/meta_tags/url.rb
96
+ - lib/dato/meta_tags_builder.rb
81
97
  - lib/dato/middleman_extension.rb
82
98
  - lib/dato/record.rb
83
99
  - lib/dato/repo.rb
100
+ - lib/dato/seo.rb
84
101
  - lib/middleman-dato.rb
85
102
  - lib/middleman_extension.rb
86
103
  - middleman-dato.gemspec
104
+ - spec/dato/meta_tags/article_modified_time_spec.rb
105
+ - spec/dato/meta_tags/og_locale_spec.rb
106
+ - spec/spec_helper.rb
107
+ - spec/support/mock_builder.rb
87
108
  homepage: http://cantierecreativo.net
88
109
  licenses: []
89
110
  metadata: {}
@@ -107,5 +128,9 @@ rubygems_version: 2.2.2
107
128
  signing_key:
108
129
  specification_version: 4
109
130
  summary: Fetches data from a Dato space
110
- test_files: []
131
+ test_files:
132
+ - spec/dato/meta_tags/article_modified_time_spec.rb
133
+ - spec/dato/meta_tags/og_locale_spec.rb
134
+ - spec/spec_helper.rb
135
+ - spec/support/mock_builder.rb
111
136
  has_rdoc: