jekyll_picture_tag 1.6.0 → 1.7.0

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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -0
  3. data/.travis.yml +11 -0
  4. data/Gemfile +2 -2
  5. data/Rakefile +28 -0
  6. data/contributing.md +67 -0
  7. data/docs/examples/_config.yml +10 -0
  8. data/{examples → docs/examples}/_data/picture.yml +39 -19
  9. data/docs/examples/post.md +46 -0
  10. data/docs/global_configuration.md +115 -0
  11. data/docs/installation.md +30 -0
  12. data/docs/migration.md +178 -0
  13. data/docs/notes.md +85 -0
  14. data/docs/presets.md +407 -0
  15. data/docs/readme.md +23 -0
  16. data/docs/usage.md +131 -0
  17. data/jekyll-picture-tag.gemspec +3 -12
  18. data/jekyll_picture_tag.gemspec +8 -3
  19. data/lib/jekyll-picture-tag.rb +5 -3
  20. data/lib/jekyll_picture_tag.rb +45 -42
  21. data/lib/jekyll_picture_tag/defaults/global.yml +0 -3
  22. data/lib/jekyll_picture_tag/defaults/presets.yml +1 -0
  23. data/lib/jekyll_picture_tag/generated_image.rb +60 -39
  24. data/lib/jekyll_picture_tag/img_uri.rb +55 -0
  25. data/lib/jekyll_picture_tag/instructions.rb +1 -102
  26. data/lib/jekyll_picture_tag/instructions/configuration.rb +30 -74
  27. data/lib/jekyll_picture_tag/instructions/html_attributes.rb +18 -27
  28. data/lib/jekyll_picture_tag/instructions/preset.rb +14 -3
  29. data/lib/jekyll_picture_tag/instructions/set.rb +61 -0
  30. data/lib/jekyll_picture_tag/instructions/tag_parser.rb +80 -23
  31. data/lib/jekyll_picture_tag/output_formats.rb +1 -1
  32. data/lib/jekyll_picture_tag/output_formats/{basics.rb → basic.rb} +24 -19
  33. data/lib/jekyll_picture_tag/output_formats/data_attributes.rb +2 -2
  34. data/lib/jekyll_picture_tag/output_formats/direct_url.rb +1 -3
  35. data/lib/jekyll_picture_tag/output_formats/img.rb +4 -4
  36. data/lib/jekyll_picture_tag/output_formats/naked_srcset.rb +5 -4
  37. data/lib/jekyll_picture_tag/output_formats/picture.rb +6 -16
  38. data/lib/jekyll_picture_tag/output_formats/readme.md +8 -15
  39. data/lib/jekyll_picture_tag/router.rb +98 -0
  40. data/lib/jekyll_picture_tag/source_image.rb +15 -23
  41. data/lib/jekyll_picture_tag/srcsets.rb +1 -1
  42. data/lib/jekyll_picture_tag/srcsets/{basics.rb → basic.rb} +22 -13
  43. data/lib/jekyll_picture_tag/srcsets/pixel_ratio.rb +6 -11
  44. data/lib/jekyll_picture_tag/srcsets/width.rb +3 -11
  45. data/lib/jekyll_picture_tag/utils.rb +32 -49
  46. data/lib/jekyll_picture_tag/version.rb +1 -1
  47. data/readme.md +70 -70
  48. metadata +97 -16
  49. data/bin/console +0 -14
  50. data/bin/setup +0 -7
  51. data/examples/_config.yml +0 -4
  52. data/examples/post.md +0 -18
@@ -0,0 +1,55 @@
1
+ require 'addressable'
2
+
3
+ module PictureTag
4
+ # Represents a link to an image. We use the File library rather than the URI
5
+ # library to build these because it doesn't like relative URIs.
6
+ #
7
+ # Just give it a filename, and pass source_image: true if it's not a generated
8
+ # image. Call to_s on it to get the link.
9
+ class ImgURI
10
+ attr_reader :filename, :source_image
11
+ def initialize(filename, source_image: false)
12
+ @source_image = source_image
13
+ @filename = filename
14
+ end
15
+
16
+ # https://example.com/my-base-path/assets/generated-images/image.jpg
17
+ # | domain | baseurl | directory | filename
18
+ def to_s
19
+ Addressable::URI.escape(
20
+ File.join(domain, baseurl, directory, @filename)
21
+ )
22
+ end
23
+
24
+ private
25
+
26
+ # https://example.com/my-base-path/assets/generated-images/image.jpg
27
+ # ^^^^^^^^^^^^^^^^^^^^
28
+ # | domain | baseurl | j-p-t output dir | filename
29
+ def domain
30
+ if PictureTag.cdn?
31
+ PictureTag.pconfig['cdn_url']
32
+ elsif PictureTag.pconfig['relative_url']
33
+ ''
34
+ else
35
+ PictureTag.config['url'] || ''
36
+ end
37
+ end
38
+
39
+ # https://example.com/my-base-path/assets/generated-images/image.jpg
40
+ # ^^^^^^^^^^^^^
41
+ # | domain | baseurl | directory | filename
42
+ def baseurl
43
+ PictureTag.config['baseurl'] || ''
44
+ end
45
+
46
+ # https://example.com/my-base-path/assets/generated-images/image.jpg
47
+ # ^^^^^^^^^^^^^^^^^^^^^^^^
48
+ # | domain | baseurl | directory | filename
49
+ def directory
50
+ PictureTag.pconfig[
51
+ @source_image ? 'source' : 'output'
52
+ ]
53
+ end
54
+ end
55
+ end
@@ -1,106 +1,5 @@
1
+ require_relative './instructions/set'
1
2
  require_relative './instructions/configuration'
