jekyll_picture_tag 1.6.0 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
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