image_processing 1.2.0 → 1.12.1

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.

Potentially problematic release.


This version of image_processing might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 39c52030a178edeef33439eb70807d86935b1e05bbf250d0f30aa9a4947f6dea
4
- data.tar.gz: 60c936577febb87380de300024a8f4517ae9dafed394d74fe7b0f78ab04efd7f
3
+ metadata.gz: ec4b4776480756b2721185419de81f228e5ca927b4bd3077fb4c0a5dcafef15f
4
+ data.tar.gz: d40b8822b6a7b2b5e1bad182099f7e3b23b25d0cdd6b61b1afa3154b665e76a6
5
5
  SHA512:
6
- metadata.gz: 9bc68c91084d44b3052a47ac332d21840965537163b541ef09cd662d729c26e152b3e588f97fd954a13aaae0a5a645be86389a79308de4eee154feb7fed95baa
7
- data.tar.gz: 4c026c8eb9cc4dfa537ef3f0f86b460a8dc0a13134fe441604483b6a4b1afd1048911b499673807fac82f7a15c37773e27fad1dd2d049f8e8adedd5204166923
6
+ metadata.gz: 77cff245646f56f409d4c1d006d26cee819d11cc9c263b88d86bafb6e480ac691240bfa17542bf9c578891056355d53f63fefddfa1f3eb801e3ddeea20666ae3
7
+ data.tar.gz: bf3f39c4204d7dcbb6382596a4a8850f8c7d22fee94e8ed77a1782a58bd1f370448268bb4e74028e429ee2e7c6156613b1022f5465faf6d30ab01833751c4df9
data/CHANGELOG.md CHANGED
@@ -1,112 +1,204 @@
1
+ ## 1.12.1 (2020-11-06)
2
+
3
+ * Fix format fallback for files ending with a dot on Ruby 2.7+ (@coding-chimp)
4
+
5
+ ## 1.12.0 (2020-09-20)
6
+
7
+ * Add instrumentation support via `#instrumenter` (@janko)
8
+
9
+ ## 1.11.0 (2020-05-17)
10
+
11
+ * [minimagick] Handle destination format having no file extension (@janko)
12
+
13
+ * [minimagick] Disable sharpening on `#resize_*` operators by default (@flori)
14
+
15
+ * [minimagick] Add `#crop` which accepts `left, top, width, height` arguments (@janko)
16
+
17
+ ## 1.10.3 (2020-01-12)
18
+
19
+ * [vips] Fix auto-rotation not working in certain cases on libvips 8.9.0 (@janko)
20
+
21
+ ## 1.10.2 (2020-01-11)
22
+
23
+ * Fix Ruby 2.7 warnings for separation of positional and keyword arguments (@kamipo, @janko)
24
+
25
+ ## 1.10.1 (2020-01-07)
26
+
27
+ * [vips] Fix compatibility with ruby-vips 2.0.17+ (@janko)
28
+
29
+ ## 1.10.0 (2019-12-18)
30
+
31
+ * [minimagick] Add `:loader` option for explicitly setting input file type (@janko)
32
+
33
+ ## 1.9.3 (2019-08-11)
34
+
35
+ * [vips] Use integer precision when sharpening for better quality (@metaskills)
36
+
37
+ ## 1.9.2 (2019-07-22)
38
+
39
+ * Bump `mini_magick` dependency to `>= 4.9.5` (@chioreandan)
40
+
41
+ ## 1.9.1 (2019-07-20)
42
+
43
+ * Bring back support for MRI 2.3 (@janko)
44
+
45
+ ## 1.9.0 (2019-04-09)
46
+
47
+ * Drop support for MRI 2.2 and 2.3 (@janko)
48
+
49
+ * [vips] Allow forcing a specific loader or saver (@janko)
50
+
51
+ ## 1.8.0 (2019-02-25)
52
+
53
+ * [vips] Perform resize-on-load when possible, significantly improving resizing speed (@janko)
54
+
55
+ ## 1.7.1 (2018-09-27)
56
+
57
+ * [vips] Make `#remove` that's used for removing image metadata chainable (@janko)
58
+
59
+ ## 1.7.0 (2018-09-20)
60
+
61
+ * [vips] `#rotate` now always calls `vips_similarity()` and forwards all options to it (@janko)
62
+
63
+ ## 1.6.0 (2018-07-13)
64
+
65
+ * [vips] In `#composite` accept `:offset` option for the position of the overlay image (@janko)
66
+
67
+ * [vips] In `#composite` accept `:gravity` option for the direction of the overlay image (@janko)
68
+
69
+ * [vips] In `#composite` accept blend mode as an optional `:mode` parameter which defaults to `:over` (@janko)
70
+
71
+ * [minimagick] In `#composite` rename `:compose` option to `:mode` (@janko)
72
+
73
+ * [minimagick] In `#composite` replace `:geometry` option with `:offset` which accepts an array (@janko)
74
+
75
+ ## 1.5.0 (2018-07-10)
76
+
77
+ * [minimagick, vips] Add `#composite` method (@janko)
78
+
79
+ * [core] Allow operations to accept blocks (janko-m)
80
+
81
+ ## 1.4.0 (2018-06-14)
82
+
83
+ * [minimagick] Accept RGB(A) arrays for color names for `:background` (@janko)
84
+
85
+ * [minimagick] Don't add empty `-background` option in `#rotate` when `:background` is not given (@janko)
86
+
87
+ * [vips] Modify `#rotate` to accept only `:background` and not other `vips_similarity()` options (@janko)
88
+
89
+ ## 1.3.0 (2018-06-13)
90
+
91
+ * [minimagick, vips] Add `#rotate` method (@janko)
92
+
93
+ * [vips] Use native `vips_image_hasalpha()` and `vips_addalpha()` functions in `#resize_and_pad` (@janko)
94
+
1
95
  ## 1.2.0 (2018-04-18)
