claricle 0.1.0 → 0.2.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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +10 -1
  3. data/LICENSE +25 -0
  4. data/README.adoc +439 -157
  5. data/TODO.plan/00-overview.md +502 -0
  6. data/TODO.plan/01-core.md +296 -0
  7. data/TODO.plan/02-inspect.md +163 -0
  8. data/TODO.plan/03-conform.md +208 -0
  9. data/TODO.plan/04-convert.md +216 -0
  10. data/exe/claricle +1 -1
  11. data/lib/claricle/batch.rb +240 -0
  12. data/lib/claricle/cli.rb +514 -40
  13. data/lib/claricle/conformance_options.rb +49 -0
  14. data/lib/claricle/conversion_engine.rb +21 -0
  15. data/lib/claricle/convert.rb +21 -0
  16. data/lib/claricle/detector.rb +696 -0
  17. data/lib/claricle/emf_header.rb +33 -0
  18. data/lib/claricle/errors.rb +73 -0
  19. data/lib/claricle/fault.rb +69 -0
  20. data/lib/claricle/handlers/base.rb +169 -0
  21. data/lib/claricle/handlers/extension_points.rb +124 -0
  22. data/lib/claricle/handlers/metafile.rb +1011 -0
  23. data/lib/claricle/handlers/pdf.rb +961 -0
  24. data/lib/claricle/handlers/pdf_arlington/definitions.rb +54 -0
  25. data/lib/claricle/handlers/pdf_arlington/kind.rb +62 -0
  26. data/lib/claricle/handlers/pdf_arlington/predicate_gate.rb +39 -0
  27. data/lib/claricle/handlers/pdf_arlington/rules.rb +86 -0
  28. data/lib/claricle/handlers/pdf_arlington/walker.rb +131 -0
  29. data/lib/claricle/handlers/pdf_arlington.rb +38 -0
  30. data/lib/claricle/handlers/pdf_profiles.rb +66 -0
  31. data/lib/claricle/handlers/png.rb +1107 -0
  32. data/lib/claricle/handlers/postscript.rb +1357 -0
  33. data/lib/claricle/handlers/svg.rb +787 -0
  34. data/lib/claricle/image.rb +272 -0
  35. data/lib/claricle/lossiness/levels.rb +13 -0
  36. data/lib/claricle/lossiness.rb +864 -0
  37. data/lib/claricle/models/base.rb +460 -0
  38. data/lib/claricle/models/batch_item.rb +127 -0
  39. data/lib/claricle/models/conversion.rb +167 -0
  40. data/lib/claricle/models/format_capability.rb +40 -0
  41. data/lib/claricle/models/free_form_hash.rb +77 -0
  42. data/lib/claricle/models/inspection.rb +188 -0
  43. data/lib/claricle/models/issue.rb +23 -0
  44. data/lib/claricle/models/location.rb +51 -0
  45. data/lib/claricle/models/report.rb +54 -0
  46. data/lib/claricle/models/uncoerced_integer.rb +38 -0
  47. data/lib/claricle/postscript_fidelity/verdict.rb +37 -0
  48. data/lib/claricle/postscript_fidelity/view_box.rb +82 -0
  49. data/lib/claricle/postscript_fidelity.rb +160 -0
  50. data/lib/claricle/registry.rb +125 -0
  51. data/lib/claricle/version.rb +1 -1
  52. data/lib/claricle/writer.rb +468 -0
  53. data/lib/claricle.rb +244 -7
  54. metadata +201 -19
  55. data/claricle.gemspec +0 -42
  56. data/sig/claricle.rbs +0 -4
data/lib/claricle.rb CHANGED
@@ -2,15 +2,252 @@
2
2
 
3
3
  require "thor"
4
4
  require_relative "claricle/version"
5
+ require_relative "claricle/errors"
6
+ require_relative "claricle/models/location"
7
+ require_relative "claricle/models/issue"
8
+ require_relative "claricle/models/report"
9
+ require_relative "claricle/models/inspection"
10
+ require_relative "claricle/lossiness"
11
+ require_relative "claricle/models/conversion"
12
+ require_relative "claricle/models/batch_item"
13
+ require_relative "claricle/models/format_capability"
14
+ require_relative "claricle/fault"
15
+ require_relative "claricle/batch"
16
+ require_relative "claricle/writer"
17
+ require_relative "claricle/registry"
18
+ require_relative "claricle/conformance_options"
19
+ require_relative "claricle/detector"
20
+ require_relative "claricle/image"
21
+ require_relative "claricle/cli"
22
+ require_relative "claricle/convert"
5
23
 
