jekyll_picture_tag 1.11.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) 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 +31 -3
  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 +118 -0
  18. data/docs/index.md +67 -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 +32 -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 +75 -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/presets/writing_presets.md +65 -0
  69. data/docs/users/tutorial.md +97 -0
  70. data/jekyll_picture_tag.gemspec +38 -23
  71. data/lib/jekyll_picture_tag.rb +11 -10
  72. data/lib/jekyll_picture_tag/cache.rb +64 -3
  73. data/lib/jekyll_picture_tag/defaults/global.rb +18 -0
  74. data/lib/jekyll_picture_tag/defaults/presets.rb +57 -0
  75. data/lib/jekyll_picture_tag/images.rb +4 -0
  76. data/lib/jekyll_picture_tag/images/generated_image.rb +92 -0
  77. data/lib/jekyll_picture_tag/images/image_file.rb +90 -0
  78. data/lib/jekyll_picture_tag/{img_uri.rb → images/img_uri.rb} +3 -10
  79. data/lib/jekyll_picture_tag/{source_image.rb → images/source_image.rb} +44 -9
  80. data/lib/jekyll_picture_tag/instructions.rb +70 -6
  81. data/lib/jekyll_picture_tag/instructions/children/config.rb +128 -0
  82. data/lib/jekyll_picture_tag/instructions/children/context.rb +24 -0
  83. data/lib/jekyll_picture_tag/instructions/children/params.rb +90 -0
  84. data/lib/jekyll_picture_tag/instructions/children/parsers.rb +41 -0
  85. data/lib/jekyll_picture_tag/instructions/children/preset.rb +182 -0
  86. data/lib/jekyll_picture_tag/instructions/parents/conditional_instruction.rb +69 -0
  87. data/lib/jekyll_picture_tag/instructions/parents/env_instruction.rb +29 -0
  88. data/lib/jekyll_picture_tag/output_formats/basic.rb +5 -17
  89. data/lib/jekyll_picture_tag/parsers.rb +5 -0
  90. data/lib/jekyll_picture_tag/{instructions → parsers}/arg_splitter.rb +1 -1
  91. data/lib/jekyll_picture_tag/parsers/configuration.rb +28 -0
  92. data/lib/jekyll_picture_tag/{instructions → parsers}/html_attributes.rb +1 -1
  93. data/lib/jekyll_picture_tag/parsers/preset.rb +43 -0
  94. data/lib/jekyll_picture_tag/{instructions → parsers}/tag_parser.rb +15 -12
  95. data/lib/jekyll_picture_tag/router.rb +35 -93
  96. data/lib/jekyll_picture_tag/srcsets/basic.rb +4 -10
  97. data/lib/jekyll_picture_tag/utils.rb +24 -20
  98. data/lib/jekyll_picture_tag/version.rb +1 -1
  99. data/readme.md +15 -13
  100. metadata +215 -93
  101. data/.travis.yml +0 -8
  102. data/Dockerfile +0 -9
  103. data/docs/_layouts/directory.html +0 -32
  104. data/docs/assets/style.css +0 -31
  105. data/docs/contributing.md +0 -109
  106. data/docs/example_presets.md +0 -116
  107. data/docs/global_configuration.md +0 -173
  108. data/docs/installation.md +0 -45
  109. data/docs/notes.md +0 -91
  110. data/docs/output.md +0 -63
  111. data/docs/presets.md +0 -391
  112. data/docs/releases.md +0 -70
  113. data/docs/usage.md +0 -157
  114. data/jekyll-picture-tag.gemspec +0 -52
  115. data/lib/jekyll-picture-tag.rb +0 -25
  116. data/lib/jekyll_picture_tag/cache/base.rb +0 -59
  117. data/lib/jekyll_picture_tag/cache/generated.rb +0 -20
  118. data/lib/jekyll_picture_tag/cache/source.rb +0 -19
  119. data/lib/jekyll_picture_tag/defaults/global.yml +0 -11
  120. data/lib/jekyll_picture_tag/defaults/presets.yml +0 -11
  121. data/lib/jekyll_picture_tag/generated_image.rb +0 -140
  122. data/lib/jekyll_picture_tag/instructions/configuration.rb +0 -121
  123. data/lib/jekyll_picture_tag/instructions/preset.rb +0 -103
  124. data/lib/jekyll_picture_tag/instructions/set.rb +0 -71
