dato 0.7.18 → 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +42 -5
  3. data/.ruby-version +1 -1
  4. data/.travis.yml +2 -2
  5. data/Gemfile +1 -1
  6. data/Rakefile +2 -2
  7. data/TODO.md +28 -0
  8. data/bin/console +3 -3
  9. data/bin/rspec +6 -6
  10. data/dato.gemspec +1 -1
  11. data/exe/dato +3 -3
  12. data/lib/dato/account/client.rb +2 -2
  13. data/lib/dato/api_client.rb +37 -43
  14. data/lib/dato/api_error.rb +10 -13
  15. data/lib/dato/cli.rb +18 -18
  16. data/lib/dato/dump/dsl/add_to_data_file.rb +1 -1
  17. data/lib/dato/dump/dsl/create_data_file.rb +1 -1
  18. data/lib/dato/dump/dsl/create_post.rb +1 -1
  19. data/lib/dato/dump/dsl/directory.rb +4 -4
  20. data/lib/dato/dump/dsl/root.rb +7 -7
  21. data/lib/dato/dump/format/json.rb +1 -1
  22. data/lib/dato/dump/format/toml.rb +5 -6
  23. data/lib/dato/dump/format/yaml.rb +2 -3
  24. data/lib/dato/dump/format.rb +3 -3
  25. data/lib/dato/dump/operation/add_to_data_file.rb +4 -4
  26. data/lib/dato/dump/operation/create_data_file.rb +3 -3
  27. data/lib/dato/dump/operation/create_post.rb +5 -6
  28. data/lib/dato/dump/operation/directory.rb +1 -1
  29. data/lib/dato/dump/runner.rb +5 -5
  30. data/lib/dato/dump/ssg_detector.rb +18 -20
  31. data/lib/dato/json_api_deserializer.rb +15 -16
  32. data/lib/dato/json_api_serializer.rb +39 -28
  33. data/lib/dato/json_schema_relationships.rb +19 -23
  34. data/lib/dato/json_schema_type.rb +47 -0
  35. data/lib/dato/local/entities_repo.rb +3 -3
  36. data/lib/dato/local/field_type/color.rb +11 -7
  37. data/lib/dato/local/field_type/file.rb +18 -24
  38. data/lib/dato/local/field_type/gallery.rb +1 -1
  39. data/lib/dato/local/field_type/global_seo.rb +4 -7
  40. data/lib/dato/local/field_type/lat_lon.rb +1 -1
  41. data/lib/dato/local/field_type/seo.rb +1 -1
  42. data/lib/dato/local/field_type/structured_text.rb +63 -0
  43. data/lib/dato/local/field_type/theme.rb +2 -2
  44. data/lib/dato/local/field_type/upload_id.rb +5 -5
  45. data/lib/dato/local/field_type/video.rb +9 -15
  46. data/lib/dato/local/item.rb +11 -12
  47. data/lib/dato/local/items_repo.rb +11 -18
  48. data/lib/dato/local/json_api_entity.rb +4 -3
  49. data/lib/dato/local/loader.rb +30 -31
  50. data/lib/dato/local/site.rb +3 -4
  51. data/lib/dato/paginator.rb +4 -4
  52. data/lib/dato/repo.rb +23 -30
  53. data/lib/dato/site/client.rb +5 -5
  54. data/lib/dato/upload/create_upload_path.rb +7 -10
  55. data/lib/dato/upload/file.rb +3 -3
  56. data/lib/dato/upload/image.rb +1 -1
  57. data/lib/dato/utils/build_modular_block.rb +4 -4
  58. data/lib/dato/utils/favicon_tags_builder.rb +10 -10
  59. data/lib/dato/utils/locale_value.rb +1 -1
  60. data/lib/dato/utils/meta_tags/article_modified_time.rb +3 -3
  61. data/lib/dato/utils/meta_tags/article_publisher.rb +2 -2
  62. data/lib/dato/utils/meta_tags/base.rb +5 -6
  63. data/lib/dato/utils/meta_tags/description.rb +4 -4
  64. data/lib/dato/utils/meta_tags/image.rb +4 -5
  65. data/lib/dato/utils/meta_tags/og_locale.rb +2 -2
  66. data/lib/dato/utils/meta_tags/og_site_name.rb +2 -2
  67. data/lib/dato/utils/meta_tags/og_type.rb +3 -3
  68. data/lib/dato/utils/meta_tags/robots.rb +2 -2
  69. data/lib/dato/utils/meta_tags/title.rb +6 -6
  70. data/lib/dato/utils/meta_tags/twitter_card.rb +2 -2
  71. data/lib/dato/utils/meta_tags/twitter_site.rb +2 -2
  72. data/lib/dato/utils/seo_tags_builder.rb +12 -12
  73. data/lib/dato/version.rb +1 -1
  74. data/lib/dato.rb +11 -9
  75. metadata +10 -8
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'imgix'
3
+ require "imgix"
4
4
 