6
24
  module Claricle
7
- class Error < StandardError; end
25
+ # Detects the format of `source`, a String of image content or an IO.
26
+ #
27
+ # An IO is read from wherever it is currently positioned -- it is never
28
+ # rewound, so a caller who has already consumed part of it gets a
29
+ # verdict on the remainder. Bytes are pulled in incrementally and
30
+ # classification is retried after each read, so a short, conclusive
31
+ # image (its signature or root tag already present) returns without
32
+ # waiting for more. Plain PostScript and EPSF are the exception: a byte
33
+ # that hasn't arrived yet can still turn one into the other, so that
34
+ # verdict waits for the probe bound -- the largest amount any detector
35
+ # probe consults -- or end of stream. A binary-preview EPS has its own
36
+ # conclusive magic and returns immediately. A source that stays open
37
+ # and never supplies enough to decide blocks until one of those is
38
+ # reached; content beyond the bound is left unread on the IO rather
39
+ # than buffered. It should be in binary mode; newline translation
40
+ # would corrupt the signatures this matches on. Pass a path to
41
+ # `Image.from_path` to stream from a file instead of buffering.
42
+ def self.detect(source)
43
+ return Detector.detect(source) unless source.respond_to?(:read)
8
44
 
9
- # Future component loading will go here:
10
- # require_relative "claricle/png_validator"
11
- # require_relative "claricle/svg_processor"
12
- # require_relative "claricle/vector_converter"
13
- # require_relative "claricle/image_compressor"
45
+ Detector.detect(accumulate(source))
46
+ end
14
47
 
