rasn1 0.16.3 → 0.17.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 56e418f5906034865b82fd6dd271da80be89d601e4298230b3e36919d13dae22
4
- data.tar.gz: d1f5d699c1e88e10b82a43fd3b9e0105041cb16ab11701751a6183088c2cca33
3
+ metadata.gz: 67e24db40c3ec0a8e7d7ad23211549c1aadda9511ea73f632034a4cdefa97ae0
4
+ data.tar.gz: d8847b0b52cce0014f02772077da519df146c14a1f65ffebc72cc206e888b0cd
5
5
  SHA512:
6
- metadata.gz: a0efd01e244b3e61260eb50ab1317e2f200a2d2a311ae51293f2e409f20086857ff334edd2019358f7929cc14ae657124733848c99abdce80ad67b91c1377a15
7
- data.tar.gz: 83ae40e970a4c185fe9652d10e38ac9cd1effa4c28a0362172cf619c675ce400be4bf2935e889b35ace98f3cfb0cee7ce8923d0dc571e5cc6df0cca829036f4e
6
+ metadata.gz: 12da7b29112a40073dd64e3eb949412cd941932d63fb87e2cf36cf020c1df784cdd85e6e2cd04113f8bf74e7b16c630fad2346b885933874f86dcd329f42511b
7
+ data.tar.gz: a5294cfc1a3ebc0430c1be31558ed1e33ac97e5d87ad8ff3c14d6c8633b251d53b33e7818762f46bb6272c4f71da439a42aa86f79413c3af405b5b3d076777a3
data/README.md CHANGED
@@ -52,7 +52,9 @@ ComplexRecord ::= SEQUENCE {
52
52
  }
53
53
  ```
54
54
 
55
- ### Create a ASN.1 model
55
+ ### Create an ASN.1 model
56
+
57
+ A model is created this way:
56
58
 
57
59
  ```ruby
58
60
  class Record < RASN1::Model
@@ -63,14 +65,31 @@ class Record < RASN1::Model
63
65
  end
64
66
  ```
65
67
 
68
+ or, this ways in a more rubyish style:
69
+
70
+ ```ruby
71
+ # This Record class is defined as a sequence conaining:
72
+ # * an ID (integer)
73
+ # * a room number (integer, with explicit tag, optional)
74
+ # * a house if (integer, with explicit tag and a default value)
75
+ class Record < RASN1::Model
76
+ sequence :record do
77
+ integer(:id)
78
+ integer(:room, implicit: 0, optional: true)
79
+ integer(:house, implicit: 1, default: 0)
80
+ end
81
+ end
82
+ ```
83
+
66
84
  More comple classes may be designed by nesting simple classes. For example:
67
85
 
68
86
  ```ruby
69
87
  class ComplexRecord < RASN1::Model
70
- sequence :cplx_record,
71
- content: [boolean(:bool),
72
- octet_string(:data, explicit: 0),
73
- model(:a_record, Record)]
88
+ sequence :cplx_record do
89
+ boolean(:bool)
90
+ octet_string(:data, explicit: 0)
91
+ model(:a_record, Record) # Use another model in model
92
+ end
74
93
  end
75
94
  ```
76
95
 
@@ -115,10 +134,6 @@ record.set id: 124, house: 155
115
134
  record.to_der # => String
116
135
  ```
117
136
 
118
- ### More information
119
-
120
- see <https://github.com/sdaubert/rasn1/wiki>
121
-
122
137
  ## Contributing
123
138
 