5
5
  module Dato
6
6
  module Local
@@ -10,7 +10,7 @@ module Dato
10
10
  if value
11
11
  v = value.with_indifferent_access
12
12
 
13
- upload = repo.entities_repo.find_entity('upload', v[:upload_id])
13
+ upload = repo.entities_repo.find_entity("upload", v[:upload_id])
14
14
 
15
15
  if upload
16
16
  new(
@@ -19,7 +19,7 @@ module Dato
19
19
  v[:title],
20
20
  v[:custom_data],
21
21
  v[:focal_point],
22
- repo.site.entity.imgix_host
22
+ repo.site.entity.imgix_host,
23
23
  )
24
24
  end
25
25
  end
@@ -88,25 +88,25 @@ module Dato
88
88
  def alt
89
89
  default_metadata = @upload.default_field_metadata.deep_stringify_keys
90
90
  .fetch(I18n.locale.to_s, {})
91
- @alt || default_metadata['alt']
91
+ @alt || default_metadata["alt"]
92
92
  end
93
93
 
94
94
  def title
95
95
  default_metadata = @upload.default_field_metadata.deep_stringify_keys
96
96
  .fetch(I18n.locale.to_s, {})
97
- @title || default_metadata['title']
97
+ @title || default_metadata["title"]
98
98
  end
99
99
 
100
100
  def custom_data
101
101
  default_metadata = @upload.default_field_metadata.deep_stringify_keys
102
102
  .fetch(I18n.locale.to_s, {})
103
- @custom_data.merge(default_metadata.fetch('custom_data', {}))
103
+ @custom_data.merge(default_metadata.fetch("custom_data", {}))
104
104
  end
105
105
 
106
106
  def focal_point
107
107
  default_metadata = @upload.default_field_metadata.deep_stringify_keys
108
108
  .fetch(I18n.locale.to_s, {})
109
- @focal_point || default_metadata['focal_point']
109
+ @focal_point || default_metadata["focal_point"]
110
110
  end
111
111
 
112
112
  def tags
@@ -174,9 +174,7 @@ module Dato
174
174
  if options[:exact_res] == :low
175
175
  raw_mp4_url("low")
176
176
  elsif options[:exact_res] == :medium
177
- if %w[medium high].include?(@upload.mux_mp4_highest_res)
178
- raw_mp4_url("medium")
179
- end
177
+ raw_mp4_url("medium") if %w[medium high].include?(@upload.mux_mp4_highest_res)
180
178
  elsif @upload.mux_mp4_highest_res == :high
181
179
  raw_mp4_url("high")
182
180
  end
@@ -212,16 +210,14 @@ module Dato
212
210
  end
213
211
 
214
212
  def video
215
- if @upload.mux_playback_id
216
- VideoAttributes.new(@upload)
217
- end
213
+ VideoAttributes.new(@upload) if @upload.mux_playback_id
218
214
  end
219
215
 
220
216
  def file
221
217
  Imgix::Client.new(
222
218
  domain: @imgix_host,
223
219
  secure: true,
224
- include_library_param: false
220
+ include_library_param: false,
225
221
  ).path(path)
226
222
  end
227
223
 