15
- require_relative "claricle/cli"
48
+ # Grows `buffer` by reading from `source` a chunk at a time, stopping
49
+ # as soon as the buffer classifies, hits the probe bound, or the
50
+ # source ends -- so a complete short image on a stream that never
51
+ # closes doesn't wait for bytes nothing needs.
52
+ def self.accumulate(source)
53
+ buffer = "".b
54
+ loop do
55
+ return buffer if conclusive?(buffer) || buffer.bytesize >= Detector::MAX_PROBE_BYTES
56
+
57
+ begin
58
+ buffer << source.readpartial(Detector::MAX_PROBE_BYTES - buffer.bytesize)
59
+ rescue EOFError
60
+ return buffer
61
+ end
62
+ end
63
+ end
64
+
65
+ def self.conclusive?(buffer)
66
+ return true if EpsBinary.wrapped?(buffer)
67
+
68
+ format = Detector.detect(buffer)
69
+ # A plain PostScript verdict is provisional until the underlying line
70
+ # scan is certain: a byte that hasn't arrived yet can still flip EPSF
71
+ # from a trusted match to a disqualified one, so this loop must not
72
+ # settle for less than a real end of stream or the probe bound.
73
+ !%i[ps eps].include?(format)
74
+ rescue UnknownFormat
75
+ false
76
+ end
77
+
78
+ # Does everything named here conform? Exactly one of a positional path or
79
+ # `pattern:` -- issue #1's own examples use both shapes.
80
+ #
81
+ # A predicate answers about conformance and raises about everything else.
82
+ # A nonconformant file is `false`; an unknown format, an unsupported one,
83
+ # a missing file or a delegate crash raises, out of the batch shape too,
84
+ # so an operational failure never reads as a verdict.
85
+ #
86
+ # Both shapes reach the same expansion, so a positional means here exactly
87
+ # what it means on the command line: a literal path when it names a file,
88
+ # and a glob otherwise.
89
+ def self.conform?(path = nil, pattern: nil, strict: false, profile: nil, level: nil)
90
+ raise InvocationError, "give exactly one of a path or pattern" unless path.nil? ^ pattern.nil?
91
+
92
+ profile, level = ConformanceOptions.normalize(profile, level)
93
+ result = conformance_batch(*[path].compact, pattern: pattern,
94
+ strict: strict, profile: profile, level: level)
95
+ raise result.highest_error if result.highest_error
96
+
97
+ result.exit_code.zero?
98
+ end
99
+
100
+ def self.conformance_report(path, profile: nil, level: nil)
101
+ profile, level = ConformanceOptions.normalize(profile, level)
102
+ Image.from_path(path).conformance_report(profile: profile, level: level)
103
+ end
104
+
105
+ # A batch predicate loses information, so a caller can have the whole
106
+ # result instead: ordered per-file outcomes plus the aggregate status,
107
+ # which is what the command prints. Takes the command's own argument
108
+ # shape -- files, a pattern, or both -- so the two cannot drift about
109
+ # what conformance means.
110
+ def self.conformance_batch(*paths, pattern: nil, strict: false, profile: nil, level: nil)
111
+ # Checked eagerly here, before the batch runs, so a profile no format
112
+ # defines is one invocation error about the call and never a row in a
113
+ # report -- `conformance_report` checks it again per file, but only as a
114
+ # no-op once this call has already passed.
115
+ profile, level = ConformanceOptions.normalize(profile, level)
116
+ Batch.run(paths, pattern: pattern,
117
+ classify: ->(report) { conformant?(report, strict: strict) ? 0 : 1 }) do |file|
118
+ conformance_report(file, profile: profile, level: level)
119
+ end
120
+ end
121
+
122
+ # Any error means no; a warning alone means suspicious, which passes
123
+ # unless the caller asked for strict; info never downgrades anything.
124
+ def self.conformant?(report, strict:)
125
+ strict ? report.valid == :yes : report.valid != :no
126
+ end
127
+
128
+ # A batch predicate loses information, so a caller can have the whole
129
+ # result instead: ordered per-file outcomes plus the aggregate status.
130
+ # Same argument shape as `conformance_batch` (paths, pattern:), plus
131
+ # `to:`/`output:`/`force:` for the target and the write lifecycle, so
132
+ # the CLI command and the Ruby API cannot drift about what "which files"
133
+ # or "where to" mean.
134
+ #
135
+ # The whole destination set is preflighted -- collision, overwrite,
136
+ # case-fold aliasing -- BEFORE any file is converted. That is why this
137
+ # resolves the expanded file list and every destination up front, rather
138
+ # than letting `Batch.run` derive them one file at a time the way
139
+ # `conformance_batch` does.
140
+ #
141
+ # Target resolution runs before the single-source check below, so a
142
+ # `--to`/`--output` mismatch is reported even when the source count is
143
+ # also wrong -- the more specific problem surfaces first rather than
144
+ # being masked by the more generic one.
145
+ def self.convert_batch(*paths, to: nil, output: nil, force: false, pattern: nil)
146
+ files = Batch.expand(paths, pattern)
147
+ target = resolved_convert_target(to: to, output: output)
148
+ raise InvocationError, "--output takes a single source; #{files.length} files matched" if output && files.length > 1
149
+
150
+ destinations = files.to_h { |file| [file, convert_destination(file, target: target, output: output)] }
151
+ writer = Writer.new(destinations.values, sources: files, force: force)
152
+
153
+ # `classify` always answers 0: the block below either returns a
154
+ # `Models::Conversion` normally, or raises, which Batch's own per-file
155
+ # rescue already turns into a failed item with its own exit code. There
156
+ # is no success/failure distinction left for `classify` to make --
157
+ # unlike `Report#valid`, a completed conversion has no verdict to grade.
158
+ #
159
+ # `run_files`, not `run`: `files` is already the expanded list built
160
+ # above for the destination preflight. `run` would expand it a SECOND
161
+ # time -- redundant stat/realpath work on every file, and a real gap:
162
+ # a file removed between the two expansions would silently drop out of
163
+ # the second one with no error, even though a destination was already
164
+ # preflighted for it.
165
+ Batch.run_files(files, classify: ->(_result) { 0 }) do |file|
166
+ convert_one(file, target: target, destination: destinations.fetch(file), writer: writer)
167
+ end
168
+ end
169
+
170
+ def self.convert_one(file, target:, destination:, writer:)
171
+ image = Image.from_path(file)
172
+ raise InvocationError, "#{file} is already #{target}; nothing to convert to" if image.format == target
173
+
174
+ # See `Models::Conversion#with_output_path` for why a second instance
175
+ # is built here rather than the handler's own carrying the real path.
176
+ conversion = image.convert(to: target)
177
+ conversion.with_output_path(writer.write(conversion.content, to: destination))
178
+ end
179
+
180
+ # `--to` wins outright when given, once it does not conflict with a
181
+ # recognised `--output` extension. `--output` alone must name a
182
+ # recognised extension to infer from; `--output -` alone cannot, since
183
+ # stdout has no extension.
184
+ #
185
+ # `--to` is case-folded to the registry's own spelling (`Registry.formats`
186
+ # is always lowercase symbols) so `--to SVG` and `--to svg` resolve
187
+ # identically -- unfolded, `--to SVG --output copy.svg` reported a false
188
+ # "conflicts with --output" (the two sides compared `:SVG` against the
189
+ # inferred `:svg`), a same-format `--to SVG` on an already-SVG source
190
+ # skipped the guard below entirely, and the derived destination for a
191
+ # bare `--to SVG` carried the wrong-cased extension.
192
+ def self.resolved_convert_target(to:, output:)
193
+ # `if to` alone treats an explicit `--to ""` as given: truthy, but
194
+ # `to.to_s.downcase.to_sym` then builds the bogus target `:""`, which
195
+ # went on to derive a destination with no extension and a garbled
196
+ # "not supported for convert to :\"\"" message instead of the clean
197
+ # invocation error below. `--to ""` and no `--to` at all mean the same
198
+ # thing -- there is no target -- so both take this branch.
199
+ return resolved_to_target(to, output) if to && !to.to_s.empty?
200
+ if output == Writer::STDOUT_DESTINATION
201
+ raise InvocationError, "--output - needs --to; there is no extension to infer from"
202
+ end
203
+ raise InvocationError, "give --to, or an --output with a recognised format extension" if output.nil?
204
+
205
+ convert_extension_format(output) ||
206
+ raise(InvocationError, "--output #{output.inspect} has no recognised format extension; give --to")
207
+ end
208
+
209
+ def self.resolved_to_target(to, output)
210
+ target = to.to_s.downcase.to_sym
211
+ raise InvocationError, "unknown format #{to.to_s.inspect} for --to" unless Registry.formats.include?(target)
212
+
213
+ check_to_output_conflict(target, output)
214
+ target
215
+ end
216
+
217
+ # A conflict, not a preference: one silently winning over the other would
218
+ # surprise whichever the caller meant. `output:` naming stdout or an
219
+ # unrecognised extension carries no claim about the target, so there is
220
+ # nothing for `--to` to conflict with in either case. `target` arrives
221
+ # already case-folded from `resolved_convert_target`.
222
+ def self.check_to_output_conflict(target, output)
223
+ return if output.nil? || output == Writer::STDOUT_DESTINATION
224
+
225
+ inferred = convert_extension_format(output)
226
+ return if inferred.nil? || inferred == target
227
+
228
+ raise InvocationError, "--to #{target} conflicts with --output #{output} (looks like #{inferred})"
229
+ end
230
+
231
+ # The canonical extension for a target is the format symbol itself --
232
+ # there is no central extension table, only `Registry.formats`.
233
+ def self.convert_extension_format(name)
234
+ ext = File.extname(name.to_s).delete_prefix(".").downcase
235
+ return nil if ext.empty?
236
+
237
+ format = ext.to_sym
238
+ Registry.formats.include?(format) ? format : nil
239
+ end
240
+
241
+ # The issue's own example: `convert("diagram.emf", to: :svg)` writes
242
+ # `diagram.svg` -- the source's own name, the target's extension,
243
+ # alongside the source.
244
+ def self.convert_destination(file, target:, output:)
245
+ return output if output
246
+
247
+ File.join(File.dirname(file), "#{File.basename(file, ".*")}.#{target}")
248
+ end
249
+
250
+ private_class_method :accumulate, :conclusive?, :conformant?,
251
+ :convert_one, :resolved_convert_target, :resolved_to_target,
252
+ :check_to_output_conflict, :convert_extension_format, :convert_destination
16
253
  end