124
- Bug reports and pull requests are welcome on GitHub at <https://github.com/sdaubert/rasn1>.
139
+ Bug reports and pull requests are welcome on GitHub at <https://codeberg.org/lemontree55/rasn1>.
@@ -0,0 +1,229 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is part of RASN1
4
+ # See https://codeberg.org/lemontree55/rasn1 for more informations
5
+ # Copyright (C) 2016-2024 Sylvain Daubert <sylvain.daubert@laposte.net>
6
+ # Copyright (C) 2024 LemonTree55 <lenontree@proton.me>
7
+ # This program is published under MIT license.
8
+
9
+ module RASN1
10
+ class Model
11
+ # Define helper methods to define models
12
+ # @author Sylvain Daubert
13
+ module Accel
14
+ # @return [Hash]
15
+ attr_reader :options
16
+
17
+ # On inheritance, create +@elements+ class variable
18
+ # @param klass [Class]
19
+ # @return [void]
20
+ def inherited(klass)
21
+ super
22
+ current_elements = @elements
23
+ klass.class_eval { @elements = current_elements.dup }
24
+ end
25
+
26
+ # @since 0.17.0
27
+ def elements
28
+ return @elements unless @elements.nil?
29
+
30
+ @elements = []
31
+ end
32
+
33
+ # Use another model in this model
34
+ # @param name [String,Symbol]
35
+ # @param model_klass [Class]
36
+ # @return [Elem]
37
+ def model(name, model_klass)
38
+ push_element(ModelElem.new(name, model_klass))
39
+ end
40
+
41
+ # @since 0.17.0
42
+ # @param [BaseElem, WrapElem, ModelElem] elem
43
+ # @return [BaseElem, WrapElem, ModelElem] elem
44
+ def push_element(elem)
45
+ elements << elem
46
+ elem
47
+ end
48
+
49
+ # @since 0.17.0
50
+ def root
51
+ elements.last
52
+ end
53
+
54
+ # @since 0.17.0
55
+ def root=(elem)
56
+ if elements.empty?
57
+ elements << elem
58
+ else
59
+ elements[-1] = elem
60
+ end
61
+ end
62
+
63
+ # @overload wrapper(element, options={})
64
+ # Use a {Wrapper} around a {Types::Base} or a {Model} object
65
+ # @param element [Types::Base,Model]
66
+ # @param options [Hash]
67
+ # @return [WrapElem]
68
+ # @since 0.12
69
+ # @overload(options={})
70
+ # @param options [Hash]
71
+ # @return [WrapElem]
72
+ # @yieldreturn [BaseElem, ModelElem] element to wrapp
73
+ # @since 0.17.0
74
+ def wrapper(element_or_options={}, options={}, &)
75
+ case element_or_options
76
+ when Hash
77
+ element = generate_content(&).last
78
+ options = element_or_options
79
+ else
80
+ element = element_or_options
81
+ end
82
+ push_element(WrapElem.new(element, options))
83
+ end
84
+
85
+ # Update options of root element.
86
+ # May be used when subclassing.
87
+ # class Model1 < RASN1::Model
88
+ # sequence :seq, implicit: 0,
89
+ # content: [bool(:bool), integer(:int)]
90
+ # end
91
+ #
92
+ # # same as Model1 but with implicit tag set to 1
93
+ # class Model2 < Model1
94
+ # root_options implicit: 1
95
+ # end
96
+ # @param options [Hash]
97
+ # @return [void]
98
+ # @since 0.12.0 may change name through +:name+
99
+ def root_options(options)
100
+ @options = options
101
+ return unless options.key?(:name)
102
+
103
+ self.root = root.dup
104
+ root.name = options[:name]
105
+ end
106
+
107
+ # @private
108
+ # @param accel_name [String,Symbol]
109
+ # @param klass [Class]
110
+ # @since 0.11.0
111
+ # @since 0.12.0 track source location on error (adfoster-r7)
112
+ def define_type_accel_base(accel_name, klass)
113
+ singleton_class.class_eval <<-EVAL, __FILE__, __LINE__ + 1
114
+ def #{accel_name}(name, options={}) # def sequence(name, type, options)
115
+ options[:name] = name
116
+ proc = proc do |opts|
117
+ #{klass}.new(options.merge(opts)) # Sequence.new(options.merge(opts))
118
+ end
119
+ push_element(BaseElem.new(name, proc, nil))
120
+ end
121
+ EVAL
122
+ end
123
+
124
+ # @private
125
+ # @param accel_name [String,Symbol]
126
+ # @param klass [Class]
127
+ # @since 0.17.0
128
+ def define_type_accel_container(accel_name, klass)
129
+ singleton_class.class_eval <<-EVAL, __FILE__, __LINE__ + 1
130
+ def #{accel_name}(name, options={}, &block) # def sequence(name, type, options, &block)
131
+ options[:name] = name
132
+ proc = proc do |opts|
133
+ #{klass}.new(options.merge(opts)) # Sequence.new(options.merge(opts))
134
+ end
135
+ options[:content] ||= []
136
+ options[:content] += generate_content(&block)
137
+ push_element(BaseElem.new(name, proc, options[:content]))
138
+ end
139
+ EVAL
140
+ end
141
+
142
+ # @private
143
+ # @since 0.17.0
144
+ def generate_content
145
+ return [] unless block_given?
146
+
147
+ previous_elements = @elements
148
+ @elements = []
149
+ yield
150
+ content = @elements
151
+ @elements = previous_elements
152
+ content
153
+ end
154
+
155
+ # @private
156
+ # @param accel_name [String,Symbol]
157
+ # @param klass [Class]
158
+ # @since 0.11.0
159
+ # @since 0.12.0 track source location on error (adfoster-r7)
160
+ def define_type_accel_of(accel_name, klass)
161
+ singleton_class.class_eval <<-EVAL, __FILE__, __LINE__ + 1
162
+ def #{accel_name}_of(name, type, options={}) # def sequence_of(name, type, options)
163
+ options[:name] = name
164
+ proc = proc do |opts|
165
+ #{klass}.new(type, options.merge(opts)) # SequenceOf.new(type, options.merge(opts))
166
+ end
167
+ push_element(BaseElem.new(name, proc, nil))
168
+ end
169
+ EVAL
170
+ end
171
+
172
+ # Define an accelarator to access a type in a model definition
173
+ # @param accel_name [String]
174
+ # @param klass [Class] class to instanciate
175
+ # @since 0.11.0
176
+ # @since 0.12.0 track source location on error (adfoster-r7)
177
+ def define_type_accel(accel_name, klass)
178
+ if klass <= Types::SequenceOf
179
+ define_type_accel_of(accel_name, klass)
180
+ elsif (klass <= Types::Sequence) || (klass <= Types::Choice)
181
+ define_type_accel_container(accel_name, klass)
182
+ else
183
+ define_type_accel_base(accel_name, klass)
184
+ end
185
+ end
186
+
187
+ # @param name [Symbol,String] name of object in model
188
+ # @param options [Hash]
189
+ # @return [Elem]
190
+ # @note This method is named +objectid+ and not +object_id+ to not override
191
+ # +Object#object_id+.
192
+ # @see Types::ObjectId#initialize
193
+ def objectid(name, options={})
194
+ options[:name] = name
195
+ proc = proc { |opts| Types::ObjectId.new(options.merge(opts)) }
196
+ push_element(BaseElem.new(name, proc, nil))
197
+ end
198
+
199
+ # @param name [Symbol,String] name of object in model
200
+ # @param options [Hash]
201
+ # @return [Elem]
202
+ # @see Types::Any#initialize
203
+ def any(name, options={})
204
+ options[:name] = name
205
+ proc = proc { |opts| Types::Any.new(options.merge(opts)) }
206
+ push_element(BaseElem.new(name, proc, nil))
207
+ end
208
+
209
+ # Give type name (aka class name)
210
+ # @return [String]
211
+ def type
212
+ return @type if defined? @type
213
+
214
+ @type = self.to_s.gsub(/.*::/, '')
215
+ end
216
+
217
+ # Parse a DER/BER encoded string
218
+ # @param str [String]
219
+ # @param ber [Boolean] accept BER encoding or not
220
+ # @return [Model]
221
+ # @raise [ASN1Error] error on parsing
222
+ def parse(str, ber: false)
223
+ model = new
224
+ model.parse!(str, ber: ber)
225
+ model
226
+ end
227
+ end
228
+ end
229
+ end
data/lib/rasn1/model.rb CHANGED
@@ -6,6 +6,8 @@
6
6
  # Copyright (C) 2024 LemonTree55 <lenontree@proton.me>