2
96
 
3
- * [minimagick] Allow appending "+" operators in `#loader` and `#saver` using the value `false` (@janko-m)
97
+ * [minimagick] Allow appending "+" operators in `#loader` and `#saver` using the value `false` (@janko)
4
98
 
5
- * [core] Fix `#apply` not accepting a Hash as an argument (@janko-m)
99
+ * [core] Fix `#apply` not accepting a Hash as an argument (@janko)
6
100
 
7
- * [core] Allow sending any builder commands via `#apply`, not just operations (@janko-m)
101
+ * [core] Allow sending any builder commands via `#apply`, not just operations (@janko)
8
102
 
9
- * [minimagick] Add `#define` as a wrapper around `-define` (@janko-m)
103
+ * [minimagick] Add `#define` as a wrapper around `-define` (@janko)
10
104
 
11
105
  ## 1.1.0 (2018-04-05)
12
106
 
13
107
  * [minimagick] Disallow splitting multi-layer images into multiple single-layer
14
108
  images by default to avoid unexpected behaviour, but can be re-enabled with
15
- the `:allow_splitting` saver option (@janko-m)
109
+ the `:allow_splitting` saver option (@janko)
16
110
 
17
- * [core] Add `#apply` for applying a list of operations (@janko-m)
111
+ * [core] Add `#apply` for applying a list of operations (@janko)
18
112
 
19
113
  ## 1.0.0 (2018-04-04)
20
114
 
21
- * Depend on `mini_magick` and `ruby-vips` gems (@janko-m, @mokolabs)
115
+ * Depend on `mini_magick` and `ruby-vips` gems (@janko, @mokolabs)
22
116
 
23
- * [minimagick] Remove deprecated API in favor of the chainable API (@janko-m)
117
+ * [minimagick] Remove deprecated API in favor of the chainable API (@janko)
24
118
 
25
- * [core] Rename `Builder#default_options` to `Builder#options` (@janko-m)
119
+ * [core] Rename `Builder#default_options` to `Builder#options` (@janko)
26
120
 
27
- * [minimagick] Remove `:fail` loader option in favor of the existing `:regard_warnings` (@janko-m)
121
+ * [minimagick] Remove `:fail` loader option in favor of the existing `:regard_warnings` (@janko)
28
122
 