@@ -0,0 +1,5 @@
1
+ require_relative 'parsers/arg_splitter'
2
+ require_relative 'parsers/configuration'
3
+ require_relative 'parsers/html_attributes'
4
+ require_relative 'parsers/preset'
5
+ require_relative 'parsers/tag_parser'
@@ -1,5 +1,5 @@
1
1
  module PictureTag
2
- module Instructions
2
+ module Parsers
3
3
  # This class takes in the arguments passed to the liquid tag, and splits it
4
4
  # up into 'words' (correctly handling quotes and backslash escapes.)
5
5
  #
@@ -0,0 +1,28 @@
1
+ module PictureTag
2
+ module Parsers
3
+ # Global config (big picture). loads jekyll data/config files, and the j-p-t
4
+ # defaults from included yml files.
5
+ class Configuration
6
+ # returns jekyll's configuration (picture is a subset)
7
+ def [](key)
8
+ content[key]
9
+ end
10
+
11
+ private
12
+
13
+ def content
14
+ @content ||= setting_merge(DEFAULT_CONFIG, PictureTag.site.config)
15
+ end
16
+
17
+ def setting_merge(default, jekyll)
18
+ jekyll.merge default do |_key, config_setting, default_setting|
19
+ if default_setting.respond_to? :merge
20
+ setting_merge(default_setting, config_setting)
21
+ else
22
+ config_setting
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -1,5 +1,5 @@
1
1
  module PictureTag
2
- module Instructions
2
+ module Parsers
3
3
  # Handles HTML attributes, sourced from configuration and the liquid tag,
4
4
  # sent to various elements.
5
5
  # Stored as a hash, with string keys.
@@ -0,0 +1,43 @@
1
+ module PictureTag
2
+ module Parsers
3
+ # Handles the specific tag image set to construct.
4
+ class Preset
5
+ attr_reader :name
6
+
7
+ def initialize(name)
8
+ @name = name
9
+ end
10
+
11
+ def [](key)
12
+ content[key]
13
+ end
14
+
15
+ protected
16
+
17
+ def content
18
+ @content ||= DEFAULT_PRESET.merge settings
19
+ end
20
+
21
+ private
22
+
23
+ def settings
24
+ PictureTag.site.data.dig('picture', 'presets', name) ||
25
+ STOCK_PRESETS[name] ||
26
+ no_preset
27
+ end
28
+
29
+ def no_preset
30
+ unless name == 'default'
31
+ Utils.warning(
32
+ <<~HEREDOC
33
+ Preset "#{name}" not found in #{PictureTag.config['data_dir']}/picture.yml
34
+ under 'presets' key, or in stock presets. Using default values."
35
+ HEREDOC
36
+ )
37
+ end
38
+
39
+ {}
40
+ end
41
+ end
42
+ end
43
+ end
@@ -1,5 +1,5 @@
1
1
  module PictureTag
2
- module Instructions
2
+ module Parsers
3
3
  # Tag Parsing Responsibilities:
4
4
  #
5
5
  # {% picture mypreset a.jpg 3:2 mobile: b.jpg --alt "Alt" --link "/" %}
@@ -9,17 +9,16 @@ module PictureTag
9
9
  # string), hands them to ArgSplitter (which breaks them up into an array of
10
10
  # words), extracts the preset name (if present), source image name(s),
11
11
  # associated media queries (if present), and image-related arguments such as
12
- # crop and gravity. HTML attributes are handed off to its respective class
12
+ # crop and keep. HTML attributes are handed off to its respective class
13
13
  # (as 'leftovers')
14
14
  #
15
15
  # Media presets and source names are stored as arrays in their correct
16
- # orders. Gravities and geometries are stored in a hash, keyed by their
16
+ # orders. Crop settings are stored in a hash, keyed by their
17
17
  # relevant media presets. Note that the base image will have a media preset
18
18
  # of nil, which is a perfectly fine hash key.
19
- #
20
19
  class TagParser
21
- attr_reader :preset_name, :source_names, :media_presets, :gravities,
22
- :geometries, :leftovers
20
+ attr_reader :preset_name, :source_names, :media_presets, :keep,
21
+ :crop, :leftovers
23
22
 