metadata CHANGED
@@ -1,36 +1,175 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: claricle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-10-27 00:00:00.000000000 Z
11
+ date: 2026-10-16 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: emf
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.1.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.1.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: emfsvg
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.1.2
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.1.2
41
+ - !ruby/object:Gem::Dependency
42
+ name: lutaml-model
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.8.32
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.8.32
55
+ - !ruby/object:Gem::Dependency
56
+ name: pdfrb
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.7.23
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.7.23
69
+ - !ruby/object:Gem::Dependency
70
+ name: png_conform
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.1.4
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.1.4
83
+ - !ruby/object:Gem::Dependency
84
+ name: postscript
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.2.0
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.2.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: postsvg
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 0.3.0
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 0.3.0
111
+ - !ruby/object:Gem::Dependency
112
+ name: rexml
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 3.4.4
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 3.4.4
125
+ - !ruby/object:Gem::Dependency
126
+ name: svg_conform
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 0.2.2
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 0.2.2
13
139
  - !ruby/object:Gem::Dependency
14
140
  name: thor
15
141
  requirement: !ruby/object:Gem::Requirement
16
142
  requirements:
17
143
  - - "~>"
18
144
  - !ruby/object:Gem::Version
19
- version: '1.0'
145
+ version: '1.2'
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '1.2'
153
+ - !ruby/object:Gem::Dependency
154
+ name: vectory
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: 0.12.0
20
160
  type: :runtime