29
- * [vips, minimagick] Don't fail on warnings when loading the image (@janko-m)
123
+ * [vips, minimagick] Don't fail on warnings when loading the image (@janko)
30
124
 
31
- * [vips] Don't apply `Vips::Image#autorot` if `:autorotate` loader option was passed in (@janko-m)
125
+ * [vips] Don't apply `Vips::Image#autorot` if `:autorotate` loader option was passed in (@janko)
32
126
 
33
- * [minimagick] Allow using value `nil` to add ImageMagick options that don't have a value (@janko-m)
127
+ * [minimagick] Allow using value `nil` to add ImageMagick options that don't have a value (@janko)
34
128
 
35
- * [vips] Accept `:quality` saver option as an alias to `:Q` (@janko-m)
129
+ * [vips] Accept `:quality` saver option as an alias to `:Q` (@janko)
36
130
 
37
- * [minimagick] Automatically sharpen thumbnails after resizing (@janko-m, @mokolabs)
131
+ * [minimagick] Automatically sharpen thumbnails after resizing (@janko, @mokolabs)
38
132
 
39
- * [vips] Automatically sharpen thumbnails after resizing (@janko-m, @mokolabs)
133
+ * [vips] Automatically sharpen thumbnails after resizing (@janko, @mokolabs)
40
134
 
41
135
  ## 0.11.2 (2018-03-31)
42
136
 
43
- * [minimagick] Avoid `#resize_*` operations stripping data by switching back to `-resize` (@janko-m)
44
-
45
- * [core] Make sure an empty destination file doesn't remain on processing errors when `:destination` is used (@janko-m)
137
+ * [minimagick] Avoid `#resize_*` operations stripping data by switching back to `-resize` (@janko)
46
138
 
47
- * [vips] Fix `:alpha` not correctly adding alpha for certain types of images (@janko-m)
139
+ * [core] Make sure an empty destination file doesn't remain on processing errors when `:destination` is used (@janko)
48
140
 
49
- * [minimagick] Drop official support for GraphicsMagick (@janko-m)
141
+ * [vips] Fix `:alpha` not correctly adding alpha for certain types of images (@janko)
50
142
 
51
143
  ## 0.11.1 (2018-03-27)
52
144
 
53
- * [minimagick] Rename `#limit` to `#limits` to still allow adding `-limit` arguments directly (@janko-m)
145
+ * [minimagick] Rename `#limit` to `#limits` to still allow adding `-limit` arguments directly (@janko)
54
146
 
55
147
  ## 0.11.0 (2018-03-27)
56
148
 
57
- * [minimagick] Fix broken deprecated `#convert` (@janko-m)
149
+ * [minimagick] Fix broken deprecated `#convert` (@janko)
58
150
 
59
- * [minimagick] Add `#limit` for specifying resource limits using `-limit` (@janko-m)
151
+ * [minimagick] Add `#limit` for specifying resource limits using `-limit` (@janko)
60
152
 
61
- * [minimagick] Use `-thumbnail` instead of `-resize` in `#resize_*` methods (@janko-m)
153
+ * [minimagick] Use `-thumbnail` instead of `-resize` in `#resize_*` methods (@janko)
62
154
 
63
- * [minimagick] Add loader and saver options (@janko-m)
155
+ * [minimagick] Add loader and saver options (@janko)
64
156
 
65
157
  ## 0.10.3 (2018-03-24)
66
158
 
67
- * [minimagick] Fix bang methods in deprecated API calling nondestructive versions (@janko-m)
159
+ * [minimagick] Fix bang methods in deprecated API calling nondestructive versions (@janko)
68
160
 
69
161
  ## 0.10.2 (2018-03-22)
70
162
 
71
- * [minimagick] Add back default offset arguments to deprecated `#crop` (@janko-m)
163
+ * [minimagick] Add back default offset arguments to deprecated `#crop` (@janko)
72
164
 
73
165
  ## 0.10.1 (2018-03-22)
74
166
 