@@ -229,12 +225,12 @@ module Dato
229
225
  query.deep_stringify_keys!
230
226
 
231
227
  if focal_point &&
232
- query["fit"] == "crop" &&
233
- (query["h"] || query["height"]) &&
234
- (query["w"] || query["width"]) &&
235
- [nil, "focalpoint"].include?(query["crop"]) &&
236
- query["fp-x"].nil? &&
237
- query["fp-y"].nil?
228
+ query["fit"] == "crop" &&
229
+ (query["h"] || query["height"]) &&
230
+ (query["w"] || query["width"]) &&
231
+ [nil, "focalpoint"].include?(query["crop"]) &&
232
+ query["fp-x"].nil? &&
233
+ query["fp-y"].nil?
238
234
 
239
235
  query.merge!(
240
236
  "crop" => "focalpoint",
@@ -252,9 +248,7 @@ module Dato
252
248
 
253
249
  response = Faraday.get(file.to_url(opts.merge(lqip: "blurhash")))
254
250
 
255
- if response.status == 200
256
- "data:image/jpeg;base64,#{Base64.strict_encode64(response.body)}"
257
- end
251
+ "data:image/jpeg;base64,#{Base64.strict_encode64(response.body)}" if response.status == 200
258
252
  end
259
253
 
260
254
  def to_hash(*_args)
@@ -279,7 +273,7 @@ module Dato
279
273
  mime_type: mime_type,
280
274
  colors: colors.map(&:to_hash),
281
275
  blurhash: blurhash,
282
- video: video && video.to_hash
276
+ video: video && video.to_hash,
283
277
  }
284
278
  end
285
279
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dato/local/field_type/file'
3
+ require "dato/local/field_type/file"
4
4
 
5
5
  module Dato
6
6
  module Local
@@ -1,15 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dato/local/field_type/seo'
3
+ require "dato/local/field_type/seo"
4
4
 
5
5
  module Dato
6
6
  module Local
7
7
  module FieldType
8
8
  class GlobalSeo
9
- attr_reader :site_name
10
- attr_reader :title_suffix
11
- attr_reader :twitter_account
12
- attr_reader :facebook_page_url
9
+ attr_reader :site_name, :title_suffix, :twitter_account, :facebook_page_url
13
10
 
14
11
  def self.parse(value, repo)
15
12
  value && new(
@@ -18,7 +15,7 @@ module Dato
18
15
  value[:twitter_account],
19
16
  value[:facebook_page_url],
20
17
  value[:fallback_seo],
21
- repo
18
+ repo,
22
19
  )
23
20
  end
24
21
 
@@ -48,7 +45,7 @@ module Dato
48
45
  title_suffix: title_suffix,
49
46
  twitter_account: twitter_account,
50
47
  facebook_page_url: facebook_page_url,
51
- fallback_seo: fallback_seo && fallback_seo.to_hash(*args)
48
+ fallback_seo: fallback_seo && fallback_seo.to_hash(*args),
52
49
  }
53
50
  end
54
51
  end
@@ -22,7 +22,7 @@ module Dato
22
22
  def to_hash(*_args)
23
23
  {
24
24
  latitude: latitude,
25
- longitude: longitude
25
+ longitude: longitude,
26
26
  }
27
27
  end
28
28
  end
@@ -26,7 +26,7 @@ module Dato
26
26
  {
27
27
  title: title,
28
28
  description: description,
29
- image: image && image.to_hash(*args)
29
+ image: image && image.to_hash(*args),
30
30
  }
31
31
  end
32
32
  end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dato