7
7
  # This program is published under MIT license.
8
8
 
9
+ require_relative 'model/accel'
10
+
9
11
  module RASN1
10
12
  # @abstract
11
13
  # {Model} class is a base class to define ASN.1 models.
@@ -16,7 +18,8 @@ module RASN1
16
18
  # room [0] IMPLICIT INTEGER OPTIONAL,
17
19
  # house [1] EXPLICIT INTEGER DEFAULT 0
18
20
  # }
19
- # you may create your model like this:
21
+ #
22
+ # You may create your model like this:
20
23
  # class Record < RASN1::Model
21
24
  # sequence(:record,
22
25
  # content: [integer(:id),
@@ -24,6 +27,15 @@ module RASN1
24
27
  # integer(:house, explicit: 1, default: 0)])
25
28
  # end
26
29
  #
30
+ # You may also use block style definition:
31
+ # class Record < RASN1::Model
32
+ # sequence :record do
33
+ # integer :id
34
+ # integer :room, implicit: 0, optional: true
35
+ # integer :house, explicit: 1, default: 0
36
+ # end
37
+ # end
38
+ #
27
39
  # In a model, each element must have a unique name.
28
40
  #
29
41
  # === Parse a DER-encoded string
@@ -47,10 +59,12 @@ module RASN1
47
59
  # == Create a more complex model