24
23
  def initialize(raw_params)
25
24
  @raw_params = raw_params
@@ -27,8 +26,8 @@ module PictureTag
27
26
 
28
27
  @media_presets = []
29
28
  @source_names = []
30
- @geometries = {}
31
- @gravities = {}
29
+ @keep = {}
30
+ @crop = {}
32
31
 
33
32
  parse_params
34
33
  end
@@ -51,14 +50,18 @@ module PictureTag
51
50
  end
52
51
 
53
52
  def parse_param(param)
53
+ # Media query, i.e. 'mobile:'
54
54
  if param.match?(/[\w\-]+:$/)
55
55
  add_media_source
56
56
 
57
- elsif Utils::GRAVITIES.include?(param.downcase)
58
- @gravities[@media_presets.last] = @params.shift
57
+ # Smartcrop interestingness setting. We label it 'keep', since it
58
+ # determines what to keep when cropping.
59
+ elsif %w[none centre center entropy attention].include?(param.downcase)
60
+ @keep[@media_presets.last] = @params.shift
59
61
 
60
- elsif param.match?(Utils::GEOMETRY_REGEX)
61
- @geometries[@media_presets.last] = @params.shift
62
+ # Aspect ratio, i.e. '16:9'
63
+ elsif param.match?(/\A\d+:\d+\z/)
64
+ @crop[@media_presets.last] = @params.shift
62
65
 
63
66
  else
64
67
  raise_error(param)
@@ -1,115 +1,57 @@
1
1
  module PictureTag
2
2
  # The rest of the application doesn't care where the instruction logic
3
- # resides. The following module 'routes' method calls to the right place, so
4
- # the rest of the application can just call 'PictureTag.(some method)'
5
-
6
- # At first I thought I'd do some sweet dynamic metaprogramming here, but it
7
- # ended up complicated and clever, rather than convenient and understandable.
8
- # This way is not strictly DRY, but it's straightforward and readable. If it
9
- # gets big, I'll refactor.
3
+ # resides. This module 'routes' method calls to the right place, so
4
+ # information consumers can just call 'PictureTag.(some method)'
5
+ #
6
+ # This is accomplished with a bit of metaprogramming, which is hopefully not
7
+ # unnecessarily clever or complicated. Missing methods are converted to class
8
+ # names, which are looked up under the Instructions module namespace.
9
+ #
10
+ # Instantiated Instructions are stored in a hash, keyed by method name.
10
11
  module Router
11
- attr_accessor :instructions, :context
12
-
13
- # Context forwarding
14
-
15
- # Global site data
16
- def site
17
- @context.registers[:site]
18
- end
19
-
20
- # Page which tag is called from
21
- def page
22
- @context.registers[:page]
23
- end
24
-
25
- # Instructions forwarding
26
-
27
- def config
28
- @instructions.config
29
- end
30
-
31
- def preset
32
- @instructions.preset
33
- end
34
-
35
- def media_presets
36
- @instructions.media_presets
37
- end
38
-
39
- def html_attributes
40
- @instructions.html_attributes
41
- end
42
-
43
- def output_class
44
- @instructions.output_class
45
- end
12
+ # These two attributes encompass everything passed in by Jekyll.
13
+ attr_accessor :raw_params, :context
46
14
 
47
- def source_images
48
- @instructions.source_images
15
+ def method_missing(method_name, *args)
16
+ if instruction_exists?(method_name)
17
+ instruction(method_name).value(*args)
18
+ else
19
+ super
20
+ end
49
21
  end
50
22
 
51
- def crop(media = nil)
52
- @instructions.crop(media)
23
+ def respond_to_missing?(method_name, *args)
24
+ instruction_exists?(method_name) || super
53
25
  end
54
26
 
55
- def gravity(media = nil)
56
- @instructions.gravity(media)
27
+ # Required at least for testing; instructions are persisted between tags
28
+ # otherwise.
29
+ def clear_instructions
30
+ instructions.clear
57
31
  end
58
32
 