4
+ module Local
5
+ module FieldType
6
+ class StructuredText
7
+ def self.parse(value, repo)
8
+ new(value, repo)
9
+ end
10
+
11
+ def initialize(value, repo)
12
+ @value = value
13
+ @repo = repo
14
+ end
15
+
16
+ attr_reader :value
17
+
18
+ def blocks
19
+ find_all_nodes("block").map do |node|
20
+ @repo.find(node["item"])
21
+ end.uniq
22
+ end
23
+
24
+ def links
25
+ find_all_nodes(%w[inlineItem itemLink]).map do |node|
26
+ @repo.find(node["item"])
27
+ end.uniq
28
+ end
29
+
30
+ def find_all_nodes(types)
31
+ return [] if value.nil?
32
+
33
+ types = Array(types)
34
+ result = []
35
+
36
+ visit(value["document"]) do |node|
37
+ result << node if node.is_a?(Hash) && types.include?(node["type"])
38
+ end
39
+
40
+ result
41
+ end
42
+
43
+ def visit(node, &block)
44
+ if node.is_a?(Hash) && node["children"].is_a?(Array)
45
+ node["children"].each do |child|
46
+ visit(child, &block)
47
+ end
48
+ end
49
+
50
+ block.call(node)
51
+ end
52
+
53
+ def to_hash(max_depth = 3, current_depth = 0)
54
+ {
55
+ value: value,
56
+ links: links.map { |item| item.to_hash(max_depth, current_depth) },
57
+ blocks: blocks.map { |item| item.to_hash(max_depth, current_depth) },
58
+ }
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -13,7 +13,7 @@ module Dato
13
13
  value[:dark_color],
14
14
  value[:light_color],
15
15
  value[:accent_color],
16
- repo
16
+ repo,
17
17
  )
18
18
  end
19
19
 
@@ -36,7 +36,7 @@ module Dato
36
36
  dark_color: dark_color,
37
37
  light_color: light_color,
38
38
  accent_color: accent_color,
39
- logo: logo && logo.to_hash(*args)
39
+ logo: logo && logo.to_hash(*args),
40
40
  }
41
41
  end
42
42
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'imgix'
3
+ require "imgix"
4
4
 
5
5
  module Dato
6
6
  module Local
@@ -10,7 +10,7 @@ module Dato
10
10
 
11
11
  def self.parse(upload_id, repo)
12
12
  if upload_id
13
- upload = repo.entities_repo.find_entity('upload', upload_id)
13
+ upload = repo.entities_repo.find_entity("upload", upload_id)
14
14
 
15
15
  if upload
16
16
  new(
@@ -19,7 +19,7 @@ module Dato
19
19
  upload.size,
20
20
  upload.width,
21
21
  upload.height,
22
- repo.site.entity.imgix_host
22
+ repo.site.entity.imgix_host,
23
23
  )
24
24
  end
25
25
  end
@@ -45,7 +45,7 @@ module Dato
45
45
  Imgix::Client.new(
46
46
  domain: @imgix_host,
47
47
  secure: true,
48
- include_library_param: false
48
+ include_library_param: false,
49
49
  ).path(path)
50
50
  end
51
51
 
@@ -59,7 +59,7 @@ module Dato
59
59
  size: size,
60
60
  width: width,
61
61
  height: height,
62
- url: url
62
+ url: url,
63
63
  }
64
64
  end
65
65
  end
@@ -4,14 +4,7 @@ module Dato
4
4
  module Local
5
5
  module FieldType
6
6
  class Video
7
- attr_reader :url
8
- attr_reader :thumbnail_url
9
- attr_reader :title
10
- attr_reader :width
11
- attr_reader :height
12
- attr_reader :provider
13
- attr_reader :provider_url
14
- attr_reader :provider_uid
7
+ attr_reader :url, :thumbnail_url, :title, :width, :height, :provider, :provider_url, :provider_uid
15
8
 
16
9
  def self.parse(value, _repo)
17
10
  value && new(
@@ -22,7 +15,7 @@ module Dato
22
15
  value[:height],
23
16
  value[:provider],
24
17
  value[:provider_url],
25
- value[:provider_uid]
18
+ value[:provider_uid],
26
19
  )
27
20
  end
28
21
 
@@ -47,15 +40,16 @@ module Dato
47
40
  end
48
41
 
49
42
  def iframe_embed(width = self.width, height = self.height)
50
- # rubocop:disable Metrics/LineLength
51
- if provider == 'youtube'
43
+ # rubocop:disable Layout/LineLength
44
+ case provider
45
+ when "youtube"
52
46
  %(<iframe width="#{width}" height="#{height}" src="//www.youtube.com/embed/#{provider_uid}?rel=0" frameborder="0" allowfullscreen></iframe>)
