Class: RASN1::Model Abstract
Overview
Model class is a base class to define ASN.1 models.
Create a simple ASN.1 model
Given this ASN.1 example:
Record ::= SEQUENCE {
id INTEGER,
room [0] IMPLICIT INTEGER OPTIONAL,
house [1] EXPLICIT INTEGER DEFAULT 0
}
you may create your model like this:
class Record < RASN1::Model
sequence(:record,
content: [integer(:id),
integer(:room, implicit: 0, optional: true),
integer(:house, explicit: 1, default: 0)])
end
In a model, each element must have a unique name.
Parse a DER-encoded string
record = Record.parse(der_string)
record[:id] # => RASN1::Types::Integer
record[:id].value # => Integer
record[:id].to_i # => Integer
record[:id].asn1_class # => Symbol
record[:id].optional? # => false
record[:id].default # => nil
record[:room].optional # => true
record[:house].default # => 0
You may also parse a BER-encoded string this way:
record = Record.parse(der_string, ber: true)
Generate a DER-encoded string
record = Record.new(id: 12, room: 24)
record.to_der
Create a more complex model
Models may be nested. For example:
class Record2 < RASN1::Model
sequence(:record2,
content: [boolean(:rented, default: false),
model(:a_record, Record)])
end
Set values like this:
record2 = Record2.new
record2[:rented] = true
record2[:a_record][:id] = 65537
record2[:a_record][:room] = 43
or like this:
record2 = Record2.new(rented: true, a_record: { id: 65537, room: 43 })
Delegation
Model may delegate some methods to its root element. Thus, if root element is, for example, a Types::Choice, model may delegate #chosen and #chosen_value.
All methods defined by root may be delegated by model, unless model also defines this method.
Defined Under Namespace
Modules: Accel Classes: BaseElem, ModelElem, WrapElem
Constant Summary collapse
- SEQUENCE_TYPES =
[Types::Sequence, Types::SequenceOf, Types::Set, Types::SetOf].freeze
Instance Attribute Summary collapse
- #root ⇒ Model, ... readonly
Attributes included from Accel
Class Method Summary collapse
- .bit_string(name, options) ⇒ Elem
- .bmp_string(name, options) ⇒ Elem
- .boolean(name, options) ⇒ Elem
- .choice(name, options) ⇒ Elem
- .enumerated(name, options) ⇒ Elem
- .ia5_string(name, options) ⇒ Elem
- .integer(name, options) ⇒ Elem
- .null(name, options) ⇒ Elem
- .numeric_string(name, options) ⇒ Elem
- .octet_string(name, options) ⇒ Elem
- .printable_string(name, options) ⇒ Elem
- .sequence(name, options) ⇒ Elem
- .sequence_of(name, type, options) ⇒ Elem
- .set(name, options) ⇒ Elem
- .set_of(name, type, options) ⇒ Elem
- .universal_string(name, options) ⇒ Elem
- .utf8_string(name, options) ⇒ Elem
- .visible_string(name, options) ⇒ Elem
Instance Method Summary collapse
-
#==(other) ⇒ Boolean
Objects are equal if they have same class AND same DER.
- #[](name_or_idx) ⇒ Object
-
#[]=(name, value) ⇒ Object
Set value of element
name. - #do_parse(der, ber: false) ⇒ Object
-
#initialize(args = {}) ⇒ Model
constructor
Create a new instance of a Model.
-
#initialize_copy ⇒ void
clone @elements and initialize @root from this new @element.
- #inspect(level = 0) ⇒ String
-
#keys ⇒ Array<Symbol,String>
Get elements names.
-
#method_missing(meth, *args, **kwargs) ⇒ Object
Delegate some methods to root element.
-
#name ⇒ String
Give model name (a.k.a root name).
-
#parse!(der, ber: false) ⇒ Integer
Parse a DER/BER encoded string, and modify object in-place.
- #respond_to_missing?(meth) ⇒ Boolean
- #to_der ⇒ String
-
#to_h ⇒ Hash
Return a hash image of model.
-
#type ⇒ String
Give type name (aka class name).
- #value(name = nil, *args) ⇒ Object?
Methods included from Accel
any, define_type_accel, define_type_accel_base, define_type_accel_of, inherited, model, objectid, parse, root_options, wrapper
Constructor Details
#initialize(args = {}) ⇒ Model
Create a new instance of a RASN1::Model
388 389 390 391 392 393 |
# File 'lib/rasn1/model.rb', line 388 def initialize(args={}) @elements = {} generate_root(args) args.delete(:name) lazy_initialize(args) unless args.empty? end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(meth, *args, **kwargs) ⇒ Object
Delegate some methods to root element
522 523 524 525 526 527 528 |
# File 'lib/rasn1/model.rb', line 522 def method_missing(meth, *args, **kwargs) if root.respond_to?(meth) root.send(meth, *args, **kwargs) else super end end |
Instance Attribute Details
Class Method Details
.bit_string(name, options) ⇒ Elem
376 377 378 379 380 381 |
# File 'lib/rasn1/model.rb', line 376 Types.primitives.each do |prim| next if prim == Types::ObjectId method_name = prim.type.gsub(/([a-z0-9])([A-Z])/, '\1_\2').downcase.gsub(/\s+/, '_') self.define_type_accel_base(method_name, prim) end |
.bmp_string(name, options) ⇒ Elem
376 377 378 379 380 381 |
# File 'lib/rasn1/model.rb', line 376 Types.primitives.each do |prim| next if prim == Types::ObjectId method_name = prim.type.gsub(/([a-z0-9])([A-Z])/, '\1_\2').downcase.gsub(/\s+/, '_') self.define_type_accel_base(method_name, prim) end |
.boolean(name, options) ⇒ Elem
376 377 378 379 380 381 |
# File 'lib/rasn1/model.rb', line 376 Types.primitives.each do |prim| next if prim == Types::ObjectId method_name = prim.type.gsub(/([a-z0-9])([A-Z])/, '\1_\2').downcase.gsub(/\s+/, '_') self.define_type_accel_base(method_name, prim) end |
.choice(name, options) ⇒ Elem
276 277 278 |
# File 'lib/rasn1/model.rb', line 276 %w[sequence set choice].each do |type| self.define_type_accel_base(type, Types.const_get(type.capitalize)) end |
.enumerated(name, options) ⇒ Elem
376 377 378 379 380 381 |
# File 'lib/rasn1/model.rb', line 376 Types.primitives.each do |prim| next if prim == Types::ObjectId method_name = prim.type.gsub(/([a-z0-9])([A-Z])/, '\1_\2').downcase.gsub(/\s+/, '_') self.define_type_accel_base(method_name, prim) end |
.ia5_string(name, options) ⇒ Elem
376 377 378 379 380 381 |
# File 'lib/rasn1/model.rb', line 376 Types.primitives.each do |prim| next if prim == Types::ObjectId method_name = prim.type.gsub(/([a-z0-9])([A-Z])/, '\1_\2').downcase.gsub(/\s+/, '_') self.define_type_accel_base(method_name, prim) end |
.integer(name, options) ⇒ Elem
376 377 378 379 380 381 |
# File 'lib/rasn1/model.rb', line 376 Types.primitives.each do |prim| next if prim == Types::ObjectId method_name = prim.type.gsub(/([a-z0-9])([A-Z])/, '\1_\2').downcase.gsub(/\s+/, '_') self.define_type_accel_base(method_name, prim) end |
.null(name, options) ⇒ Elem
376 377 378 379 380 381 |
# File 'lib/rasn1/model.rb', line 376 Types.primitives.each do |prim| next if prim == Types::ObjectId method_name = prim.type.gsub(/([a-z0-9])([A-Z])/, '\1_\2').downcase.gsub(/\s+/, '_') self.define_type_accel_base(method_name, prim) end |
.numeric_string(name, options) ⇒ Elem
376 377 378 379 380 381 |
# File 'lib/rasn1/model.rb', line 376 Types.primitives.each do |prim| next if prim == Types::ObjectId method_name = prim.type.gsub(/([a-z0-9])([A-Z])/, '\1_\2').downcase.gsub(/\s+/, '_') self.define_type_accel_base(method_name, prim) end |
.octet_string(name, options) ⇒ Elem
376 377 378 379 380 381 |
# File 'lib/rasn1/model.rb', line 376 Types.primitives.each do |prim| next if prim == Types::ObjectId method_name = prim.type.gsub(/([a-z0-9])([A-Z])/, '\1_\2').downcase.gsub(/\s+/, '_') self.define_type_accel_base(method_name, prim) end |
.printable_string(name, options) ⇒ Elem
376 377 378 379 380 381 |
# File 'lib/rasn1/model.rb', line 376 Types.primitives.each do |prim| next if prim == Types::ObjectId method_name = prim.type.gsub(/([a-z0-9])([A-Z])/, '\1_\2').downcase.gsub(/\s+/, '_') self.define_type_accel_base(method_name, prim) end |
.sequence(name, options) ⇒ Elem
276 277 278 |
# File 'lib/rasn1/model.rb', line 276 %w[sequence set choice].each do |type| self.define_type_accel_base(type, Types.const_get(type.capitalize)) end |
.sequence_of(name, type, options) ⇒ Elem
294 295 296 |
# File 'lib/rasn1/model.rb', line 294 %w[sequence set].each do |type| define_type_accel_of(type, Types.const_get(:"#{type.capitalize}Of")) end |
.set(name, options) ⇒ Elem
276 277 278 |
# File 'lib/rasn1/model.rb', line 276 %w[sequence set choice].each do |type| self.define_type_accel_base(type, Types.const_get(type.capitalize)) end |
.set_of(name, type, options) ⇒ Elem
294 295 296 |
# File 'lib/rasn1/model.rb', line 294 %w[sequence set].each do |type| define_type_accel_of(type, Types.const_get(:"#{type.capitalize}Of")) end |
.universal_string(name, options) ⇒ Elem
376 377 378 379 380 381 |
# File 'lib/rasn1/model.rb', line 376 Types.primitives.each do |prim| next if prim == Types::ObjectId method_name = prim.type.gsub(/([a-z0-9])([A-Z])/, '\1_\2').downcase.gsub(/\s+/, '_') self.define_type_accel_base(method_name, prim) end |
.utf8_string(name, options) ⇒ Elem
376 377 378 379 380 381 |
# File 'lib/rasn1/model.rb', line 376 Types.primitives.each do |prim| next if prim == Types::ObjectId method_name = prim.type.gsub(/([a-z0-9])([A-Z])/, '\1_\2').downcase.gsub(/\s+/, '_') self.define_type_accel_base(method_name, prim) end |
.visible_string(name, options) ⇒ Elem
376 377 378 379 380 381 |
# File 'lib/rasn1/model.rb', line 376 Types.primitives.each do |prim| next if prim == Types::ObjectId method_name = prim.type.gsub(/([a-z0-9])([A-Z])/, '\1_\2').downcase.gsub(/\s+/, '_') self.define_type_accel_base(method_name, prim) end |
Instance Method Details
#==(other) ⇒ Boolean
Objects are equal if they have same class AND same DER
545 546 547 |
# File 'lib/rasn1/model.rb', line 545 def ==(other) (other.class == self.class) && (other.to_der == self.to_der) end |
#[](name) ⇒ Model, ... #[](idx) ⇒ Model, ...
403 404 405 406 407 408 409 410 411 412 413 |
# File 'lib/rasn1/model.rb', line 403 def [](name_or_idx) case name_or_idx when Symbol elt = @elements[name_or_idx] return elt unless elt.is_a?(Proc) @elements[name_or_idx] = elt.call when Integer root[name_or_idx] end end |
#[]=(name, value) ⇒ Object
Set value of element name. Element should be a Types::Base.
419 420 421 422 423 424 |
# File 'lib/rasn1/model.rb', line 419 def []=(name, value) # Here, use #[] to force generation for lazy elements raise Error, 'cannot set value for a Model' if self[name].is_a?(Model) self[name].value = value end |
#do_parse(der, ber: false) ⇒ Object
474 475 476 |
# File 'lib/rasn1/model.rb', line 474 def do_parse(der, ber: false) root.do_parse(der, ber: ber) end |
#initialize_copy ⇒ void
This method returns an undefined value.
clone @elements and initialize @root from this new @element.
428 429 430 431 |
# File 'lib/rasn1/model.rb', line 428 def initialize_copy(*) @elements = @elements.clone @root = @elements[@root_name] end |
#inspect(level = 0) ⇒ String
538 539 540 |
# File 'lib/rasn1/model.rb', line 538 def inspect(level=0) "#{' ' * level}(#{type}) #{root.inspect(-level)}" end |
#keys ⇒ Array<Symbol,String>
Get elements names
441 442 443 |
# File 'lib/rasn1/model.rb', line 441 def keys @elements.keys end |
#name ⇒ String
Give model name (a.k.a root name)
435 436 437 |
# File 'lib/rasn1/model.rb', line 435 def name @root_name end |
#parse!(der, ber: false) ⇒ Integer
Parse a DER/BER encoded string, and modify object in-place.
467 468 469 |
# File 'lib/rasn1/model.rb', line 467 def parse!(der, ber: false) root.parse!(der, ber: ber) end |
#respond_to_missing?(meth) ⇒ Boolean
532 533 534 |
# File 'lib/rasn1/model.rb', line 532 def respond_to_missing?(meth, *) root.respond_to?(meth) || super end |
#to_der ⇒ String
452 453 454 |
# File 'lib/rasn1/model.rb', line 452 def to_der root.to_der end |
#to_h ⇒ Hash
Return a hash image of model
447 448 449 |
# File 'lib/rasn1/model.rb', line 447 def to_h private_to_h end |
#type ⇒ String
Give type name (aka class name)
458 459 460 |
# File 'lib/rasn1/model.rb', line 458 def type self.class.type end |
#value ⇒ Object? #value(name, *args) ⇒ Object?
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 |
# File 'lib/rasn1/model.rb', line 499 def value(name=nil, *args) if name.nil? root.value else elt = by_name(name) return nil if elt.nil? unless args.empty? args.each do |arg| elt = elt.root if elt.is_a?(Model) elt = elt[arg] end end elt.value end end |