lib/rasn1/model.rb in rasn1-0.6.8 vs lib/rasn1/model.rb in rasn1-0.7.0
- old
+ new
@@ -1,7 +1,8 @@
-module RASN1
+# frozen_string_literal: true
+module RASN1
# @abstract
# {Model} class is a base class to define ASN.1 models.
# == Create a simple ASN.1 model
# Given this ASN.1 example:
# Record ::= SEQUENCE {
@@ -56,11 +57,10 @@
#
# All methods defined by root may be delegated by model, unless model also defines
# this method.
# @author Sylvain Daubert
class Model
-
class << self
# @return [Hash]
attr_reader :options
# Use another model in this model
@@ -90,11 +90,11 @@
# On inheritance, create +@root+ class variable
# @param [Class] klass
# @return [void]
def inherited(klass)
super
- root = defined?(@root )? @root : nil
+ root = @root
klass.class_eval { @root = root }
end
# @method sequence(name, options)
# @param [Symbol,String] name name of object in model
@@ -106,20 +106,20 @@
# @see Types::Set#initialize
# @method choice(name, options)
# @param [Symbol,String] name name of object in model
# @param [Hash] options
# @see Types::Choice#initialize
- %w(sequence set choice).each do |type|
+ %w[sequence set choice].each do |type|
class_eval "def #{type}(name, options={})\n" \
" options.merge!(name: name)\n" \
- " proc = Proc.new do |opts|\n" \
+ " proc = proc do |opts|\n" \
" Types::#{type.capitalize}.new(options.merge(opts))\n" \
" end\n" \
" @root = [name, proc]\n" \
" @root << options[:content] unless options[:content].nil?\n" \
" @root\n" \
- "end"
+ 'end'
end
# @method sequence_of(name, type, options)
# @param [Symbol,String] name name of object in model
# @param [Model, Types::Base] type type for SEQUENCE OF
@@ -128,19 +128,19 @@
# @method set_of(name, type, options)
# @param [Symbol,String] name name of object in model
# @param [Model, Types::Base] type type for SET OF
# @param [Hash] options
# @see Types::SetOf#initialize
- %w(sequence set).each do |type|
+ %w[sequence set].each do |type|
klass_name = "Types::#{type.capitalize}Of"
class_eval "def #{type}_of(name, type, options={})\n" \
" options.merge!(name: name)\n" \
- " proc = Proc.new do |opts|\n" \
+ " proc = proc do |opts|\n" \
" #{klass_name}.new(type, options.merge(opts))\n" \
" end\n" \
" @root = [name, proc]\n" \
- "end"
+ 'end'
end
# @method boolean(name, options)
# @param [Symbol,String] name name of object in model
# @param [Hash] options
@@ -185,44 +185,46 @@
# @param [Symbol,String] name name of object in model
# @param [Hash] options
# @see Types::IA5String#initialize
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+/, '_')
class_eval "def #{method_name}(name, options={})\n" \
" options.merge!(name: name)\n" \
- " proc = Proc.new do |opts|\n" \
- " #{prim.to_s}.new(options.merge(opts))\n" \
+ " proc = proc do |opts|\n" \
+ " #{prim}.new(options.merge(opts))\n" \
" end\n" \
" @root = [name, proc]\n" \
- "end"
+ 'end'
end
# @param [Symbol,String] name name of object in model
# @param [Hash] options
# @note This method is named +objectid+ and not +object_id+ to not override
# +Object#object_id+.
# @see Types::ObjectId#initialize
def objectid(name, options={})
options.merge!(name: name)
- proc = Proc.new { |opts| Types::ObjectId.new(options.merge(opts)) }
+ proc = proc { |opts| Types::ObjectId.new(options.merge(opts)) }
@root = [name, proc]
end
# @param [Symbol,String] name name of object in model
# @param [Hash] options
# @see Types::Any#initialize
def any(name, options={})
options.merge!(name: name)
- proc = Proc.new { |opts| Types::Any.new(options.merge(opts)) }
+ proc = proc { |opts| Types::Any.new(options.merge(opts)) }
@root = [name, proc]
end
# Give type name (aka class name)
# @return [String]
def type
return @type if defined? @type
+
@type = self.to_s.gsub(/.*::/, '')
end
# Parse a DER/BER encoded string
# @param [String] str
@@ -254,11 +256,12 @@
# Set value of element +name+. Element should be a {Base}.
# @param [String,Symbol] name
# @param [Object] value
# @return [Object] value
def []=(name, value)
- raise Error, "cannot set value for a Model" if @elements[name].is_a? Model
+ raise Error, 'cannot set value for a Model' if @elements[name].is_a? Model
+
@elements[name].value = value
end
# Get name frm root type
# @return [String,Symbol]
@@ -302,20 +305,51 @@
# @raise [ASN1Error] error on parsing
def parse!(str, ber: false)
@elements[@root].parse!(str.dup.force_encoding('BINARY'), ber: ber)
end
+ # @overload value
+ # Get value of root element
+ # @return [Object,nil]
+ # @overload value(name)
+ # Direct access to the value of +name+ (nested) element of model.
+ # @param [String,Symbol] name
+ # @return [Object,nil]
+ # @return [Object,nil]
+ def value(name=nil, *args)
+ if name.nil?
+ @elements[@root].value
+ else
+ elt = by_name(name)
+
+ unless args.empty?
+ elt = elt.root if elt.is_a?(Model)
+ args.each do |arg|
+ elt = elt.root if elt.is_a?(Model)
+ elt = elt[arg]
+ end
+ end
+
+ elt.value
+ end
+ end
+
# Delegate some methods to root element
# @param [Symbol] meth
def method_missing(meth, *args)
if @elements[@root].respond_to? meth
@elements[@root].send meth, *args
else
super
end
end
+ # @return [Boolean]
+ def respond_to_missing?(meth, *)
+ @elements[@root].respond_to?(meth) || super
+ end
+
# @return [String]
def inspect(level=0)
' ' * level + "(#{type}) #{root.inspect(-level)}"
end
@@ -324,18 +358,33 @@
# @return [Boolean]
def ==(other)
(other.class == self.class) && (other.to_der == self.to_der)
end
- private
+ protected
- def is_composed?(el)
- [Types::Sequence, Types::Set].include? el.class
+ # Give a (nested) element from its name
+ # @param [String, Symbol] name
+ # @return [Model, Types::Base]
+ def by_name(name)
+ elt = self[name]
+ return elt unless elt.nil?
+
+ keys.each do |subelt_name|
+ if self[subelt_name].is_a?(Model)
+ elt = self[subelt_name][name]
+ return elt unless elt.nil?
+ end
+ end
+
+ nil
end
- def is_of?(el)
- [Types::SequenceOf, Types::SetOf].include? el.class
+ private
+
+ def composed?(elt)
+ [Types::Sequence, Types::Set].include? elt.class
end
def get_type(proc_or_class, options={})
case proc_or_class
when Proc
@@ -351,20 +400,20 @@
@elements = {}
@elements[@root] = get_type(root[1], self.class.options || {})
root
end
- def set_elements(name, el, content=nil)
- if content.is_a? Array
- @elements[name].value = content.map do |name2, proc_or_class, content2|
- subel = get_type(proc_or_class)
- @elements[name2] = subel
- if is_composed?(subel) and content2.is_a? Array
- set_elements(name2, proc_or_class, content2)
- end
- subel
+ def set_elements(name, _elt, content=nil)
+ return unless content.is_a? Array
+
+ @elements[name].value = content.map do |name2, proc_or_class, content2|
+ subel = get_type(proc_or_class)
+ @elements[name2] = subel
+ if composed?(subel) && content2.is_a?(Array)
+ set_elements(name2, proc_or_class, content2)
end
+ subel
end
end
def initialize_elements(obj, args)
args.each do |name, value|
@@ -408,13 +457,14 @@
else
my_element.value.map { |el| private_to_h(el) }
end
when Types::Sequence
seq = my_element.value.map do |el|
- next if el.optional? and el.value.nil?
- name = el.is_a?(Model) ? @elements.key(el) : el.name
- [name, private_to_h(el)]
- end
+ next if el.optional? && el.value.nil?
+
+ name = el.is_a?(Model) ? @elements.key(el) : el.name
+ [name, private_to_h(el)]
+ end
seq.compact!
Hash[seq]
else
my_element.value
end