75
- * [minimagick] Don't print deprecation warning for old API twice when IO objects are used (@janko-m)
167
+ * [minimagick] Don't print deprecation warning for old API twice when IO objects are used (@janko)
76
168
 
77
169
  ## 0.10.0 (2018-03-21)
78
170
 
79
- * [minimagick] Rewrite MiniMagick module to use the chainable API (@janko-m)
171
+ * [minimagick] Rewrite MiniMagick module to use the chainable API (@janko)
80
172
 
81
- * [minimagick] Deprecate the old API (@janko-m)
173
+ * [minimagick] Deprecate the old API (@janko)
82
174
 
83
- * [minimagick] Raise an exception on processing warnings (@janko-m)
175
+ * [minimagick] Raise an exception on processing warnings (@janko)
84
176
 
85
- * [minimagick] Speed up `.valid_image?` by an order of magnitude (@janko-m)
177
+ * [minimagick] Speed up `.valid_image?` by an order of magnitude (@janko)
86
178
 
87
- * [minimagick] Don't accept arbitrary IO object anymore (@janko-m)
179
+ * [minimagick] Don't accept arbitrary IO object anymore (@janko)
88
180
 
89
- * [minimagick] Removed unnecessary `#crop` and `#resample` macros (@janko-m)
181
+ * [minimagick] Removed unnecessary `#crop` and `#resample` macros (@janko)
90
182
 
91
- * [vips] Ignore undefined loader/saver options (@janko-m)
183
+ * [vips] Ignore undefined loader/saver options (@janko)
92
184
 
93
- * [vips] Preserve transparent background in `#resize_to_pad` (@janko-m)
185
+ * [vips] Preserve transparent background in `#resize_to_pad` (@janko)
94
186
 
95
- * [vips] Remove the ability to specify colors using names (@janko-m)
187
+ * [vips] Remove the ability to specify colors using names (@janko)
96
188
 
97
- * [minimagick, vips] Autorotate images after loading them (@janko-m)
189
+ * [minimagick, vips] Autorotate images after loading them (@janko)
98
190
 
99
- * [core] Delete result `Tempfile` object in case of processing errors (@janko-m)
191
+ * [core] Delete result `Tempfile` object in case of processing errors (@janko)
100
192
 
101
- * [core] Allow returning `nil` in the `#custom` block (@janko-m)
193
+ * [core] Allow returning `nil` in the `#custom` block (@janko)
102
194
 
103
- * [core] Allow specifying a path string as source file (@janko-m)
195
+ * [core] Allow specifying a path string as source file (@janko)
104
196
 
105
- * [core] Allow saving to a specific location with the `:destination` call option (@janko-m)
197
+ * [core] Allow saving to a specific location with the `:destination` call option (@janko)
106
198
 
107
199
  ## 0.9.0 (2018-03-16)
108
200
 
109
- * Added libvips module (@GustavoCaso, @janko-m)
201
+ * Added libvips module (@GustavoCaso, @janko)
110
202
 
111
203
  * Drop official support for MRI 2.0 and 2.1
112
204
 
@@ -116,15 +208,15 @@
116
208
 
117
209
  ## 0.4.4 (2017-06-16)
118
210
 
119
- * Fix last changes being incompatible with older Ruby versions, again (@janko-m)
211
+ * Fix last changes being incompatible with older Ruby versions, again (@janko)
120
212
 
121
213
  ## 0.4.3 (2017-06-16)
122
214
 
123
- * Fix last changes being incompatible with older Ruby versions (@janko-m)
215
+ * Fix last changes being incompatible with older Ruby versions (@janko)
124
216
 
125
217
  ## 0.4.2 (2017-06-16)
126
218
 
127
- * Don't use path of input file as basename for output file (@janko-m)
219
+ * Don't use path of input file as basename for output file (@janko)
128
220
 
129
221
  ## 0.4.1 (2016-09-08)
130
222
 
data/README.md CHANGED
@@ -3,11 +3,11 @@
3
3
  Provides higher-level image processing helpers that are commonly needed
4
4
  when handling image uploads.