53
- elsif provider == 'vimeo'
47
+ when "vimeo"
54
48
  %(<iframe src="//player.vimeo.com/video/#{provider_uid}?title=0&amp;byline=0&amp;portrait=0" width="#{width}" height="#{height}" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>)
55
- elsif provider == 'facebook'
49
+ when "facebook"
56
50
  %(<iframe src="//www.facebook.com/plugins/video.php?href=#{url}&width=#{width}&show_text=false&height=#{height}" width="#{width}" height="#{height}" style="border:none;overflow:hidden;width:100%;" scrolling="no" frameborder="0" allowTransparency="true" allow="encrypted-media" allowFullScreen="true"></iframe>)
57
51
  end
58
- # rubocop:enable Metrics/LineLength
52
+ # rubocop:enable Layout/LineLength
59
53
  end
60
54
 
61
55
  def to_hash(*_args)
@@ -67,7 +61,7 @@ module Dato
67
61
  height: height,
68
62
  provider: provider,
69
63
  provider_url: provider_url,
70
- provider_uid: provider_uid
64
+ provider_uid: provider_uid,
71
65
  }
72
66
  end
73
67
  end
@@ -1,11 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'forwardable'
4
- require 'active_support/inflector/transliterate'
5
- require 'active_support/hash_with_indifferent_access'
6
- require 'dato/utils/locale_value'
3
+ require "forwardable"
4
+ require "dato/utils/locale_value"
7
5
 
8
- Dir[File.dirname(__FILE__) + '/field_type/*.rb'].each do |file|
6
+ Dir["#{File.dirname(__FILE__)}/field_type/*.rb"].sort.each do |file|
9
7
  require file
10
8
  end
11
9
 
@@ -15,6 +13,7 @@ module Dato
15
13
  extend Forwardable
16
14
 
17
15
  attr_reader :entity
16
+
18
17
  def_delegators :entity, :id, :meta
19
18
 
20
19
  def initialize(entity, items_repo)
@@ -45,7 +44,7 @@ module Dato
45
44
 
46
45
  def attributes
47
46
  fields.each_with_object(
48
- ActiveSupport::HashWithIndifferentAccess.new
47
+ ActiveSupport::HashWithIndifferentAccess.new,
49
48
  ) do |field, acc|
50
49
  acc[field.api_key.to_sym] = read_attribute(field.api_key, field)
51
50
  end
@@ -88,7 +87,7 @@ module Dato
88
87
  id: id,
89
88
  item_type: item_type.api_key,
90
89
  updated_at: updated_at,
91
- created_at: created_at
90
+ created_at: created_at,
92
91
  }
93
92
 
94
93
  base[:position] = position if item_type.sortable
@@ -98,7 +97,7 @@ module Dato
98
97
  base[:children] = children.map do |child|
99
98
  child.to_hash(
100
99
  max_depth,
101
- current_depth + 1
100
+ current_depth + 1,
102
101
  )
103
102
  end
104
103
  end
@@ -109,7 +108,7 @@ module Dato
109
108
  result[field.api_key.to_sym] = if value.respond_to?(:to_hash)
110
109
  value.to_hash(
111
110
  max_depth,
112
- current_depth + 1
111
+ current_depth + 1,
113
112
  )
114
113
  else
115
114
  value
@@ -138,9 +137,9 @@ module Dato
138
137
  "Warning: unrecognized field of type `#{field_type}`",
139
138
  "for item `#{item_type.api_key}` and",
140
139
  "field `#{method}`: returning a simple Hash instead.",
141
- 'Please upgrade to the latest version of the `dato` gem!'
140
+ "Please upgrade to the latest version of the `dato` gem!",
142
141
  ]
143
- puts warning.join(' ')
142
+ puts warning.join(" ")
144
143
 
145
144
  value
146
145
  end
@@ -154,7 +153,7 @@ module Dato
154
153
  super
155
154
  end
156
155
  rescue NoMethodError => e
