device-identifier 0.0.1 → 0.0.2

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.
data/README.md CHANGED
@@ -7,11 +7,47 @@ Rationale:
7
7
  - Hard-phones have an Ethernet MAC address.
8
8
  - Soft-phones don't. They have/need some sort of identification string
9
9
  (any sequence of bytes).
10
- - Both are device identifiers, with the MAC address being a sub-class.
10
+ - Soft-phones may use UUIDs as identifiers.
11
+ - All of them are device identifiers, with the MAC address resp. UUID being sub-classes.
11
12
 
12
13
  Author: Philipp Kempgen, [http://kempgen.net](http://kempgen.net)
13
14
 
14
15
 
16
+ ## Usage
17
+
18
+ require 'dev-id'
19
+
20
+ m = DevId::MacAddress.from_hex ""
21
+ m.valid? # => false
22
+
23
+ m = DevId::MacAddress.from_hex "001122aabbcc"
24
+ m.valid? # => true
25
+
26
+ m = DevId::MacAddress.from_hex "00:11:22:aa:bb:cc"
27
+ m.valid? # => true
28
+
29
+ m = DevId::MacAddress.from_hex "00-11-22-AA-BB-CC"
30
+ m.valid? # => true
31
+ m.ascii # => "001122aabbcc"
32
+ m.pretty # => "00:11:22:AA:BB:CC"
33
+ m.to_s # => "00:11:22:AA:BB:CC"
34
+ m.pretty({ :sep => '-', :upcase => false })
35
+ # => "00-11-22-aa-bb-cc"
36
+ m.raw # => "\x00\x11\x22\xAA\xBB\xCC"
37
+ m.bytes.to_a # => [0, 17, 34, 170, 187, 204]
38
+ m.bytesize # => 6
39
+ m.to_int # => 73596058572
40
+ m.starts_with? DevId::MacAddressOui.from_hex '00:11:22'
41
+ # => true
42
+ m.starts_with? DevId::MacAddressPartial.from_hex '00:11:22:aa'
43
+ # => true
44
+
45
+ # MacAddress specific:
46
+ m.null? # => false
47
+ m.multicast? # => false
48
+ m.oui_raw # => "\x00\x11\x22"
49
+
50
+
15
51
  ## Inheritance
16
52
 
17
53
  The class inheritance is as follows:
@@ -31,6 +67,10 @@ The class inheritance is as follows:
31
67
  - **`MacAddress`**
32
68
 
33
69
  Model for a MAC address.
70
+
71
+ - **`DeviceUuid`**
72
+
73
+ Model for a device identifier UUID.
34
74
 
35
75
  - **`MacAddressPartial`**
36
76
 
@@ -43,9 +83,9 @@ The class inheritance is as follows:
43
83
 
44
84
  ## Device identifiers
45
85
 
46
- There are 2 kinds of device identifiers: the generic `DeviceIdentifier` and the more specific `MacAddress`.
86
+ There are 3 kinds of device identifiers: the generic `DeviceIdentifier`, and the more specific `MacAddress` and `DeviceUuid`.
47
87
 
48
- Both support the methods in following (amongst others):
88
+ All of them support the methods in following (amongst others):
49
89
 
50
90
  - `bytes`
51
91
 
@@ -101,6 +141,15 @@ Instance methods:
101
141
 
102
142
  The number of bytes.
103
143
 
144
+ - `getbyte( index )`
145
+
146
+ Returns one of the raw bytes as an integer.
147
+
148
+ - `byteslice( from, len = nil )`
149
+
150
+ Returns a slice (sub-string) of the raw bytes.
151
+ `from` can be an `Integer` or a `Range` – in the latter case `len` must not be specified.
152
+
104
153
  - `length`
105
154
 
106
155
  Alias for `bytesize`.
@@ -161,7 +210,7 @@ Instance methods:
161
210
 
162
211
  - `null?`
163
212
 
164
- If it's a null address (all 6 bytes \x00: 00:00:00:00:00:00).
213
+ If it's a null address (all 6 bytes `\x00`: `00:00:00:00:00:00`).
165
214
 
166
215
  - `pretty( opts = nil )`
167
216
 
@@ -181,6 +230,38 @@ Instance methods:
181
230
  The OUI (vendor) part (first 3 bytes) in raw format.
182
231
 
183
232
 
233
+ ### `DeviceUuid`
234
+
235
+ **Inheritance**:
236
+ `Base` >
237
+ `BinaryAddress` >
238
+ `DeviceIdentifier` >
239
+ `DeviceUuid`
240
+
241
+ Model for a device UUID.
242
+
243
+ Instance methods:
244
+
245
+ - `null?`
246
+
247
+ If it's a null address (all bytes `\x00`: `00000000-0000-0000-0000-000000000000`).
248
+
249
+ - `pretty( opts = nil )`
250
+
251
+ A pretty ASCII representation (hex format).
252
+
253
+ Default options are:
254
+
255
+ {
256
+ :sep => '-', # separator, typically "-"
257
+ :upcase => false, # use uppercase?
258
+ }
259
+
260
+ If the default options are used this method returns the canonical UUID representation.
261
+
262
+ - A couple of UUID specific methods (named `uuid`...).
263
+
264
+
184
265
  ### `MacAddressPartial`
185
266
 
186
267
  **Inheritance**:
@@ -203,4 +284,3 @@ Model for the OUI (vendor) part of a MAC address.
203
284
 
204
285
  Validates that the raw address has a length of 3 bytes.
205
286
 
206
-
@@ -6,4 +6,5 @@ require 'dev-id/base'
6
6
  require 'dev-id/binary_address'
7
7
  require 'dev-id/device_identifier'
8
8
  require 'dev-id/mac_address'
9
+ require 'dev-id/device_uuid'
9
10
 
@@ -1,5 +1,21 @@
1
- require 'dev-id'
2
- require 'active_model'
1
+ #require 'dev-id' # for DevId
2
+ require 'active_model' # for ActiveModel (from the "activemodel" gem)
3
+ #if ! ::ActiveModel.const_defined?( :MassAssignmentSecurity )
4
+ # # ActiveModel::MassAssignmentSecurity is no longer part of the
5
+ # # "activemodel" gem as of version 4, but went into the
6
+ # # "protected_attributes" gem.
7
+ # begin
8
+ # require 'protected_attributes'
9
+ # rescue ::LoadError => e
10
+ # STDERR.puts "------------------------------------------------------------"
11
+ # STDERR.puts "#{e.message} (#{e.class.name})"
12
+ # STDERR.puts (e.backtrace || []).reject{|l| l.match( %r{ /lib/rake/ }x )}.map{|l| " #{l}"}
13
+ # STDERR.puts "------------------------------------------------------------"
14
+ # STDERR.puts "For ActiveModel >= 4 please add the \"protected_attributes\" gem to your bundle."
15
+ # STDERR.puts " ActiveModel version: #{::ActiveModel::VERSION::STRING}"
16
+ # STDERR.puts "------------------------------------------------------------"
17
+ # end
18
+ #end
3
19
 
4
20
  module ::DevId
5
21
 
@@ -7,7 +23,13 @@ module ::DevId
7
23
  class BasicActiveModel
8
24
  extend ::ActiveModel::Naming
9
25
  include ::ActiveModel::Validations
10
- include ::ActiveModel::MassAssignmentSecurity
26
+
27
+ if ::ActiveModel::VERSION::MAJOR <= 3
28
+ include ::ActiveModel::MassAssignmentSecurity
29
+ else
30
+ include ::ActiveModel::ForbiddenAttributesProtection
31
+ end
32
+
11
33
  include ::ActiveModel::Conversion
12
34
  # extend ::ActiveModel::Callbacks
13
35
 
@@ -24,7 +46,11 @@ module ::DevId
24
46
  attributes = new_attributes.stringify_keys
25
47
 
26
48
  unless options[:without_protection]
27
- attributes = sanitize_for_mass_assignment( attributes, options[:as] || :default )
49
+ if ::ActiveModel::VERSION::MAJOR <= 3
50
+ attributes = sanitize_for_mass_assignment( attributes, options[:as] || :default )
51
+ else
52
+ attributes = sanitize_for_mass_assignment( attributes )
53
+ end
28
54
  end
29
55
 
30
56
  attributes.each { |k, v|
@@ -36,6 +36,20 @@ module ::DevId
36
36
  end
37
37
  alias :length :bytesize
38
38
 
39
+ def byteslice( from, len=nil )
40
+ return nil if ! raw
41
+ if len
42
+ raw.byteslice( from, len )
43
+ else
44
+ raw.byteslice( from ) # from can be a Fixnum or a Range
45
+ end
46
+ end
47
+ alias :'[]' :'byteslice'
48
+
49
+ def getbyte( idx )
50
+ (raw || '').getbyte( idx )
51
+ end
52
+
39
53
  # Construct a new instance from a raw string.
40
54
  #
41
55
  def self.from_raw( str )
@@ -129,8 +143,6 @@ module ::DevId
129
143
  return ! (self =~ other)
130
144
  end
131
145
 
132
- #TODO getbyte, [], byteslice
133
-
134
146
  end
135
147
  end
136
148
 
@@ -0,0 +1,237 @@
1
+ require 'dev-id/device_identifier'
2
+ require 'dev-id/binary_address'
3
+ require 'dev-id/mac_address'
4
+
5
+ module ::DevId
6
+
7
+ # Model for a device UUID.
8
+ #
9
+ # 16 bytes.
10
+ #
11
+ class DeviceUuid < DeviceIdentifier
12
+
13
+ validates_length_of :raw, :is => 16
14
+
15
+ # Default options for conversion to ASCII in the `pretty`
16
+ # method.
17
+ DEFAULT_TO_PRETTY_OPTS = {
18
+ :sep => '-', # typically "-"
19
+ :upcase => false,
20
+ }.freeze
21
+
22
+ UUID_VARIANT_NCS = :ncs # 0b0xx, reserved, NCS backward compatibility (also used for the nil UUID)
23
+ UUID_VARIANT_RFC_4122 = :rfc4122 # 0b10x, the variant specified by RFC 4122
24
+ UUID_VARIANT_MICROSOFT = :microsoft # 0b110, reserved, Microsoft backward compatibility
25
+ UUID_VARIANT_FUTURE = :future # 0b111, reserved for future definition
26
+
27
+ # Whether the device UUID is the "nil"/"null" address (16
28
+ # NULL bytes).
29
+ #
30
+ def null?
31
+ return nil if ! valid?
32
+ return raw == (?\0.force_encoding( ::Encoding::ASCII_8BIT ) * 16)
33
+ end
34
+
35
+ # Pretty ASCII representation in UUID format (8-4-4-4-12).
36
+ #
37
+ def pretty( opts = nil )
38
+ return nil if ! valid?
39
+ opts = DEFAULT_TO_PRETTY_OPTS.merge( opts || {} )
40
+ #return ascii( opts )
41
+ #return ::Kernel.sprintf( '%.2x%.2x%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x', * self.bytes )
42
+ uuid_str = raw.unpack( 'H8H4H4H4H12' ).join( opts[:sep] )
43
+ uuid_str = uuid_str.upcase if opts[:upcase]
44
+ return uuid_str
45
+ end
46
+
47
+ # Pretty ASCII representation in UUID format (8-4-4-4-12).
48
+ #
49
+ # This is the same as .pretty with default options
50
+ # ({ :sep => '-', :upcase => false }) but slightly faster.
51
+ #
52
+ def uuid_str
53
+ return nil if ! valid?
54
+ return raw.unpack( 'H8H4H4H4H12' ).join( '-' )
55
+ end
56
+
57
+ # `to_s` is an alias for `pretty`.
58
+ #
59
+ def to_s( opts = nil )
60
+ pretty( opts )
61
+ end
62
+
63
+ def require_uuid_tools
64
+ require 'uuidtools' unless ::Module.const_defined?( :UUIDTools )
65
+ end
66
+ private :require_uuid_tools
67
+
68
+ def uuid
69
+ if @uuid == nil
70
+ if ! valid?
71
+ @uuid = false
72
+ else
73
+ require_uuid_tools()
74
+ @uuid = ::UUIDTools::UUID.parse_raw( raw )
75
+ end
76
+ end
77
+ @uuid
78
+ end
79
+
80
+ # Returns the UUID type (a.k.a. variant).
81
+ #
82
+ # Possible values:
83
+ # - 0b000: reserved, NCS backward compatibility (also used for the nil UUID)
84
+ # - 0b001: ", mapped to 0b000
85
+ # - 0b010: ", mapped to 0b000
86
+ # - 0b011: ", mapped to 0b000
87
+ # - 0b100: the variant specified by RFC 4122
88
+ # - 0b101: ", mapped to 0b100
89
+ # - 0b110: reserved, Microsoft backward compatibility
90
+ # - 0b111: reserved for future definition
91
+ #
92
+ def uuid_variant
93
+ #return nil if ! uuid
94
+ #return uuid.variant
95
+
96
+ return nil if ! valid?
97
+ var_raw = raw.getbyte(8) >> 5
98
+ ret = nil
99
+ if (var_raw >> 2) == 0
100
+ ret = 0x000
101
+ elsif (var_raw >> 1) == 2
102
+ ret = 0x100
103
+ else
104
+ ret = var_raw
105
+ end
106
+ return (ret >> 6)
107
+ end
108
+ alias :uuid_type :uuid_variant
109
+
110
+ def uuid_variant_name
111
+ v = uuid_variant
112
+ {
113
+ 0b100 => UUID_VARIANT_RFC_4122,
114
+ 0b000 => UUID_VARIANT_NCS,
115
+ 0b110 => UUID_VARIANT_MICROSOFT,
116
+ 0b111 => UUID_VARIANT_FUTURE,
117
+ }[ v ]
118
+ end
119
+ alias :uuid_type_name :uuid_variant_name
120
+
121
+ def uuid_variant_ncs?
122
+ v = uuid_variant
123
+ v ? (v == 0b000) : nil
124
+ end
125
+ alias :'uuid_type_ncs?' :'uuid_variant_ncs?'
126
+
127
+ def uuid_variant_rfc4122?
128
+ v = uuid_variant
129
+ v ? (v == 0b100) : nil
130
+ end
131
+ alias :'uuid_type_rfc4122?' :'uuid_variant_rfc4122?'
132
+
133
+ def uuid_variant_microsoft?
134
+ v = uuid_variant
135
+ v ? (v == 0b110) : nil
136
+ end
137
+ alias :'uuid_type_microsoft?' :'uuid_variant_microsoft?'
138
+
139
+ def uuid_variant_future?
140
+ v = uuid_variant
141
+ v ? (v == 0b111) : nil
142
+ end
143
+ alias :'uuid_type_future?' :'uuid_variant_future?'
144
+
145
+ # Returns the UUID sub-type (a.k.a. version).
146
+ #
147
+ # Possible values:
148
+ # - 1: time-based with unique or random host identifier
149
+ # - 2: DCE Security version, with embedded POSIX UIDs
150
+ # - 3: name-based (uses MD5 hash)
151
+ # - 4: random
152
+ # - 5: name-based (uses SHA-1 hash)
153
+ #
154
+ def uuid_version
155
+ #return nil if ! uuid
156
+ #return nil if ! uuid_variant_rfc4122?
157
+ #return uuid.version
158
+
159
+ return nil if ! valid?
160
+ return nil if ! uuid_variant_rfc4122?
161
+ #b6 = self.bytes.to_a[ 6 ]
162
+ b6 = (raw || '').getbyte( 6 )
163
+ return nil if ! b6
164
+ #b6.div( 16 ) # return value
165
+ b6 >> 4 # return value
166
+ end
167
+ alias :uuid_sub_type :uuid_version
168
+
169
+ # Returns the MAC address (lowercase, ":"-separated) used to
170
+ # generate this UUID, or nil if a MAC address was not used.
171
+ # Applies only to version 1 UUIDs with a given (i.e.
172
+ # non-random) node ID.
173
+ #
174
+ def uuid_mac_addr
175
+ #return nil if ! uuid
176
+ #return nil if ! uuid_variant_rfc4122?
177
+ #return uuid.mac_address.upcase
178
+
179
+ return nil if ! valid?
180
+ return nil if ! uuid_variant_rfc4122?
181
+ return nil if uuid_version != 1
182
+ return nil if uuid_random_node_id?
183
+ opts = ::DevId::MacAddress::DEFAULT_TO_PRETTY_OPTS
184
+ return self.byteslice( 10, 6 ).bytes.map{ |b| (opts[:upcase] ? '%02X' : '%02x') % [b] }.join( opts[:sep] )
185
+ end
186
+
187
+ # This method applies only to version 1 UUIDs. Checks if the
188
+ # node ID was generated from a random number or from a MAC
189
+ # address. Always returns `false` for UUIDs that aren't
190
+ # version 1. This should not be confused with version 4
191
+ # UUIDs where more than just the node ID is random.
192
+ #
193
+ def uuid_random_node_id?
194
+ #return nil if ! uuid
195
+ #return nil if ! uuid_variant_rfc4122?
196
+ #return uuid.random_node_id?
197
+
198
+ return nil if ! valid?
199
+ return nil if ! uuid_variant_rfc4122?
200
+ return false if uuid_version != 1
201
+ return ((raw.getbyte( 10 ) & 0x01) == 1)
202
+ end
203
+
204
+ # This method applies only to version 1 UUIDs. Returns the
205
+ # timestamp used to generate this UUID.
206
+ #
207
+ # @return `Time` instance timestamp
208
+ #
209
+ def uuid_timestamp
210
+ return nil if ! uuid
211
+ return nil if ! uuid_variant_rfc4122?
212
+ #return uuid.timestamp
213
+
214
+ return nil if ! valid?
215
+ return nil if ! uuid_variant_rfc4122?
216
+ return nil if uuid_version != 1
217
+
218
+ tlmh = raw.unpack('Nnn') # time_low, time_mid, time_hi_and_version
219
+ t_utc_100_ns = tlmh[0] + (tlmh[1] << 32) + ((tlmh[2] & 0x0FFF) << 48)
220
+
221
+ # Subtract offset between UUID time and Unix time.
222
+ # UUID UTC base time is October 15, 1582 (1582-10-15 00:00:00 Z).
223
+ # Unix UTC base time is January 1, 1970 (1970-01-01 00:00:00 Z).
224
+ return ::Time.at(
225
+ (t_utc_100_ns - 0x01B21DD213814000) / 10000000.0 )
226
+ end
227
+
228
+ # Returns an URI string ("`urn:uuid:`"...) for this UUID.
229
+ #
230
+ def uuid_to_uri
231
+ uuid ? "urn:uuid:#{self.uuid_str}" : nil
232
+ end
233
+ alias :uuid_to_urn :uuid_to_uri
234
+
235
+ end
236
+ end
237
+
@@ -18,13 +18,21 @@ module ::DevId
18
18
  :upcase => true,
19
19
  }.freeze
20
20
 
21
- # Whether the MAC address is a multicast address.
21
+ # Whether the MAC address is a group address (multicast address).
22
22
  #
23
23
  def multicast?
24
24
  return nil if ! valid?
25
25
  return (raw.getbyte(0).to_i % 2) != 0
26
26
  end
27
27
 
28
+ # Whether the MAC address is a local address (as compared to a global address).
29
+ #
30
+ def local?
31
+ return nil if ! valid?
32
+ #return raw.getbyte(0).to_s(2).rjust(8,'0')[-2] == '1'
33
+ return ((raw.getbyte(0).to_i >> 1) % 2) != 0
34
+ end
35
+
28
36
  # Whether the MAC address is the "null" address (6 NULL
29
37
  # bytes).
30
38
  #
@@ -4,7 +4,7 @@
4
4
  module ::DevId
5
5
 
6
6
  # The version of this Gem.
7
- VERSION = [ 0, 0, 1 ].freeze
7
+ VERSION = [ 0, 0, 2 ].freeze
8
8
 
9
9
  # The version of this Gem as a string.
10
10
  VERSION_STR = VERSION.map(& :to_s).join('.').freeze
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: device-identifier
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,16 +9,70 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-17 00:00:00.000000000 Z
12
+ date: 2013-11-27 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: uuidtools
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 2.1.4
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 2.1.4
14
46
  - !ruby/object:Gem::Dependency
15
47
  name: activemodel
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '3'
54
+ - - <
55
+ - !ruby/object:Gem::Version
56
+ version: '5'
57
+ type: :runtime
58
+ prerelease: false
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ! '>='
63
+ - !ruby/object:Gem::Version
64
+ version: '3'
65
+ - - <
66
+ - !ruby/object:Gem::Version
67
+ version: '5'
68
+ - !ruby/object:Gem::Dependency
69
+ name: uuidtools
16
70
  requirement: !ruby/object:Gem::Requirement
17
71
  none: false
18
72
  requirements:
19
73
  - - ~>
20
74
  - !ruby/object:Gem::Version
21
- version: '3.2'
75
+ version: 2.1.4
22
76
  type: :runtime
23
77
  prerelease: false
24
78
  version_requirements: !ruby/object:Gem::Requirement
@@ -26,7 +80,7 @@ dependencies:
26
80
  requirements:
27
81
  - - ~>
28
82
  - !ruby/object:Gem::Version
29
- version: '3.2'
83
+ version: 2.1.4
30
84
  description: Models for device identifiers, e.g. MAC addresses for hardware clients
31
85
  and arbitrary identifier strings for software clients.
32
86
  email:
@@ -37,6 +91,7 @@ files:
37
91
  - lib/dev-id/base.rb
38
92
  - lib/dev-id/binary_address.rb
39
93
  - lib/dev-id/device_identifier.rb
94
+ - lib/dev-id/device_uuid.rb
40
95
  - lib/dev-id/mac_address.rb
41
96
  - lib/dev-id/version.rb
42
97
  - lib/dev-id.rb