5
5
 
6
- This gem can process images with either [ImageMagick] or [libvips] libraries.
7
- ImageMagick is a good default choice, especially if you are migrating from
8
- another gem or library that uses ImageMagick. Libvips is a newer library that
9
- can process images [very rapidly][libvips performance] (up to 10x faster than
10
- ImageMagick).
6
+ This gem can process images with either [ImageMagick]/[GraphicsMagick] or
7
+ [libvips] libraries. ImageMagick is a good default choice, especially if you
8
+ are migrating from another gem or library that uses ImageMagick. Libvips is a
9
+ newer library that can process images [very rapidly][libvips performance]
10
+ (often multiple times faster than ImageMagick).
11
11
 
12
12
 
13
13
  ## Goal
@@ -42,9 +42,9 @@ how to resize and process images.
42
42
 
43
43
  ## Usage
44
44
 
45
- Processing is performed through [`ImageProcessing::Vips`] or
46
- [`ImageProcessing::MiniMagick`] modules. Both modules share the same chainable
47
- API for defining the processing pipeline:
45
+ Processing is performed through **[`ImageProcessing::Vips`]** or
46
+ **[`ImageProcessing::MiniMagick`]** modules. Both modules share the same
47
+ chainable API for defining the processing pipeline:
48
48
 
49
49
  ```rb
50
50
  require "image_processing/mini_magick"
@@ -117,7 +117,8 @@ pipeline.options
117
117
  ```
118
118
 
119
119
  The source object needs to responds to `#path`, or be a String, a Pathname, or
120
- a `Vips::Image`/`MiniMagick::Tool` object.
120
+ a `Vips::Image`/`MiniMagick::Tool` object. Note that the processed file is
121
+ always saved to a new location, in-place processing is not supported.
121
122
 
122
123
  ```rb
123
124
  ImageProcessing::Vips.source(File.open("source.jpg"))
@@ -144,8 +145,37 @@ You can continue reading the API documentation for specific modules:
144
145
  * **[`ImageProcessing::Vips`]**
145
146
  * **[`ImageProcessing::MiniMagick`]**
146
147
 
147
- See the **[wiki]** for additional "How To" guides for common scenarios.
148
+ See the **[wiki]** for additional "How To" guides for common scenarios. The wiki
149
+ is publicly editable, so you're encouraged to add your own guides.
148
150
 
151
+ ## Instrumentation
152
+
153
+ You can register an `#instrumenter` block for a given pipeline, which will wrap
154
+ the pipeline execution, allowing you to record performance metrics.
155
+
156
+ ```rb
157
+ pipeline = ImageProcessing::Vips.instrumenter do |**options, &processing|
158
+ options[:source] #=> #<File:...>
159
+ options[:loader] #=> { fail: true }
160
+ options[:saver] #=> { quality: 85 }
161
+ options[:format] #=> "png"
162
+ options[:operations] #=> [[:resize_to_limit, 500, 500], [:flip, [:horizontal]]]
163
+ options[:processor] #=> ImageProcessing::Vips::Processor
164
+
165
+ ActiveSupport::Notifications.instrument("process.image_processing", **options) do
166
+ processing.call # calls the pipeline
167
+ end
168
+ end
169
+
170
+ pipeline
171
+ .source(image)
172
+ .loader(fail: true)
173
+ .saver(quality: 85)
174
+ .convert("png")
175
+ .resize_to_limit(500, 500)
176
+ .flip(:horizontal)
177
+ .call # calls instrumenter
178
+ ```
149
179
 
150
180
  ## Contributing
151
181
 
@@ -179,11 +209,12 @@ The `ImageProcessing::MiniMagick` functionality was extracted from
179
209
 
180
210
  [MIT](LICENSE.txt)
181
211
 
182
- [libvips]: http://jcupitt.github.io/libvips/
212
+ [libvips]: http://libvips.github.io/libvips/
183
213
  [ImageMagick]: https://www.imagemagick.org