2
3
  require_relative './instructions/html_attributes'
3
4
  require_relative './instructions/preset'
4
5
  require_relative './instructions/tag_parser'
5
-
6
- # Allows us to access settings as methods on PictureTag itself.
7
- module PictureTag
8
- class << self
9
- attr_reader :context, :config, :params, :preset, :html_attributes
10
-
11
- def init(raw_tag_params, context)
12
- @context = context
13
-
14
- # Create global config (big picture). Config class loads jekyll
15
- # data/config files, and the j-p-t defaults from included yml files.
16
- @config = Instructions::Configuration.new
17
-
18
- # Parse tag params. We must do this before setting the preset, because
19
- # it's one of the params.
20
- @params = Instructions::TagParser.new(raw_tag_params)
21
-
22
- # Create preset. Takes preset name from params, merges associated settings
23
- # with default values.
24
- @preset = Instructions::Preset.new
25
-
26
- # Create HTML attributes. Depends on both the preset and tag params, so
27
- # we must do this after creating both.
28
- @html_attributes = Instructions::HTMLAttributeSet.new(
29
- @params.html_attributes_raw
30
- )
31
-
32
- # Keep our generated files
33
- Utils.keep_files
34
- end
35
-
36
- # Global site data
37
- def site
38
- @context.registers[:site]
39
- end
40
-
41
- # Page which tag is called from
42
- def page
43
- @context.registers[:page]
44
- end
45
-
46
- # Media query presets. It's really just a hash, and there are no default
47
- # values, so extracting it to its own class is overkill.
48
- def media_presets
49
- site.data.dig('picture', 'media_presets') || {}
50
- end
51
-
52
- # The rest of the application doesn't care where the instruction logic
53
- # resides. For example, I don't want to use PictureTag.config.source_dir and
54
- # PictureTag.params.source_images, I just want to use PictureTag.source_dir
55
- # and PictureTag.source_images. The following method definitions accomplish
56
- # that.
57
-
58
- # At first I thought I'd do some sweet dynamic metaprogramming here, but it
59
- # ended up more complicated and clever than convenient. This way is not
60
- # strictly DRY, but it's understandable and readable.
61
-
62
- # Config Forwarding
63
- def source_dir
64
- @config.source_dir
65
- end
66
-
67
- def dest_dir
68
- @config.dest_dir
69
- end
70
-
71
- def build_url(filename)
72
- @config.build_url(filename)
73
- end
74
-
75
- def build_source_url(filename)
76
- @config.build_source_url(filename)
77
- end
78
-
79
- # Preset forwarding
80
- def widths(media)
81
- @preset.widths(media)
82
- end
83
-
84
- def fallback_format
85
- @preset.fallback_format
86
- end
87
-
88
- def fallback_width
89
- @preset.fallback_width
90
- end
91
-
92
- def nomarkdown?
93
- @preset.nomarkdown?
94
- end
95
-
96
-
97
- # Params forwarding
98
- def preset_name
99
- @params.preset_name
100
- end
101
-
102
- def source_images
103
- @params.source_images
104
- end
105
- end
106
- end
@@ -3,12 +3,14 @@ module PictureTag
3
3
  # Global config (big picture). loads jekyll data/config files, and the j-p-t
4
4
  # defaults from included yml files.
5
5
  class Configuration
6
- def initialize
7
- @content = build_config
6
+ # returns jekyll's configuration (picture is a subset)
7
+ def [](key)
8
+ content[key]
8
9
  end
9
10
 
10
- def [](key)
11
- @content[key]
11
+ # picturetag specific configuration
12
+ def pconfig
13
+ content['picture']
12
14
  end
13
15
 
14
16
  # Digs into jekyll context, returns current environment
@@ -21,38 +23,22 @@ module PictureTag
21
23
  # Site.source is the master jekyll source directory
22
24
  # Source dir is the jekyll-picture-tag source directory.
23
25
  def source_dir