48
60
  # Models may be nested. For example:
49
61
  # class Record2 < RASN1::Model
50
- # sequence(:record2,
51
- # content: [boolean(:rented, default: false),
52
- # model(:a_record, Record)])
62
+ # sequence :record2 do
63
+ # boolean :rented, default: false)
64
+ # model :a_record, Record
65
+ # end
53
66
  # end
67
+ #
54
68
  # Set values like this:
55
69
  # record2 = Record2.new
56
70
  # record2[:rented] = true
@@ -67,15 +81,22 @@ module RASN1
67
81
  # this method.
68
82
  # @author Sylvain Daubert
69
83
  # @author adfoster-r7 ModelValidationError, track source location for dynamic class methods
84
+ # @since 0.17 block notation
70
85
  class Model # rubocop:disable Metrics/ClassLength
71
86
  # @private Base Element
72
- BaseElem = Struct.new(:name, :proc, :content) do
87
+ class BaseElem
88
+ attr_accessor :name
89
+ attr_reader :proc, :content, :block
90
+
73
91
  # @param name [String,Symbol]
74
92
  # @param proc [Proc]
75
93
  # @param content [Array,nil]
76
- def initialize(name, proc, content)
94
+ def initialize(name, proc, content, &block)
95
+ @name = name
96
+ @proc = proc
97
+ @content = content
98
+ @block = block
77
99
  check_duplicates(content.map(&:name) + [name]) unless content.nil?
78
- super
79
100
  end
80
101
 
81
102
  private
@@ -111,148 +132,6 @@ module RASN1
111
132
  # @private Sequence types
112
133
  SEQUENCE_TYPES = [Types::Sequence, Types::SequenceOf, Types::Set, Types::SetOf].freeze
113
134
 
114
- # Define helper methods to define models
115
- module Accel
116
- # @return [Hash]
117
- attr_reader :options
118
-
119
- # Use another model in this model
120
- # @param name [String,Symbol]
121
- # @param model_klass [Class]
122
- # @return [Elem]
123
- def model(name, model_klass)
124
- @root = ModelElem.new(name, model_klass)
125
- end
126
-
127
- # Use a {Wrapper} around a {Types::Base} or a {Model} object
128
- # @param element [Types::Base,Model]
129
- # @param options [Hash]
130
- # @return [WrapElem]
131
- # @since 0.12
132
- def wrapper(element, options={})
133
- @root = WrapElem.new(element, options)
134
- end
135
-
136
- # Update options of root element.
137
- # May be used when subclassing.
138
- # class Model1 < RASN1::Model
139
- # sequence :seq, implicit: 0,
140
- # content: [bool(:bool), integer(:int)]
141
- # end
142
- #
143
- # # same as Model1 but with implicit tag set to 1
144
- # class Model2 < Model1
145
- # root_options implicit: 1
146
- # end
147
- # @param options [Hash]
148
- # @return [void]
149
- # @since 0.12.0 may change name through +:name+
150
- def root_options(options)
151
- @options = options
152
- return unless options.key?(:name)
153
-
154
- @root = @root.dup
155
- @root.name = options[:name]
156
- end
157
-
158
- # On inheritance, create +@root+ class variable
159
- # @param klass [Class]
160
- # @return [void]
161
- def inherited(klass)
162
- super
163
- root = @root
164
- klass.class_eval { @root = root }
165
- end
166
-
167
- # @private
168
- # @param accel_name [String,Symbol]
169
- # @param klass [Class]
170
- # @since 0.11.0
171
- # @since 0.12.0 track source location on error (adfoster-r7)
172
- def define_type_accel_base(accel_name, klass)
173
- singleton_class.class_eval <<-EVAL, __FILE__, __LINE__ + 1
174
- def #{accel_name}(name, options={}) # def sequence(name, type, options)
175
- options[:name] = name
176
- proc = proc do |opts|
177
- #{klass}.new(options.merge(opts)) # Sequence.new(options.merge(opts))
178
- end
179
- @root = BaseElem.new(name, proc, options[:content])
180
- end
181
- EVAL
182
- end
183
-
184
- # @private
185
- # @param accel_name [String,Symbol]
186
- # @param klass [Class]
187
- # @since 0.11.0
188
- # @since 0.12.0 track source location on error (adfoster-r7)
189
- def define_type_accel_of(accel_name, klass)
190
- singleton_class.class_eval <<-EVAL, __FILE__, __LINE__ + 1
191
- def #{accel_name}_of(name, type, options={}) # def sequence_of(name, type, options)
192
- options[:name] = name
193
- proc = proc do |opts|
194
- #{klass}.new(type, options.merge(opts)) # SequenceOf.new(type, options.merge(opts))
195
- end
196
- @root = BaseElem.new(name, proc, nil)
197
- end
198
- EVAL
199
- end
200
-
201
- # Define an accelarator to access a type in a model definition
202
- # @param accel_name [String]
203
- # @param klass [Class] class to instanciate
204
- # @since 0.11.0
205
- # @since 0.12.0 track source location on error (adfoster-r7)
206
- def define_type_accel(accel_name, klass)
207
- if klass < Types::SequenceOf
208
- define_type_accel_of(accel_name, klass)
209
- else
210
- define_type_accel_base(accel_name, klass)
211
- end
212
- end
213
-
214
- # @param name [Symbol,String] name of object in model
215
- # @param options [Hash]
216
- # @return [Elem]
217
- # @note This method is named +objectid+ and not +object_id+ to not override
218
- # +Object#object_id+.
219
- # @see Types::ObjectId#initialize
220
- def objectid(name, options={})
221
- options[:name] = name
222
- proc = proc { |opts| Types::ObjectId.new(options.merge(opts)) }
223
- @root = BaseElem.new(name, proc, nil)
224
- end
225
-
226
- # @param name [Symbol,String] name of object in model
227
- # @param options [Hash]
228
- # @return [Elem]
229
- # @see Types::Any#initialize
230
- def any(name, options={})
231
- options[:name] = name
232
- proc = proc { |opts| Types::Any.new(options.merge(opts)) }
233
- @root = BaseElem.new(name, proc, nil)
234
- end
235
-
236
- # Give type name (aka class name)
237
- # @return [String]
238
- def type
239
- return @type if defined? @type
240
-
241
- @type = self.to_s.gsub(/.*::/, '')
242
- end
243
-
244
- # Parse a DER/BER encoded string
245
- # @param str [String]
246
- # @param ber [Boolean] accept BER encoding or not
247
- # @return [Model]
248
- # @raise [ASN1Error] error on parsing
249
- def parse(str, ber: false)
250
- model = new
251
- model.parse!(str, ber: ber)
252
- model
253
- end
254
- end
255
-
256
135
  extend Accel
