Class: Pdfrb::Model::Cos::Dictionary
- Inherits:
-
Object
- Object
- Object
- Pdfrb::Model::Cos::Dictionary
show all
- Defined in:
- lib/pdfrb/model/cos/dictionary.rb
Overview
Common Object Syntax dictionary (s7.3.7). Wraps a Hash of
Symbol -> PDF value. Subclassed by every semantic Type::*.
Field metadata can come from two sources (mutually exclusive
per field; last declaration wins):
* `define_field` — hand-coded (HexaPDF shape).
* `arlington_object "Name"` — auto-loaded from vendored TSVs
via Pdfrb::Arlington::Loader. Calls `define_field` under
the hood with types translated to Ruby classes.
Direct Known Subclasses
Stream, Type::Action, Type::Annotation, Type::CIDFont, Type::Catalog, Type::EncryptionPublicKey, Type::EncryptionStandard, Type::FileSpecification, Type::FileTrailer, Type::Font, Type::FontDescriptor, Type::FontTrueType, Type::FontType0, Type::FontType1, Type::FontType3, Type::GraphicsStateParameter, Type::Info, Type::InteractiveForm, Type::Names, Type::OptionalContentGroup, Type::OptionalContentMembership, Type::OptionalContentProperties, Type::Outline, Type::OutlineItem, Type::OutputIntent, Type::Page, Type::PageTreeNode, Type::Resources, Type::StructElem, Type::StructTreeRoot
Instance Attribute Summary
Attributes inherited from Object
#document, #gen, #oid, #value
Class Method Summary
collapse
-
.arlington_available? ⇒ Boolean
-
.arlington_default(field_def) ⇒ Object
-
.arlington_key_to_symbol(key) ⇒ Object
-
.arlington_loaded_for?(_name) ⇒ Boolean
-
.arlington_mark_loaded(name) ⇒ Object
-
.arlington_object(name, version: "latest") ⇒ Object
Pull field metadata from the named Arlington TSV.
-
.arlington_one_type_to_ruby(t) ⇒ Object
-
.arlington_required?(field_def) ⇒ Boolean
-
.arlington_types_to_ruby(field_def) ⇒ Object
-
.arlington_version(field_def) ⇒ Object
-
.define_field(pdf_name, type:, required: false, default: nil, indirect: nil, allowed_values: nil, version: "1.0", arlington: nil) ⇒ Object
Declare a field on this class.
-
.define_field_from_arlington(field_def) ⇒ Object
-
.each_field ⇒ Object
Iterate (name, Field) pairs across the inheritance chain.
-
.field(name) ⇒ Object
Look up a field by name; walks the inheritance chain.
-
.lookup_type(symbol) ⇒ Object
-
.own_fields ⇒ Object
-
.register_type(symbol, klass = self) ⇒ Object
-
.type_map ⇒ Object
/Type-symbol -> Dictionary subclass.
Instance Method Summary
collapse
Methods inherited from Object
#==, define_type, #deref, #indirect?, #must_be_indirect?, pdf_type
Constructor Details
#initialize(value = {}, oid: 0, gen: 0, document: nil) ⇒ Dictionary
Returns a new instance of Dictionary.
181
182
183
184
185
186
187
188
189
|
# File 'lib/pdfrb/model/cos/dictionary.rb', line 181
def initialize(value = {}, oid: 0, gen: 0, document: nil)
value ||= {}
unless value.is_a?(::Hash)
raise ArgumentError, "Dictionary value must be a Hash, got #{value.class}"
end
super(value, oid: oid, gen: gen, document: document)
apply_required_defaults
end
|
Class Method Details
.arlington_available? ⇒ Boolean
108
109
110
111
112
113
|
# File 'lib/pdfrb/model/cos/dictionary.rb', line 108
def arlington_available?
Pdfrb.const_defined?(:Arlington) &&
Pdfrb::Arlington.const_defined?(:Loader)
rescue StandardError
false
end
|
.arlington_default(field_def) ⇒ Object
168
169
170
171
172
|
# File 'lib/pdfrb/model/cos/dictionary.rb', line 168
def arlington_default(field_def)
return nil if field_def.default_value.nil?
field_def.default_value
end
|
.arlington_key_to_symbol(key) ⇒ Object
158
159
160
|
# File 'lib/pdfrb/model/cos/dictionary.rb', line 158
def arlington_key_to_symbol(key)
key.to_sym
end
|
.arlington_loaded_for?(_name) ⇒ Boolean
98
99
100
|
# File 'lib/pdfrb/model/cos/dictionary.rb', line 98
def arlington_loaded_for?(_name)
@arlington_loaded_name == name
end
|
.arlington_mark_loaded(name) ⇒ Object
103
104
105
|
# File 'lib/pdfrb/model/cos/dictionary.rb', line 103
def arlington_mark_loaded(name)
@arlington_loaded_name = name
end
|
.arlington_object(name, version: "latest") ⇒ Object
Pull field metadata from the named Arlington TSV. Idempotent.
Silently no-ops when the Arlington layer or the TSV is
unavailable, so hand-coded subclasses still work.
Also registers self in Pdfrb::Model::Type.arlington_registry
under name so field-link resolution can find this class
when other Types reference it.
79
80
81
82
83
84
85
86
87
88
89
90
91
|
# File 'lib/pdfrb/model/cos/dictionary.rb', line 79
def arlington_object(name, version: "latest")
return if arlington_loaded_for?(name)
return unless arlington_available?
definition = Pdfrb::Arlington::Loader.object_definition(name, version: version)
return unless definition
arlington_mark_loaded(name)
Pdfrb::Model::Type.register_arlington(name, self) if Pdfrb::Model.const_defined?(:Type)
definition.each_field do |field_def|
define_field_from_arlington(field_def)
end
end
|
.arlington_one_type_to_ruby(t) ⇒ Object
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
# File 'lib/pdfrb/model/cos/dictionary.rb', line 137
def arlington_one_type_to_ruby(t)
case t
when :boolean then [TrueClass, FalseClass]
when :integer then Integer
when :number then [Integer, Float]
when :name then Symbol
when :string, :"string-ascii", :"string-text" then String
when :"string-byte" then Fields::PDFByteString
when :array then Pdfrb::Model::PdfArray
when :dictionary then Pdfrb::Model::Cos::Dictionary
when :stream then Pdfrb::Model::Cos::Stream
when :null then NilClass
when :date then Fields::PDFDate
when :rectangle then Pdfrb::Model::Rectangle
when :matrix then Pdfrb::Model::Matrix
when :bitmask then Integer
when :"name-tree", :"number-tree" then Pdfrb::Model::Cos::Dictionary
end
end
|
.arlington_required?(field_def) ⇒ Boolean
163
164
165
|
# File 'lib/pdfrb/model/cos/dictionary.rb', line 163
def arlington_required?(field_def)
field_def.required_literal == true
end
|
.arlington_types_to_ruby(field_def) ⇒ Object
132
133
134
|
# File 'lib/pdfrb/model/cos/dictionary.rb', line 132
def arlington_types_to_ruby(field_def)
field_def.types.map { |t| arlington_one_type_to_ruby(t) }.flatten.compact.uniq
end
|
.arlington_version(field_def) ⇒ Object
175
176
177
|
# File 'lib/pdfrb/model/cos/dictionary.rb', line 175
def arlington_version(field_def)
field_def.since_version.to_s
end
|
.define_field(pdf_name, type:, required: false, default: nil, indirect: nil, allowed_values: nil, version: "1.0", arlington: nil) ⇒ Object
Declare a field on this class. Mirrors HexaPDF's
define_field shape; we add an arlington: slot for the
source FieldDefinition.
44
45
46
47
48
49
50
51
52
|
# File 'lib/pdfrb/model/cos/dictionary.rb', line 44
def define_field(pdf_name, type:, required: false, default: nil,
indirect: nil, allowed_values: nil, version: "1.0",
arlington: nil)
own_fields[pdf_name] = Fields::Field.new(
pdf_name, type: type, required: required, default: default,
indirect: indirect, allowed_values: allowed_values,
version: version, arlington: arlington
)
end
|
.define_field_from_arlington(field_def) ⇒ Object
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
# File 'lib/pdfrb/model/cos/dictionary.rb', line 116
def define_field_from_arlington(field_def)
types = arlington_types_to_ruby(field_def)
return if types.empty?
key = arlington_key_to_symbol(field_def.key)
define_field(
key,
type: types.length == 1 ? types.first : types,
required: arlington_required?(field_def),
default: arlington_default(field_def),
version: arlington_version(field_def),
arlington: field_def
)
end
|
.each_field ⇒ Object
Iterate (name, Field) pairs across the inheritance chain.
63
64
65
66
67
68
69
70
|
# File 'lib/pdfrb/model/cos/dictionary.rb', line 63
def each_field
return enum_for(:each_field) unless block_given?
if superclass <= Pdfrb::Model::Cos::Dictionary
superclass.each_field { |n, f| yield n, f }
end
own_fields.each { |n, f| yield n, f }
end
|
.field(name) ⇒ Object
Look up a field by name; walks the inheritance chain.
55
56
57
58
59
60
|
# File 'lib/pdfrb/model/cos/dictionary.rb', line 55
def field(name)
return own_fields[name] if own_fields.key?(name)
return superclass.field(name) if superclass <= Pdfrb::Model::Cos::Dictionary
nil
end
|
.lookup_type(symbol) ⇒ Object
37
38
39
|
# File 'lib/pdfrb/model/cos/dictionary.rb', line 37
def lookup_type(symbol)
TYPE_MAP[symbol]
end
|
.own_fields ⇒ Object
93
94
95
|
# File 'lib/pdfrb/model/cos/dictionary.rb', line 93
def own_fields
@own_fields ||= {}
end
|
.register_type(symbol, klass = self) ⇒ Object
32
33
34
35
|
# File 'lib/pdfrb/model/cos/dictionary.rb', line 32
def register_type(symbol, klass = self)
TYPE_MAP[symbol] = klass
klass.define_type(symbol) unless klass.pdf_type
end
|
/Type-symbol -> Dictionary subclass. Populated by
register_type. Used by Document#wrap to dispatch.
28
29
30
|
# File 'lib/pdfrb/model/cos/dictionary.rb', line 28
def type_map
TYPE_MAP
end
|
Instance Method Details
Typed access. Resolves References, wraps in field-specific
subclass, applies default, runs converters.
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
|
# File 'lib/pdfrb/model/cos/dictionary.rb', line 193
def [](name)
name = name.to_sym unless name.is_a?(::Symbol)
field = self.class.field(name)
data = @value[name]
data = field.default if data.nil? && field&.default?
return nil if data.nil?
data = dereference(data)
data = data.value if unbox_object?(data)
return data unless field
converted = Fields.apply(field, data, document)
if converted
@value[name] = converted
converted
else
data
end
end
|
#[]=(name, value) ⇒ Object
214
215
216
217
218
|
# File 'lib/pdfrb/model/cos/dictionary.rb', line 214
def []=(name, value)
raise ArgumentError, "Dictionary keys must be Symbols" unless name.is_a?(::Symbol)
@value[name] = value
end
|
#delete(name) ⇒ Object
225
226
227
228
|
# File 'lib/pdfrb/model/cos/dictionary.rb', line 225
def delete(name)
name = name.to_sym unless name.is_a?(::Symbol)
@value.delete(name)
end
|
Iterate (Symbol, processed-value) pairs. Slower than #each_raw
because it runs the full accessor pipeline; use that when
you don't need wrapping.
233
234
235
236
237
238
|
# File 'lib/pdfrb/model/cos/dictionary.rb', line 233
def each
return enum_for(:each) unless block_given?
@value.each_key { |k| yield(k, self[k]) }
self
end
|
Iterate (Symbol, raw-value) pairs without accessor pipeline.
241
242
243
244
245
246
|
# File 'lib/pdfrb/model/cos/dictionary.rb', line 241
def each_raw
return enum_for(:each_raw) unless block_given?
@value.each { |k, v| yield(k, v) }
self
end
|
#empty? ⇒ Boolean
249
|
# File 'lib/pdfrb/model/cos/dictionary.rb', line 249
def empty?; @value.empty?; end
|
#key?(name) ⇒ Boolean
220
221
222
223
|
# File 'lib/pdfrb/model/cos/dictionary.rb', line 220
def key?(name)
name = name.to_sym unless name.is_a?(::Symbol)
!@value[name].nil?
end
|
248
|
# File 'lib/pdfrb/model/cos/dictionary.rb', line 248
def keys; @value.keys; end
|
251
252
253
|
# File 'lib/pdfrb/model/cos/dictionary.rb', line 251
def pdf_type
self.class.pdf_type || self[:Type]
end
|
Walk every declared field and yield (message, correctable)
for each violation. Returns an Enumerator if no block given.
257
258
259
260
261
262
263
|
# File 'lib/pdfrb/model/cos/dictionary.rb', line 257
def validate
return enum_for(:validate) unless block_given?
self.class.each_field do |name, field|
validate_one(name, field) { |*a| yield(*a) }
end
end
|