157
- if e.name === method
156
+ if e.name == method
158
157
  message = []
159
158
  message << "Undefined method `#{method}`"
160
159
  message << "Available fields for a `#{item_type.api_key}` item:"
@@ -1,8 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_support/core_ext/string'
4
- require 'dato/local/item'
5
- require 'dato/local/site'
3
+ require "dato/local/item"
4
+ require "dato/local/site"
6
5
 
7
6
  module Dato
8
7
  module Local
@@ -37,8 +36,8 @@ module Dato
37
36
 
38
37
  def site
39
38
  Site.new(
40
- entities_repo.find_entities_of_type('site').first,
41
- self
39
+ entities_repo.find_entities_of_type("site").first,
40
+ self,
42
41
  )
43
42
  end
44
43
 
@@ -47,7 +46,7 @@ module Dato
47
46
  end
48
47
 
49
48
  def item_types
50
- entities_repo.find_entities_of_type('item_type')
49
+ entities_repo.find_entities_of_type("item_type")
51
50
  end
52
51
 
53
52
  def single_instance_item_types
@@ -97,7 +96,7 @@ module Dato
97
96
  end
98
97
 
99
98
  if clashing_keys.include?(pluralized_api_key)
100
- suffix = item_type.singleton ? 'instance' : 'collection'
99
+ suffix = item_type.singleton ? "instance" : "collection"
101
100
  method = "#{method}_#{suffix}"
102
101
  end
103
102
 
@@ -119,9 +118,7 @@ module Dato
119
118
  item = Item.new(item_entity, self)
120
119
  method = item_type_methods[item_entity.item_type]
121
120
 
122
- unless item_entity.item_type.singleton
123
- @collections_by_type[method].push item
124
- end
121
+ @collections_by_type[method].push item unless item_entity.item_type.singleton
125
122
 
126
123
  @items_by_id[item.id] = item
127
124
 
@@ -144,9 +141,7 @@ module Dato
144
141
  item[field].nil?
145
142
  end
146
143
  @collections_by_type[method] = valid_items.sort_by { |item| item[field] } + nil_items
147
- if item_type.ordering_direction == 'desc'
148
- @collections_by_type[method].reverse!
149
- end
144
+ @collections_by_type[method].reverse! if item_type.ordering_direction == "desc"
150
145
  end
151
146
  end
152
147
  end
@@ -156,16 +151,14 @@ module Dato
156
151
  method = item_type_methods[item_type]
157
152
  next unless item_type.singleton
158
153
 
159
- item = if item_type.singleton_item
160
- @items_by_id[item_type.singleton_item.id]
161
- end
154
+ item = (@items_by_id[item_type.singleton_item.id] if item_type.singleton_item)
162
155
 
163
156
  @collections_by_type[method] = item
164
157
  end
165
158
  end
166
159
 
167
160
  def item_entities
168
- entities_repo.find_entities_of_type('item')
161
+ entities_repo.find_entities_of_type("item")
169
162
  end
170
163
 
171
164
  def method_missing(method, *arguments, &block)
@@ -177,7 +170,7 @@ module Dato
177
170
  rescue NoMethodError
178
171
  message = []
179
172
  message << "Undefined method `#{method}`"
180
- message << 'Available DatoCMS collections/items:'
173
+ message << "Available DatoCMS collections/items:"
181
174
  message += collections_by_type.map do |key, _value|
182
175
  "* .#{key}"
183
176
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dato/local/json_api_meta'
3
+ require "dato/local/json_api_meta"
4
4
 
5
5
  module Dato
6
6
  module Local
@@ -60,11 +60,12 @@ module Dato
60
60
  end
61
61
 
62
62
  def dereference_linkage(linkage)
63
- if linkage.is_a? Array
63
+ case linkage
64
+ when Array
64
65
  linkage.map do |item|
65
66
  data_source.find_entity(item[:type], item[:id])
66
67
  end
67
- elsif linkage.is_a? Hash
68
+ when Hash
68
69
  data_source.find_entity(linkage[:type], linkage[:id])
69
70
  end
70
71
  end