257
136
 
258
137
  # @!method sequence(name, options)
@@ -274,7 +153,7 @@ module RASN1
274
153
  # @return [Elem]
275
154
  # @see Types::Choice#initialize
276
155
  %w[sequence set choice].each do |type|
277
- self.define_type_accel_base(type, Types.const_get(type.capitalize))
156
+ self.define_type_accel_container(type, Types.const_get(type.capitalize))
278
157
  end
279
158
 
280
159
  # @!method sequence_of(name, type, options)
@@ -610,7 +489,7 @@ module RASN1
610
489
  # @return [void]
611
490
  def generate_root(args)
612
491
  opts = args.slice(:name, :explicit, :implicit, :optional, :class, :default, :constructed, :tag_value)
613
- root = self.class.class_eval { @root }
492
+ root = self.class.root
614
493
  root_options = self.class.options || {}
615
494
  root_options.merge!(opts)
616
495
  @root_name = args[:name] || root.name
data/lib/rasn1/tracer.rb CHANGED
@@ -38,6 +38,12 @@ module RASN1
38
38
  level ||= @tracing_level
39
39
  ' ' * level
40
40
  end
41
+
42
+ def higher_tracing_level
43
+ self.tracing_level += 1
44
+ yield
45
+ self.tracing_level -= 1
46
+ end
41
47
  end
42
48
 
43
49
  # Trace RASN1 parsing to +io+.
@@ -107,9 +113,7 @@ module RASN1
107
113
  # @return [void]
108
114
  # @see #parse!
109
115
  def do_parse_explicit_with_tracing(data)
110
- RASN1.tracer.tracing_level += 1
111
- do_parse_explicit_without_tracing(data)
112
- RASN1.tracer.tracing_level -= 1
116
+ RASN1.tracer.higher_tracing_level { do_parse_explicit_without_tracing(data) }
113
117
  end
114
118
  end
115
119
 