59
- # Config Forwarding
60
-
61
- def source_dir
62
- config.source_dir
63
- end
64
-
65
- def dest_dir
66
- config.dest_dir
67
- end
68
-
69
- def continue_on_missing?
70
- config.continue_on_missing?
71
- end
72
-
73
- def cdn?
74
- config.cdn?
75
- end
76
-
77
- def pconfig
78
- config.pconfig
79
- end
80
-
81
- def disabled?
82
- config.disabled?
83
- end
84
-
85
- def fast_build?
86
- config.fast_build?
87
- end
88
-
89
- # Preset forwarding
90
-
91
- def widths(media)
92
- preset.widths(media)
93
- end
33
+ private
94
34
 
95
- def formats
96
- preset.formats
35
+ def instruction(method_name)
36
+ instructions[method_name] ||= instruction_class(method_name).new
97
37
  end
98
38
 
99
- def fallback_format
100
- preset.fallback_format
39
+ def instructions
40
+ @instructions ||= {}
101
41
  end
102
42
 
103
- def fallback_width
104
- preset.fallback_width
43
+ def instruction_exists?(method_name)
44
+ Object.const_defined? instruction_class_name(method_name.to_sym)
105
45
  end
106
46
 
107
- def nomarkdown?
108
- preset.nomarkdown?
47
+ # Class names can't contain question marks, so we strip them.
48
+ def instruction_class(method_name)
49
+ Object.const_get instruction_class_name(method_name)
109
50
  end
110
51
 
111
- def quality(format)
112
- preset.quality(format)
52
+ def instruction_class_name(method_name)
53
+ 'PictureTag::Instructions::' +
54
+ Utils.titleize(method_name.to_s.delete_suffix('?'))
113
55
  end
114
56
  end
115
57
  end
@@ -53,11 +53,11 @@ module PictureTag
53
53
  end
54
54
 
55
55
  def width_attribute
56
- files.first.source_width.to_s
56
+ source_image.width.to_s
57
57
  end
58
58
 
59
59
  def height_attribute
60
- files.first.source_height.to_s
60
+ source_image.height.to_s
61
61
  end
62
62
 
63
63
  private
@@ -86,11 +86,7 @@ module PictureTag
86
86
  end
87
87
 
88
88
  def source_width
89
- @source_width ||= if PictureTag.crop(@media)
90
- target_files.first.source_width
91
- else
92
- @source_image.width
93
- end
89
+ source_image.width
94
90
  end
95
91
 
96
92
  def target_files
@@ -112,9 +108,7 @@ module PictureTag
112
108
  GeneratedImage.new(
113
109
  source_file: @source_image,
114
110
  width: width,
115
- format: @input_format,
116
- crop: PictureTag.crop(@media),
117
- gravity: PictureTag.gravity(@media)
111
+ format: @input_format
118
112
  )
119
113
  end
120
114
  end
@@ -2,28 +2,10 @@ module PictureTag
2
2
  # This is a little module to hold logic that doesn't fit other places. If it
3
3
  # starts getting big, refactor.
4
4
  module Utils
5
- # These are valid ImageMagick gravity arguments (relevant to our use
6
- # case):
7
- GRAVITIES =
8
- %w[center
9
- north
10
- northeast
11
- east
12
- southeast
13
- south
14
- southwest
15
- west
16
- northwest].freeze
17
-
18
- # This is an attempt to recognize valid imagemagick geometry arguments
19
- # with regex. It only tries to match values which don't preserve aspect
20
- # ratio, as they're the ones people might actually need here.
21
- GEOMETRY_REGEX = /\A\d*%?[x:]?\d*[%!]?([+-]\d+){,2}\Z/i.freeze
22
-
23
5
  class << self
24
6
  # Configure Jekyll to keep our generated files
25
7
  def keep_files
26
- dest_dir = PictureTag.config['picture']['output']
8
+ dest_dir = PictureTag.pconfig['output']
27
9
 
28
10
  # Chop a slash off the end, if it's there. Doesn't work otherwise.
29
11
  dest_dir = dest_dir[0..-2] if dest_dir =~ %r{/\z}
@@ -35,7 +17,7 @@ module PictureTag
35
17
 
36
18
  # Print a warning to the console
37
19
  def warning(message)
38
- return if PictureTag.config['picture']['suppress_warnings']
20
+ return if PictureTag.pconfig['suppress_warnings']
39
21
 
40
22
  warn 'Jekyll Picture Tag Warning: '.yellow + message
