jekyll_picture_tag 1.10.2 → 2.0.0pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc +4 -0
  3. data/.github/workflows/code-checks.yml +33 -0
  4. data/.gitignore +3 -0
  5. data/.rubocop.yml +32 -0
  6. data/.ruby-version +1 -1
  7. data/docs/.envrc +2 -0
  8. data/docs/Gemfile +4 -2
  9. data/docs/Gemfile.lock +14 -12
  10. data/docs/_config.yml +6 -10
  11. data/docs/devs/contributing/code.md +54 -0
  12. data/docs/devs/contributing/docs.md +31 -0
  13. data/docs/devs/contributing/index.md +15 -0
  14. data/docs/devs/contributing/setup.md +33 -0
  15. data/docs/devs/contributing/testing.md +23 -0
  16. data/docs/devs/index.md +7 -0
  17. data/docs/devs/releases.md +113 -0
  18. data/docs/index.md +62 -31
  19. data/docs/logo.png +0 -0
  20. data/docs/logo.svg +880 -0
  21. data/docs/users/configuration/directories.md +34 -0
  22. data/docs/users/configuration/disable.md +24 -0
  23. data/docs/users/configuration/fast_build.md +28 -0
  24. data/docs/users/configuration/ignore_missing.md +23 -0
  25. data/docs/users/configuration/index.md +29 -0
  26. data/docs/users/configuration/kramdown_fix.md +20 -0
  27. data/docs/users/configuration/suppress_warnings.md +16 -0
  28. data/docs/users/configuration/urls.md +69 -0
  29. data/docs/users/getting_started.md +55 -0
  30. data/docs/users/index.md +7 -0
  31. data/docs/users/installation.md +31 -0
  32. data/docs/users/liquid_tag/argument_reference/alternate_images.md +18 -0
  33. data/docs/users/liquid_tag/argument_reference/attributes.md +42 -0
  34. data/docs/users/liquid_tag/argument_reference/base_image.md +12 -0
  35. data/docs/users/liquid_tag/argument_reference/crop.md +33 -0
  36. data/docs/users/liquid_tag/argument_reference/link.md +16 -0
  37. data/docs/users/liquid_tag/argument_reference/preset.md +17 -0
  38. data/docs/users/liquid_tag/argument_reference/readme.md +9 -0
  39. data/docs/users/liquid_tag/examples.md +81 -0
  40. data/docs/users/liquid_tag/index.md +31 -0
  41. data/docs/users/notes/git_lfs.md +7 -0
  42. data/docs/users/notes/github_pages.md +5 -0
  43. data/docs/users/notes/html_attributes.md +5 -0
  44. data/docs/users/notes/index.md +6 -0
  45. data/docs/users/notes/kramdown_bug.md +41 -0
  46. data/docs/users/notes/managing_images.md +21 -0
  47. data/docs/{migration.md → users/notes/migration_1.md} +1 -1
  48. data/docs/users/notes/migration_2.md +99 -0
  49. data/docs/users/presets/cropping.md +60 -0
  50. data/docs/users/presets/default.md +32 -0
  51. data/docs/users/presets/examples.md +111 -0
  52. data/docs/users/presets/fallback_image.md +28 -0
  53. data/docs/users/presets/html_attributes.md +26 -0
  54. data/docs/users/presets/image_formats.md +21 -0
  55. data/docs/users/presets/image_quality.md +120 -0
  56. data/docs/users/presets/index.md +137 -0
  57. data/docs/users/presets/link_source.md +16 -0
  58. data/docs/users/presets/markup_formats/fragments.md +48 -0
  59. data/docs/users/presets/markup_formats/javascript_friendly.md +57 -0
  60. data/docs/users/presets/markup_formats/readme.md +43 -0
  61. data/docs/users/presets/markup_formats/standard_html.md +25 -0
  62. data/docs/users/presets/media_queries.md +36 -0
  63. data/docs/users/presets/nomarkdown_override.md +17 -0
  64. data/docs/users/presets/pixel_ratio_srcsets.md +32 -0
  65. data/docs/users/presets/quality_width_graph.png +0 -0
  66. data/docs/users/presets/width_height_attributes.md +34 -0
  67. data/docs/users/presets/width_srcsets.md +123 -0
  68. data/docs/users/tutorial.md +97 -0
  69. data/jekyll_picture_tag.gemspec +38 -24
  70. data/lib/jekyll_picture_tag.rb +11 -9
  71. data/lib/jekyll_picture_tag/cache.rb +64 -0
  72. data/lib/jekyll_picture_tag/defaults/global.rb +18 -0
  73. data/lib/jekyll_picture_tag/defaults/presets.rb +57 -0
  74. data/lib/jekyll_picture_tag/images.rb +4 -0
  75. data/lib/jekyll_picture_tag/images/generated_image.rb +92 -0
  76. data/lib/jekyll_picture_tag/images/image_file.rb +90 -0
  77. data/lib/jekyll_picture_tag/{img_uri.rb → images/img_uri.rb} +4 -10
  78. data/lib/jekyll_picture_tag/images/source_image.rb +138 -0
  79. data/lib/jekyll_picture_tag/instructions.rb +70 -6
  80. data/lib/jekyll_picture_tag/instructions/children/config.rb +128 -0
  81. data/lib/jekyll_picture_tag/instructions/children/context.rb +24 -0
  82. data/lib/jekyll_picture_tag/instructions/children/params.rb +90 -0
  83. data/lib/jekyll_picture_tag/instructions/children/parsers.rb +41 -0
  84. data/lib/jekyll_picture_tag/instructions/children/preset.rb +182 -0
  85. data/lib/jekyll_picture_tag/instructions/parents/conditional_instruction.rb +69 -0
  86. data/lib/jekyll_picture_tag/instructions/parents/env_instruction.rb +29 -0
  87. data/lib/jekyll_picture_tag/output_formats/basic.rb +11 -21
  88. data/lib/jekyll_picture_tag/output_formats/img.rb +11 -0
  89. data/lib/jekyll_picture_tag/output_formats/picture.rb +22 -0
  90. data/lib/jekyll_picture_tag/parsers.rb +5 -0
  91. data/lib/jekyll_picture_tag/{instructions → parsers}/arg_splitter.rb +4 -3
  92. data/lib/jekyll_picture_tag/parsers/configuration.rb +28 -0
  93. data/lib/jekyll_picture_tag/{instructions → parsers}/html_attributes.rb +1 -1
  94. data/lib/jekyll_picture_tag/parsers/preset.rb +43 -0
  95. data/lib/jekyll_picture_tag/{instructions → parsers}/tag_parser.rb +15 -12
  96. data/lib/jekyll_picture_tag/router.rb +35 -92
  97. data/lib/jekyll_picture_tag/srcsets/basic.rb +11 -8
  98. data/lib/jekyll_picture_tag/utils.rb +24 -20
  99. data/lib/jekyll_picture_tag/version.rb +1 -1
  100. data/readme.md +15 -12
  101. metadata +206 -95
  102. data/.travis.yml +0 -8
  103. data/Dockerfile +0 -9
  104. data/docs/_layouts/directory.html +0 -32
  105. data/docs/assets/style.css +0 -31
  106. data/docs/contributing.md +0 -109
  107. data/docs/example_presets.md +0 -116
  108. data/docs/global_configuration.md +0 -173
  109. data/docs/installation.md +0 -45
  110. data/docs/notes.md +0 -91
  111. data/docs/output.md +0 -63
  112. data/docs/presets.md +0 -361
  113. data/docs/releases.md +0 -65
  114. data/docs/usage.md +0 -143
  115. data/jekyll-picture-tag.gemspec +0 -52
  116. data/lib/jekyll-picture-tag.rb +0 -25
  117. data/lib/jekyll_picture_tag/defaults/global.yml +0 -11
  118. data/lib/jekyll_picture_tag/defaults/presets.yml +0 -10
  119. data/lib/jekyll_picture_tag/generated_image.rb +0 -161
  120. data/lib/jekyll_picture_tag/instructions/configuration.rb +0 -121
  121. data/lib/jekyll_picture_tag/instructions/preset.rb +0 -102
  122. data/lib/jekyll_picture_tag/instructions/set.rb +0 -71
  123. data/lib/jekyll_picture_tag/source_image.rb +0 -87