24
- File.join PictureTag.site.source, self['picture']['source']
26
+ File.join PictureTag.site.source, pconfig['source']
25
27
  end
26
28
 
27
29
  # site.dest is the master jekyll destination directory
28
30
  # source_dest is the jekyll-picture-tag destination directory. (generated
29
31
  # file location setting.)
30
32
  def dest_dir
31
- File.join PictureTag.site.dest, self['picture']['output']
32
- end
33
-
34
- # Generated images, not source images.
35
- # https://example.com/my-base-path/assets/generated-images/image.jpg
36
- # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
37
- # | domain | baseurl | j-p-t output dir | filename
38
- def build_url(filename)
39
- File.join url_prefix, self['picture']['output'], filename
40
- end
41
-
42
- # For linking source images
43
- # https://example.com/my-base-path/assets/source-images/image.jpg
44
- # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
45
- # | domain | baseurl | j-p-t source dir | filename
46
- def build_source_url(filename)
47
- File.join url_prefix, self['picture']['source'], filename
33
+ File.join PictureTag.site.dest, pconfig['output']
48
34
  end
49
35
 
50
36
  def nomarkdown?
51
- Utils.markdown_page? && self['picture']['nomarkdown']
37
+ Utils.markdown_page? && pconfig['nomarkdown']
52
38
  end
53
39
 
54
40
  def continue_on_missing?
55
- setting = @content['picture']['ignore_missing_images']
41
+ setting = pconfig['ignore_missing_images']
56
42
 
57
43
  # Config setting can be a string, an array, or a boolean
58
44
  if setting.is_a? Array
@@ -64,64 +50,34 @@ module PictureTag
64
50
  end
65
51
  end
66
52
 
67
- private
68
-
69
- def build_config
70
- YAML.safe_load(
71
- # Jekyll Picture Tag Default settings
72
- File.read(
73
- File.join(ROOT_PATH, 'jekyll_picture_tag/defaults/global.yml')
74
- )
75
- ).merge(
76
- # _config.yml defined settings
77
- PictureTag.site.config
78
- ) do |_key, jpt_default, site_value|
79
- setting_merge(jpt_default, site_value)
80
- end
53
+ def cdn?
54
+ pconfig['cdn_url'] && pconfig['cdn_environments'].include?(jekyll_env)
81
55
  end
82
56
 
83
- def setting_merge(jpt_default, site_value)
84
- if site_value.nil?
85
- # Jekyll baseurl is nil if not configured, which breaks things.
86
- # jpt_default is an empty string, which doesn't.
87
- jpt_default
88
- elsif site_value.is_a? Hash
89
- # We'll merge hashes one level deep. If we need true deep merging,
90
- # we'll import a gem or do something recursive.
91
- jpt_default.merge site_value
92
- else
93
- site_value
94
- end
95
- end
57
+ private
96
58
 
97
- # Juuust complicated enough to extract to its own function.
98
- def cdn?
99
- self['picture']['cdn_url'] &&
100
- self['picture']['cdn_environments'].include?(jekyll_env)
59
+ def content
60
+ @content ||= setting_merge(defaults, PictureTag.site.config)
101
61
  end
102
62
 
103
- # https://example.com/my-base-path/assets/generated-images/image.jpg
104
- # ^^^^^^^^^^^^^^^^^^^^
105
- # | domain | baseurl | j-p-t output dir | filename
106
- def domain
107
- if cdn?
108
- self['picture']['cdn_url']
109
- elsif self['picture']['relative_url']
110
- ''
111
- else
112
- self['url']
63
+ def setting_merge(default, jekyll)
64
+ jekyll.merge default do |_key, config_setting, default_setting|
65
+ if default_setting.respond_to? :merge
66
+ setting_merge(default_setting, config_setting)
67
+ else
68
+ config_setting
69
+ end
113
70
  end
114
71
  end
115
72
 