41
23
  end
@@ -63,6 +45,28 @@ module PictureTag
63
45
  def titleize(input)
64
46
  input.split('_').map(&:capitalize).join
65
47
  end
48
+
49
+ def snakeize(input)
50
+ input.scan(/[A-Z][a-z]+/).map(&:downcase).join('_')
51
+ end
52
+
53
+ # Linear interpolator. Pass it 2 values in the x array, 2 values
54
+ # in the y array, and an x value, returns a y value.
55
+ def interpolate(xvals, yvals, xval)
56
+ xvals.map!(&:to_f)
57
+ yvals.map!(&:to_f)
58
+
59
+ # Slope
60
+ m = (yvals.last - yvals.first) / (xvals.last - xvals.first)
61
+ # Value of y when x=0
62
+ b = yvals.first - (m * xvals.first)
63
+ # y = mx + b
64
+ (m * xval) + b
65
+ end
66
+
67
+ def aspect_float(width, height)
68
+ width.to_f / height
69
+ end
66
70
  end
67
71
  end
68
72
  end
@@ -1,3 +1,3 @@
1
1
  module PictureTag
2
- VERSION = '1.11.0'.freeze
2
+ VERSION = '2.0.0'.freeze
3
3
  end
data/readme.md CHANGED
@@ -1,5 +1,9 @@
1
+ ![Logo](docs/logo.svg)
2
+
1
3
  # Jekyll Picture Tag
2
4
 
5
+ ![Tests & Formatting](https://github.com/rbuchberger/jekyll_picture_tag/workflows/Tests%20&%20Formatting/badge.svg)
6
+
3
7
  **Responsive Images done correctly.**
4
8
 
5
9
  It's simple to throw a photo on a page and call it a day, but doing justice to users on all
@@ -24,7 +28,7 @@ different image entirely.
24
28
 
25
29
  **Developer Sanity:** If you want to serve multiple images in multiple formats and resolutions, you
26
30
  have a litany of markup to write and a big pile of images to generate and organize. Jekyll Picture
27
- Tag is your responsive images minion - give it simple instructions and it'll handle the rest.
31
+ Tag is your responsive images minion - give it simple instructions and it'll handle the rest.
28
32
 
29
33
  ## Features
30
34
 
@@ -39,24 +43,22 @@ https://rbuchberger.github.io/jekyll_picture_tag/
39
43
 
40
44
  ## Changelog:
41
45
 
42
- https://rbuchberger.github.io/jekyll_picture_tag/releases
46
+ https://rbuchberger.github.io/jekyll_picture_tag/devs/releases
43
47
 
44
- Latest versions:
48
+ Recent releases:
45
49
 
46
- * 1.10.1 July 2, 2020
47
- * Bugfix for erroneously regenerated images
48
- * 1.10.2 July 6, 2020
49
- * Bugfix for fallback image files not actually getting generated
50
- * 1.11.0 July 27, 2020
51
- * **Width and height attribute support!** Begone, page reflow.
52
- * Cache image information between builds
53
- * Change image naming format. This update will trigger all images to be regenerated, so you may
54
- want to delete your generated images folder beforehand.
50
+ * 1.14.0 January 10, 2021
51
+ * Gracefully handle empty tag arguments.
52
+ * Re-add metadata stripping. I removed it inadvertently when refactoring; now
53
+ there's a test and a setting to turn it off.
54
+ * Respect Jekyll's `--disable-disk-cache` argument.
55
+ * Add baseurl configuration, allowing increased plugin support (such as I18n via `jekyll-multiple-languages-plugin`)
56
+ * Tooling & test suite maintenance and improvements.
55
57
 
56
58
  ## Help Wanted
57
59
 
58
60
  Writing code is only part of the job; often the harder part is knowing what needs to be changed. Any
59
61
  and all feedback is greatly appreciated, especially in regards to documentation. What are your pain
60
62
  points? See the [contributing
61
- guidelines](https://rbuchberger.github.io/jekyll_picture_tag/contributing), or the
63
+ guidelines](https://rbuchberger.github.io/jekyll_picture_tag/devs/contributing), or the
62
64
  [issues](https://github.com/rbuchberger/jekyll_picture_tag/issues) page for more.