184
- [`ImageProcessing::Vips`]: /doc/vips.md#imageprocessingvips
185
- [`ImageProcessing::MiniMagick`]: /doc/minimagick.md#imageprocessingminimagick
214
+ [GraphicsMagick]: http://www.graphicsmagick.org
215
+ [`ImageProcessing::Vips`]: doc/vips.md#readme
216
+ [`ImageProcessing::MiniMagick`]: doc/minimagick.md#readme
186
217
  [refile-mini_magick]: https://github.com/refile/refile-mini_magick
187
- [wiki]: https://github.com/janko-m/image_processing/wiki
218
+ [wiki]: https://github.com/janko/image_processing/wiki
188
219
  [HTTP.rb]: https://github.com/httprb/http
189
- [libvips performance]: https://github.com/jcupitt/libvips/wiki/Speed-and-memory-use
220
+ [libvips performance]: https://github.com/libvips/libvips/wiki/Speed-and-memory-use
@@ -1,14 +1,14 @@
1
- require File.expand_path('../lib/image_processing/version', __FILE__)
1
+ require File.expand_path("../lib/image_processing/version", __FILE__)
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = "image_processing"
5
5
  spec.version = ImageProcessing::VERSION
6
6
 
7
- spec.required_ruby_version = ">= 2.0"
7
+ spec.required_ruby_version = ">= 2.3"
8
8
 
9
- spec.summary = "Set of higher-level helper methods for image processing."
10
- spec.description = "Set of higher-level helper methods for image processing."
11
- spec.homepage = "https://github.com/janko-m/image_processing"
9
+ spec.summary = "High-level wrapper for processing images for the web with ImageMagick or libvips."
10
+ spec.description = "High-level wrapper for processing images for the web with ImageMagick or libvips."
11
+ spec.homepage = "https://github.com/janko/image_processing"
12
12
  spec.authors = ["Janko Marohnić"]
13
13
  spec.email = ["janko.marohnic@gmail.com"]
14
14
  spec.license = "MIT"
@@ -16,8 +16,8 @@ Gem::Specification.new do |spec|
16
16
  spec.files = Dir["README.md", "LICENSE.txt", "CHANGELOG.md", "lib/**/*.rb", "*.gemspec"]
17
17
  spec.require_paths = ["lib"]
18
18
 
19
- spec.add_dependency "mini_magick", "~> 4.0"
20
- spec.add_dependency "ruby-vips", ">= 2.0.10", "< 3"
19
+ spec.add_dependency "mini_magick", ">= 4.9.5", "< 5"
20
+ spec.add_dependency "ruby-vips", ">= 2.0.17", "< 3"
21
21
 
22
22
  spec.add_development_dependency "rake"
23
23
  spec.add_development_dependency "minitest", "~> 5.8"
@@ -8,8 +8,25 @@ module ImageProcessing
8
8
  @options = options
9
9
  end
10
10
 
11
- def call!(**options)
12
- Pipeline.new(self.options).call(**options)
11
+ # Calls the pipeline to perform the processing from built options.
12
+ def call!(**call_options)
13
+ instrument do
14
+ Pipeline.new(pipeline_options).call(**call_options)
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def instrument
21
+ return yield unless options[:instrumenter]
22
+
23
+ result = nil
24
+ options[:instrumenter].call(**pipeline_options) { result = yield }
25
+ result
26
+ end
27
+
28
+ def pipeline_options
29
+ options.reject { |key, _| key == :instrumenter }
13
30
  end
14
31
  end
15
32
  end
@@ -1,77 +1,102 @@
1
1
  module ImageProcessing
2
+ # Implements a chainable interface for building processing options.
2
3
  module Chainable
4
+ # Specify the source image file.
3
5
  def source(file)
4
6
  branch source: file
5
7
  end
6
8
 
9
+ # Specify the output format.
7
10
  def convert(format)
8
11
  branch format: format
9
12
  end
10
13
 
14
+ # Specify processor options applied when loading the image.
11
15
  def loader(**options)
12
16
  branch loader: options
13
17
  end
14
18
 
19
+ # Specify processor options applied when saving the image.
15
20
  def saver(**options)
16
21
  branch saver: options