@@ -0,0 +1,24 @@
1
+ module PictureTag
2
+ module Instructions
3
+ # Jekyll site info
4
+ class Site < Instruction
5
+ def source
6
+ PictureTag.context.registers[:site]
7
+ end
8
+ end
9
+
10
+ # Current page in jekyll site
11
+ class Page < Instruction
12
+ def source
13
+ PictureTag.context.registers[:page]
14
+ end
15
+ end
16
+
17
+ # Digs into jekyll context, returns current environment
18
+ class JekyllEnv < Instruction
19
+ def source
20
+ PictureTag.context.environments.first['jekyll']['environment']
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,90 @@
1
+ module PictureTag
2
+ module Instructions
3
+ # Builds instances of all source images.
4
+ class SourceImages < Instruction
5
+ def source
6
+ {
7
+ source_names: PictureTag.params.source_names,
8
+ media_presets: PictureTag.params.media_presets
9
+ }
10
+ end
11
+
12
+ def coerce
13
+ sources = [PictureTag::SourceImage.new(source[:source_names].shift)]
14
+
15
+ while source[:source_names].any?
16
+ sources << PictureTag::SourceImage.new(
17
+ source[:source_names].shift, source[:media_presets].shift
18
+ )
19
+ end
20
+
21
+ sources
22
+ end
23
+ end
24
+
25
+ # Which crop to use for a given media query. Can be given either in params
26
+ # or preset.
27
+ class Crop < ConditionalInstruction
28
+ def source
29
+ super.merge(
30
+ { params: PictureTag.params.crop }
31
+ )
32
+ end
33
+
34
+ def coerce(media = nil)
35
+ raise ArgumentError unless valid?
36
+
37
+ source[:params][media] || value_hash[media]
38
+ end
39
+
40
+ def setting_basename
41
+ 'crop'
42
+ end
43
+
44
+ def setting_prefix
45
+ 'media'
46
+ end
47
+
48
+ def acceptable_types
49
+ super + [String]
50
+ end
51
+ end
52
+
53
+ # Which vips interestingness setting to use for a given media query. Can be
54
+ # given either in params or preset.
55
+ class Keep < ConditionalInstruction
56
+ def source
57
+ super.merge(
58
+ { params: PictureTag.params.keep }
59
+ )
60
+ end
61
+
62
+ def coerce(media = nil)
63
+ raise ArgumentError unless valid?
64
+
65
+ lookup[source[:params][media] || super(media)]
66
+ end
67
+
68
+ def lookup
69
+ {
70
+ 'center' => :centre,
71
+ 'centre' => :centre,
72
+ 'attention' => :attention,
73
+ 'entropy' => :entropy
74
+ }
75
+ end
76
+
77
+ def setting_basename
78
+ 'keep'
79
+ end
80
+
81
+ def setting_prefix
82
+ 'media'
83
+ end
84
+
85
+ def acceptable_types
86
+ super + [String]
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,41 @@
1
+ module PictureTag
2
+ module Instructions
3
+ # PictureTag configuration
4
+ class Config < Instruction
5
+ def source
6
+ PictureTag::Parsers::Configuration.new
7
+ end
8
+ end
9
+
10
+ # Tag parameters
11
+ class Params < Instruction
12
+ def source
13
+ PictureTag::Parsers::TagParser.new PictureTag.raw_params
14
+ end
15
+ end
16
+
17
+ # Currently selected preset
18
+ class Preset < Instruction
19
+ def source
20
+ PictureTag::Parsers::Preset.new PictureTag.params.preset_name
21
+ end
22
+ end
23
+
24
+ # Handles non-image arguments to liquid tag and preset.
25
+ class HtmlAttributes < Instruction
26
+ def source
27
+ PictureTag::Parsers::HTMLAttributeSet.new PictureTag.params.leftovers
28
+ end
29
+ end
30
+
31
+ # TODO: rename to MediaQueries
32
+ # Returns user-defined media queries.
33
+ class MediaPresets < Instruction
34
+ def source
35
+ STOCK_MEDIA_QUERIES.merge(
36
+ PictureTag.site.data.dig('picture', 'media_queries') || {}
37
+ )
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,182 @@
1
+ require 'mime-types'
2
+
3
+ module PictureTag
4
+ module Instructions
5
+ # Returns an instance of the correct markup format's corresponding class
6
+ class OutputClass < Instruction
7
+ private
8
+
9
+ def source
10
+ PictureTag.preset['markup']
11
+ end
12
+
13
+ def coerce
14
+ Object.const_get(class_name)
15
+ end
16
+
17
+ def class_name
18
+ 'PictureTag::OutputFormats::' + Utils.titleize(source)
19
+ end
20
+
21
+ def valid?
22
+ source.is_a?(String) &&
23
+ !source.include?(' ') &&
24
+ Object.const_defined?(class_name)
25
+ end
26
+ end
27
+
28
+ # Image formats
29
+ class Formats < Instruction
30
+ private
31
+
32
+ def source
33
+ PictureTag.preset['formats']
34
+ end
35
+
36
+ def coerce
37
+ [source].flatten
38
+ end
39
+
40
+ def valid?
41
+ coerced.all? do |format|
42
+ types = MIME::Types.type_for(format)
43
+ format == 'original' ||
44
+ types.length == 1 && types.first.media_type == 'image'
45
+ end
46
+ end
47
+ end
48
+
49
+ # Fallback image format
50
+ class FallbackFormat < Instruction
51
+ private
52
+
53
+ def source
54
+ PictureTag.preset['fallback_format']
55
+ end
56
+
57
+ def valid?
58
+ types = MIME::Types.type_for(coerced)
59
+ coerced == 'original' ||
60
+ types.length == 1 && types.first.media_type == 'image'
61
+ end
62
+ end
63
+
64
+ # Fallback Image width
65
+ class FallbackWidth < Instruction
66
+ private
67
+
68
+ def source
69
+ PictureTag.preset['fallback_width']
70
+ end
71
+
72
+ def valid?
73
+ source.is_a? Integer
74
+ end
75
+
76
+ def error_message
77
+ <<~HEREDOC
78
+ fallback_width for preset '#{PictureTag.preset.name}' is invalid. It
79
+ should be a positive integer. You can use underscores as separators:
80
+ 1200
81
+ 1_200
82
+ HEREDOC
83
+ end
84
+ end
85
+
86
+ # Whether to add a {::nomarkdown} wrapper
87
+ class Nomarkdown < Instruction
88
+ private
89
+
90
+ def source
91
+ {
92
+ config: PictureTag.pconfig['nomarkdown'],
93
+ md_page: Utils.markdown_page?,
94
+ preset: PictureTag.preset['nomarkdown']
95
+ }
96
+ end
97
+
98
+ def valid?
99
+ source.fetch_values(:preset, :config).all? do |setting|
100
+ [true, false, nil].include? setting
101
+ end
102
+ end
103
+
104
+ def coerce
105
+ return source[:preset] unless source[:preset].nil?
106
+
107
+ source[:md_page] && source[:config]
108
+ end
109
+ end
110
+
111
+ # Returns widths for a given media query.
112
+ class Widths < ConditionalInstruction
113
+ private
114
+
115
+ def setting_name
116
+ 'widths'
117
+ end
118
+
119
+ def setting_prefix
120
+ 'media'
121
+ end
122
+
123
+ def acceptable_types
124
+ super + [Array]
125
+ end
126
+
127
+ def valid_hash?
128
+ hash = source[:hash]
129
+ return true if hash.nil?
130
+
131
+ hash.is_a?(Hash) && valid_hash_keys?(hash) && valid_hash_values?(hash)
132
+ end
133
+
134
+ def valid_hash_keys?(hash)
135
+ hash.keys.all? { |k| k.is_a? String }
136
+ end
137
+
138
+ def valid_hash_values?(hash)
139
+ hash.values.all? do |val|
140
+ val.is_a?(Array) && val.all? { |subval| subval.is_a? Integer }
141
+ end
142
+ end
143
+ end
144
+
145
+ # Returns quality for a given width.
146
+ class Quality < ConditionalInstruction
147
+ private
148
+
149
+ def setting_name
150
+ 'quality'
151
+ end
152
+
153
+ def setting_prefix
154
+ 'format'
155
+ end
156
+
157
+ def acceptable_types
158
+ super + [Integer, Hash]
159
+ end
160
+
161
+ def coerce(format = nil, width = nil)
162
+ setting = super(format)
163
+
164
+ return setting unless setting.is_a? Hash
165
+
166
+ parse_quality_hash(setting, width)
167
+ end
168
+
169
+ # Works out linearly interpolated quality settings.
170
+ def parse_quality_hash(points, width)
171
+ # The points can be given in any order.
172
+ low, high = *points.keys.map(&:to_i).sort
173
+
174
+ case width
175
+ when 0..low then points[low]
176
+ when low..high then Utils.interpolate(points.keys, points.values, width)
177
+ when high..999_999 then points[high]
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end
@@ -0,0 +1,69 @@
1
+ module PictureTag
2
+ module Instructions
3
+ # Many inputs take a common format: a generic setting which applies all of
4
+ # the time, or more specific versions of that setting for specific
5
+ # circumstances. For example, quality can be set globally, or per image
6
+ # format. This instruction class handles those cases.
7
+ #
8
+ # To use, you must at minimum define setting_basename, setting_prefix, and
9
+ # add to the acceptable_types (or write your own validation).
10
+ class ConditionalInstruction < Instruction
11
+ def value(*args)
12
+ coerce(*args)
13
+ end
14
+
15
+ private
16
+
17
+ def setting_basename
18
+ raise NotImplementedError
19
+ end
20
+
21
+ # Special condition for setting; media, crop, etc
22
+ def setting_prefix
23
+ raise NotImplementedError
24
+ end
25
+
26
+ def acceptable_types
27
+ [NilClass]
28
+ end
29
+
30
+ def coerce(arg)
31
+ raise ArgumentError unless valid?
32
+
33
+ value_hash[arg]
34
+ end
35
+
36
+ def source
37
+ {
38
+ hash: PictureTag.preset[setting_prefix + '_' + setting_name],
39
+ default: PictureTag.preset[setting_name]
40
+ }
41
+ end
42
+
43
+ def value_hash
44
+ vals = source[:hash] || {}
45
+ vals.default = source[:default]
46
+
47
+ vals
48
+ end
49
+
50
+ def valid?
51
+ valid_hash? && valid_default?
52
+ end
53
+
54
+ def acceptable_type?(value)
55
+ acceptable_types.any? { |type| value.is_a? type }
56
+ end
57
+
58
+ def valid_hash?
59
+ source[:hash].nil? || source[:hash].values.all? do |v|
60
+ acceptable_type?(v)
61
+ end
62
+ end
63
+
64
+ def valid_default?
65
+ acceptable_type? source[:default]
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,29 @@
1
+ module PictureTag
2
+ module Instructions
3
+ # There are a few config settings which are environment dependent, and can
4
+ # either be booleans, environment names, or arrays of environment names.
5
+ # This class works it out and returns a boolean.
6
+ class EnvInstruction < Instruction
7
+ private
8
+
9
+ def coerce
10
+ get_bool(source)
11
+ end
12
+
13
+ def get_bool(value)
14
+ case value
15
+ when true, false, nil then value
16
+ when String then value == PictureTag.jekyll_env
17
+ when Array then value.include? PictureTag.jekyll_env
18
+ when Hash then get_bool(value[:setting])
19
+ else raise ArgumentError, error_message
20
+ end
21
+ end
22
+
23
+ def error_message
24
+ "JPT - #{setting_name} must be a boolean, an environment name," \
25
+ ' or an array of environment names.'
26
+ end
27
+ end
28
+ end
29
+ end
@@ -6,6 +6,10 @@ module PictureTag
6
6
  class Basic