@@ -163,9 +167,7 @@ module RASN1
163
167
  # der_to_value +der+ with tracing abillity
164
168
  # @!macro do_parse
165
169
  def der_to_value_with_tracing(der, ber: false)
166
- RASN1.tracer.tracing_level += 1
167
- der_to_value_without_tracing(der, ber: ber)
168
- RASN1.tracer.tracing_level -= 1
170
+ RASN1.tracer.higher_tracing_level { der_to_value_without_tracing(der, ber: ber) }
169
171
  end
170
172
  end
171
173
 
@@ -191,9 +193,7 @@ module RASN1
191
193
  # der_to_value +der+ with tracing abillity
192
194
  # @!macro do_parse
193
195
  def der_to_value_with_tracing(der, ber: false)
194
- RASN1.tracer.tracing_level += 1
195
- der_to_value_without_tracing(der, ber: ber)
196
- RASN1.tracer.tracing_level -= 1
196
+ RASN1.tracer.higher_tracing_level { der_to_value_without_tracing(der, ber: ber) }
197
197
  end
198
198
  end
199
199
  end
@@ -101,19 +101,11 @@ module RASN1
101
101
  # Compute TZ from +date_hour+ string
102
102
  # @param date_hour [String]
103
103
  # @return [String]
104
- # @note
105
- # Ruby 3.0: special handle for timezone
106
- # * From 3.1: "Z" and "-0100" are supported
107
- # * Below 3.1: should be "-01:00" or "+00:00"
108
104
  def compute_tz(date_hour)
109
105
  if date_hour.end_with?('Z')
110
106
  date_hour.slice!(-1, 1)
111
- '+00:00' # Ruby 3.0: to remove after end-of support of ruby 3.0
112
107
  elsif date_hour.match?(/[+-]\d+$/)
113
- # Ruby 3.0
114
- # date_hour.slice!(-5, 5)
115
- zone = date_hour.slice!(-5, 5).to_s
116
- "#{zone[0, 3]}:#{zone[3, 2]}"
108
+ date_hour.slice!(-5, 5)
117
109
  end
118
110
  end
119
111
 
data/lib/rasn1/version.rb CHANGED
@@ -8,5 +8,5 @@
8
8
 
9
9
  module RASN1
10
10
  # RASN1 version number
11
- VERSION = '0.16.3'
11
+ VERSION = '0.17.0'
12
12
  end
data/lib/rasn1.rb CHANGED
@@ -41,16 +41,16 @@ module RASN1
41
41
  size = type.parse!(der, ber: ber)
42
42
 
43
43
  if CONTAINER_CLASSES.include?(type.class)
44
- RASN1.tracer.tracing_level += 1 unless RASN1.tracer.nil?
44
+ RASN1.tracer&.tracing_level += 1
45
45
  content = self.parse(type.value)
46
- type.value = content.is_a?(Array) ? content : [content]
47
- RASN1.tracer.tracing_level -= 1 unless RASN1.tracer.nil?
46
+ type.value = Array(content)
47
+ RASN1.tracer&.tracing_level -= 1
48
48
  end
49
49
 
50
50
  result << type
51
51
  der = der[size..]
52
52
  end
53
53
 
54
- result.size == 1 ? result[0] : result
54
+ result.size == 1 ? result.first : result
55
55
  end
56
56
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rasn1
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.3
4
+ version: 0.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - LemonTree55
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-11-21 00:00:00.000000000 Z
11
+ date: 2026-08-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: strptime
@@ -40,6 +40,7 @@ files:
40
40
  - lib/rasn1.rb
41
41
  - lib/rasn1/errors.rb
42
42
  - lib/rasn1/model.rb
43
+ - lib/rasn1/model/accel.rb
43
44
  - lib/rasn1/tracer.rb
44
45
  - lib/rasn1/types.rb
45
46
  - lib/rasn1/types/any.rb
@@ -91,14 +92,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
91
92
  requirements:
92
93
  - - ">="
93
94
  - !ruby/object:Gem::Version
94
- version: 3.0.0
95
+ version: 3.1.0
95
96
  required_rubygems_version: !ruby/object:Gem::Requirement
96
97
  requirements:
97
98
  - - ">="
98
99
  - !ruby/object:Gem::Version
99
100
  version: '0'
100
101
  requirements: []
101
- rubygems_version: 3.2.33
102
+ rubygems_version: 3.3.27
102
103
  signing_key:
103
104
  specification_version: 4
104
105
  summary: Ruby ASN.1 library