17
22
  end
18
23
 
19
- def custom(&block)
20
- operation :custom, block
24
+ # Register instrumentation block that will be called around the pipeline.
25
+ def instrumenter(&block)
26
+ branch instrumenter: block
21
27
  end
22
28
 
29
+ # Add multiple operations as a hash or an array.
30
+ #
31
+ # .apply(resize_to_limit: [400, 400], strip: true)
32
+ # # or
33
+ # .apply([[:resize_to_limit, [400, 400]], [:strip, true])
23
34
  def apply(operations)
24
35
  operations.inject(self) do |builder, (name, argument)|
25
36
  if argument == true || argument == nil
26
37
  builder.send(name)
27
38
  elsif argument.is_a?(Array)
28
39
  builder.send(name, *argument)
40
+ elsif argument.is_a?(Hash)
41
+ builder.send(name, **argument)
29
42
  else
30
43
  builder.send(name, argument)
31
44
  end
32
45
  end
33
46
  end
34
47
 
35
- def method_missing(name, *args)
36
- return super if name.to_s.end_with?("?")
37
- return send(name.to_s.chomp("!"), *args).call if name.to_s.end_with?("!")
38
-
39
- operation name, *args
40
- end
41
-
42
- def operation(name, *args)
43
- branch operations: [[name, args]]
48
+ # Add an operation defined by the processor.
49
+ def operation(name, *args, &block)
50
+ branch operations: [[name, args, *block]]
44
51
  end
45
52
 
53
+ # Call the defined processing and get the result. Allows specifying
54
+ # the source file and destination.
46
55
  def call(file = nil, destination: nil, **call_options)
47
- options = {}
48
- options = options.merge(source: file) if file
49
- options = options.merge(destination: destination) if destination
56
+ options = { source: file, destination: destination }.compact
50
57
 
51
- branch(options).call!(**call_options)
58
+ branch(**options).call!(**call_options)
52
59
  end
53
60
 
54
- def branch(loader: nil, saver: nil, operations: nil, **other_options)
55
- options = respond_to?(:options) ? self.options : DEFAULT_OPTIONS
61
+ # Creates a new builder object, merging current options with new options.
62
+ def branch(**new_options)
63
+ if self.is_a?(Builder)
64
+ options = self.options
65
+ else
66
+ options = DEFAULT_OPTIONS.merge(processor: self::Processor)
67
+ end
56
68
 
57
- options = options.merge(loader: options[:loader].merge(loader)) if loader
58
- options = options.merge(saver: options[:saver].merge(saver)) if saver
59
- options = options.merge(operations: options[:operations] + operations) if operations
60
- options = options.merge(processor_class: self::Processor) unless self.is_a?(Builder)
61
- options = options.merge(other_options)
69
+ options = options.merge(new_options) do |key, old_value, new_value|
70
+ case key
71
+ when :loader, :saver then old_value.merge(new_value)
72
+ when :operations then old_value + new_value
73
+ else new_value
74
+ end
75
+ end
76
+
77
+ Builder.new(options.freeze)
78
+ end
62
79
 
63
- options.freeze
80
+ private
81
+
82
+ # Assume that any unknown method names an operation supported by the
83
+ # processor. Add a bang ("!") if you want processing to be performed.
84
+ def method_missing(name, *args, &block)
85
+ return super if name.to_s.end_with?("?")
86
+ return send(name.to_s.chomp("!"), *args, &block).call if name.to_s.end_with?("!")
64
87
 
65
- Builder.new(options)
88
+ operation(name, *args, &block)
66
89
  end
90
+ ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
67
91
 
92
+ # Empty options which the builder starts with.
68
93
  DEFAULT_OPTIONS = {
69
- source: nil,
70
- loader: {},
71
- saver: {},
72
- format: nil,
73
- operations: [],
74
- processor_class: nil,
94
+ source: nil,
95
+ loader: {},
96
+ saver: {},
97
+ format: nil,
98
+ operations: [],
99
+ processor: nil,
75
100
  }.freeze
76
101
  end
77
102
  end