7
7
  include ObjectiveElements
8
8
 
9
+ def to_s
10
+ wrap(base_markup).to_s
11
+ end
12
+
9
13
  # Used for both the fallback image, and for the complete markup.
10
14
  def build_base_img
11
15
  img = SingleTag.new 'img'
@@ -23,10 +27,6 @@ module PictureTag
23
27
  img
24
28
  end
25
29
 
26
- def to_s
27
- wrap(base_markup).to_s
28
- end
29
-
30
30
  private
31
31
 
32
32
  # Handles various wrappers around basic markup
@@ -76,9 +76,7 @@ module PictureTag
76
76
  image = GeneratedImage.new(
77
77
  source_file: PictureTag.source_images.first,
78
78
  format: PictureTag.fallback_format,
79
- width: checked_fallback_width,
80
- crop: PictureTag.crop,
81
- gravity: PictureTag.gravity
79
+ width: checked_fallback_width
82
80
  )
83
81
 
84
82
  image.generate
@@ -86,13 +84,13 @@ module PictureTag
86
84
  image
87
85
  end
88
86
 
87
+ # It's only a candidate, because we don't know if the fallback width
88
+ # setting is larger than the source file.
89
89
  def fallback_candidate
90
90
  @fallback_candidate ||= GeneratedImage.new(
91
91
  source_file: PictureTag.source_images.first,
92
92
  format: PictureTag.fallback_format,
93
- width: PictureTag.fallback_width,
94
- crop: PictureTag.crop,
95
- gravity: PictureTag.gravity
93
+ width: PictureTag.fallback_width
96
94
  )
97
95
  end
98
96
 
@@ -117,22 +115,14 @@ module PictureTag
117
115
  PictureTag.source_images.first
118
116
  end
119
117
 
120
- def source_width
121
- if PictureTag.crop
122
- fallback_candidate.cropped_source_width
123
- else
124
- source.width
125
- end
126
- end
127
-
128
118
  def checked_fallback_width
129
119
  target = PictureTag.fallback_width
130
120
 
131
- if target > source_width
121
+ if target > source.width
132
122
  Utils.warning "#{source.shortname} is smaller than the " \
133
- "requested fallback width of #{target}px. Using #{source_width}" \
123
+ "requested fallback width of #{target}px. Using #{source.width}" \
134
124
  ' px instead.'
135
- source_width
125
+ source.width
136
126
  else
137
127
  target
138
128
  end