21
161
  prerelease: false
22
162
  version_requirements: !ruby/object:Gem::Requirement
23
163
  requirements:
24
164
  - - "~>"
25
165
  - !ruby/object:Gem::Version
26
- version: '1.0'
166
+ version: 0.12.0
27
167
  description: |
28
- Claricle provides a Ruby library for working with images, offering tools for
29
- image validation (PNG, SVG), format conversion, compression, and vector
30
- graphics processing. The name combines "clarity" and "particle", representing
31
- the clear validation of every pixel. It is built to integrate functionality
32
- from pngconform, svgconform, vectory, and other image processing tools into
33
- a unified interface.
168
+ Claricle detects an image's format from its bytes -- PNG, SVG, EMF, WMF,
169
+ EPS, PS and PDF -- and gives one object and one set of models to work with.
170
+ The name combines "clarity" and "particle". It inspects, checks
171
+ conformance and converts between formats, wrapping
172
+ png_conform, svg_conform, vectory and pdfrb behind a single interface.
34
173
  email:
35
174
  - open.source@ribose.com
36
175
  executables:
@@ -42,21 +181,65 @@ files:
42
181
  - ".rubocop.yml"
43
182
  - CODE_OF_CONDUCT.md
44
183
  - Gemfile
184
+ - LICENSE
45
185
  - README.adoc
46
186
  - Rakefile
47
- - claricle.gemspec
187
+ - TODO.plan/00-overview.md
188
+ - TODO.plan/01-core.md
189
+ - TODO.plan/02-inspect.md
190
+ - TODO.plan/03-conform.md
191
+ - TODO.plan/04-convert.md
48
192
  - exe/claricle
49
193
  - lib/claricle.rb
194
+ - lib/claricle/batch.rb
50
195
  - lib/claricle/cli.rb
196
+ - lib/claricle/conformance_options.rb
197
+ - lib/claricle/conversion_engine.rb
198
+ - lib/claricle/convert.rb
199
+ - lib/claricle/detector.rb
200
+ - lib/claricle/emf_header.rb
201
+ - lib/claricle/errors.rb
202
+ - lib/claricle/fault.rb
203
+ - lib/claricle/handlers/base.rb
204
+ - lib/claricle/handlers/extension_points.rb
205
+ - lib/claricle/handlers/metafile.rb
206
+ - lib/claricle/handlers/pdf.rb
207
+ - lib/claricle/handlers/pdf_arlington.rb
208
+ - lib/claricle/handlers/pdf_arlington/definitions.rb
209
+ - lib/claricle/handlers/pdf_arlington/kind.rb
210
+ - lib/claricle/handlers/pdf_arlington/predicate_gate.rb
211
+ - lib/claricle/handlers/pdf_arlington/rules.rb
212
+ - lib/claricle/handlers/pdf_arlington/walker.rb
213
+ - lib/claricle/handlers/pdf_profiles.rb
214
+ - lib/claricle/handlers/png.rb
215
+ - lib/claricle/handlers/postscript.rb
216
+ - lib/claricle/handlers/svg.rb
217
+ - lib/claricle/image.rb
218
+ - lib/claricle/lossiness.rb
219
+ - lib/claricle/lossiness/levels.rb
220
+ - lib/claricle/models/base.rb
221
+ - lib/claricle/models/batch_item.rb
222
+ - lib/claricle/models/conversion.rb
223
+ - lib/claricle/models/format_capability.rb
224
+ - lib/claricle/models/free_form_hash.rb
225
+ - lib/claricle/models/inspection.rb
226
+ - lib/claricle/models/issue.rb
227
+ - lib/claricle/models/location.rb
228
+ - lib/claricle/models/report.rb
229
+ - lib/claricle/models/uncoerced_integer.rb
230
+ - lib/claricle/postscript_fidelity.rb
231
+ - lib/claricle/postscript_fidelity/verdict.rb
232
+ - lib/claricle/postscript_fidelity/view_box.rb
233
+ - lib/claricle/registry.rb
51
234
  - lib/claricle/version.rb