116
- # https://example.com/my-base-path/assets/generated-images/image.jpg
117
- # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
118
- # | domain | baseurl | j-p-t output dir | filename
119
- def url_prefix
120
- # We use file.join because the ruby url methods don't like relative
121
- # urls.
122
- File.join(
123
- domain,
124
- self['baseurl']
73
+ def defaults
74
+ # Jekyll Picture Tag Default settings
75
+ YAML.safe_load(
76
+ File.read(
77
+ File.join(
78
+ ROOT_PATH, 'jekyll_picture_tag/defaults/global.yml'
79
+ )
80
+ )
125
81
  )
126
82
  end
127
83
  end
@@ -9,7 +9,7 @@ module PictureTag
9
9
  @content = load_preset
10
10
 
11
11
  parse_params(params) if params
12
- handle_url
12
+ handle_source_url
13
13
  end
14
14
 
15
15
  def [](key)
@@ -24,35 +24,26 @@ module PictureTag
24
24
 
25
25
  # Syntax this function processes:
26
26
  # class="old way" --picture class="new way" --alt Here's my alt text
27
- def parse_params(params)
28
- params_array = params.split(/\s+--/).map(&:strip)
29
-
30
- # This allows the old tag syntax to work.
31
- @content['implicit'] = params_array.shift unless params.strip =~ /^--/
27
+ def parse_params(words)
28
+ key = 'implicit'
29
+
30
+ words.each do |word|
31
+ if word.match(/^--/)
32
+ key = word.delete_prefix('--')
33
+ elsif @content[key]
34
+ @content[key] << ' ' + word
35
+ else
36
+ @content[key] = word
37
+ end
38
+ end
39
+ end
32
40
 
33
- # Split function above doesn't take the dashes off the first param.
34
- params_array.first.delete_prefix! '--' if params_array.any?
41
+ def handle_source_url
42
+ return unless PictureTag.preset['link_source'] && self['link'].nil?
35
43
 
36
- params_array.each do |param|
37
- # Splits on spaces, the first word will be our key.
38
- a = param.split
44
+ target = PictureTag.source_images.first.shortname
39
45
 
40
- # Supplied tag arguments will overwrite (not append) configured values
41
- @content[a.shift] = a.join(' ')
42
- end
43
- end
44
- # Handles anchor tag destination. Can come from 2 places in 2 formats:
45
- # Can come from defaults, preset, or tag
46
- # Default is false. Preset can specify either true or false
47
- # Tag params can be a URL
48
-
49
- # picture test.jpg --url http://example.com
50
- def handle_url
51
- return unless PictureTag.preset['link_source'] && !self['link']
52
-
53
- @content['link'] = PictureTag.build_source_url(
54
- Utils.biggest_source.shortname
55
- )
46
+ @content['link'] = ImgURI.new(target, source_image: true).to_s
56
47
  end
57
48
  end
58
49
  end
@@ -3,8 +3,8 @@ module PictureTag
3
3
  # Handles the specific tag image set to construct.
4
4
  class Preset
5
5
  attr_reader :name
6
- def initialize
7
- @name = PictureTag.preset_name
6
+ def initialize(name)
7
+ @name = name
8
8
  @content = build_preset
9
9
  end
10
10
 
@@ -19,8 +19,12 @@ module PictureTag
19
19
  width_hash[media]
20
20
  end
21
21
 
22
+ def formats
23
+ @content['formats']
24
+ end
25
+
22
26
  def fallback_format
23
- PictureTag::Utils.process_format(@content['fallback_format'], nil)
27
+ @content['fallback_format']
24
28
  end
25
29
 
26
30
  def fallback_width
@@ -37,6 +41,13 @@ module PictureTag
37
41
  end
38
42
  end
39
43
 
44
+ def quality(format = nil)
45
+ qualities = @content['format_quality'] || {}
46
+ qualities.default = @content['quality']
47
+
48
+ qualities[format]
49
+ end
50
+
40
51
  private
41
52
 
42
53
  def build_preset
@@ -0,0 +1,61 @@
1
+ module PictureTag
2
+ module Instructions
3
+ # Supervisor class, which manages all input handling and high level decision
4
+ # making which depends on it.
5
+ class Set
6
+ def initialize(raw_tag_params)
7
+ @raw_tag_params = raw_tag_params
8
+ end
9
+
10
+ def config
11
+ @config ||= Configuration.new
12
+ end
13
+
14
+ def params
15
+ @params ||= TagParser.new @raw_tag_params
16
+ end
17
+
18
+ def preset
19
+ @preset ||= Preset.new params.preset_name
20
+ end
21
+
22
+ def html_attributes
23
+ # Depends on both the preset and tag params.
24
+ @html_attributes ||= HTMLAttributeSet.new params.leftovers
25
+ end
26
+
27
+ # These are our Media Query presets. It's really just a hash, and there
28
+ # are no default values, so extracting this to its own class is overkill.
29
+ def media_presets
30
+ PictureTag.site.data.dig('picture', 'media_presets') || {}
31
+ end
32
+
33
+ def source_images
34
+ @source_images ||= build_source_images
35
+ end
36
+
37
+ def build_source_images
38
+ source_names = params.source_names
39
+ media_presets = params.media_presets
40
+
41
+ sources = [SourceImage.new(source_names.shift)]
42
+
43
+ while params.source_names.any?
44
+ sources << SourceImage.new(
45
+ source_names.shift, media_presets.shift
46
+ )
47
+ end
48
+
49
+ sources
50
+ end
51
+
52
+ # Returns a class constant for the selected output format, which is used
53
+ # to dynamically instantiate it.
54
+ def output_class
55
+ Object.const_get(
56
+ 'PictureTag::OutputFormats::' + Utils.titleize(preset['markup'])
57
+ )
58
+ end
59
+ end
60
+ end
61
+ end