52
- - sig/claricle.rbs
53
- homepage: https://github.com/ribose/claricle
235
+ - lib/claricle/writer.rb
236
+ homepage: https://github.com/claricle/claricle
54
237
  licenses:
55
238
  - BSD-2-Clause
56
239
  metadata:
57
- homepage_uri: https://github.com/ribose/claricle
58
- source_code_uri: https://github.com/ribose/claricle
59
- changelog_uri: https://github.com/ribose/claricle
240
+ homepage_uri: https://github.com/claricle/claricle
241
+ source_code_uri: https://github.com/claricle/claricle
242
+ changelog_uri: https://github.com/claricle/claricle/releases
60
243
  rubygems_mfa_required: 'true'
61
244
  post_install_message:
62
245
  rdoc_options: []
@@ -66,7 +249,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
66
249
  requirements:
67
250
  - - ">="
68
251
  - !ruby/object:Gem::Version
69
- version: 3.0.0
252
+ version: 3.3.0
70
253
  required_rubygems_version: !ruby/object:Gem::Requirement
71
254
  requirements:
72
255
  - - ">="
@@ -76,6 +259,5 @@ requirements: []
76
259
  rubygems_version: 3.5.22
77
260
  signing_key:
78
261
  specification_version: 4
79
- summary: Claricle is a comprehensive image utility gem for validation, conversion,
80
- and compression.
262
+ summary: Detect, inspect, conform and convert image files in Ruby.
81
263
  test_files: []
data/claricle.gemspec DELETED
@@ -1,42 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "lib/claricle/version"
4
-
5
- Gem::Specification.new do |spec|
6
- spec.name = "claricle"
7
- spec.version = Claricle::VERSION
8
- spec.authors = ["Ribose Inc."]
9
- spec.email = ["open.source@ribose.com"]
10
-
11
- spec.summary = "Claricle is a comprehensive image utility gem for validation, conversion, and compression."
12
- spec.description = <<~HEREDOC
13
- Claricle provides a Ruby library for working with images, offering tools for
14
- image validation (PNG, SVG), format conversion, compression, and vector
15
- graphics processing. The name combines "clarity" and "particle", representing
16
- the clear validation of every pixel. It is built to integrate functionality
17
- from pngconform, svgconform, vectory, and other image processing tools into
18
- a unified interface.
19
- HEREDOC
20
-
21
- spec.homepage = "https://github.com/ribose/claricle"
22
- spec.license = "BSD-2-Clause"
23
- spec.required_ruby_version = ">= 3.0.0"
24
-
25
- spec.metadata["homepage_uri"] = spec.homepage
26
- spec.metadata["source_code_uri"] = "https://github.com/ribose/claricle"
27
- spec.metadata["changelog_uri"] = "https://github.com/ribose/claricle"
28
- spec.metadata["rubygems_mfa_required"] = "true"
29
-
30
- # Specify which files should be added to the gem when it is released.
31
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
32
- spec.files = Dir.chdir(__dir__) do
33
- `git ls-files -z`.split("\x0").reject do |f|
34
- (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
35
- end
36
- end
37
- spec.bindir = "exe"
38
- spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
39
- spec.require_paths = ["lib"]
40
-
41
- spec.add_dependency "thor", "~> 1.0"
42
- end
data/sig/claricle.rbs DELETED
@@ -1,4 +0,0 @@
1
- module Claricle
2
- VERSION: String
3
- # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
- end