device-identifier 0.0.1

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 ADDED
@@ -0,0 +1,206 @@
1
+ # Device identifier models
2
+
3
+ Models for device identifiers, e.g. MAC addresses and other identifiers for VoIP phones.
4
+
5
+ Rationale:
6
+
7
+ - Hard-phones have an Ethernet MAC address.
8
+ - Soft-phones don't. They have/need some sort of identification string
9
+ (any sequence of bytes).
10
+ - Both are device identifiers, with the MAC address being a sub-class.
11
+
12
+ Author: Philipp Kempgen, [http://kempgen.net](http://kempgen.net)
13
+
14
+
15
+ ## Inheritance
16
+
17
+ The class inheritance is as follows:
18
+
19
+ - **`Base`**
20
+
21
+ Base model class, providing validations etc.
22
+
23
+ - **`BinaryAddress`**
24
+
25
+ Model for a raw binary address.
26
+
27
+ - **`DeviceIdentifier`**
28
+
29
+ Model for a device identifier.
30
+
31
+ - **`MacAddress`**
32
+
33
+ Model for a MAC address.
34
+
35
+ - **`MacAddressPartial`**
36
+
37
+ Model for a partial MAC address.
38
+
39
+ - **`MacAddressOui`**
40
+
41
+ Model for the OUI (vendor part) of a MAC address.
42
+
43
+
44
+ ## Device identifiers
45
+
46
+ There are 2 kinds of device identifiers: the generic `DeviceIdentifier` and the more specific `MacAddress`.
47
+
48
+ Both support the methods in following (amongst others):
49
+
50
+ - `bytes`
51
+
52
+ The raw bytes.
53
+
54
+ - `ascii( opts = nil )`
55
+
56
+ An ASCII representation (hex format).
57
+
58
+ - `to_s( opts = nil )`
59
+
60
+ An ASCII representation (hex format).
61
+
62
+
63
+ ## Classes
64
+
65
+
66
+ ### `Base`
67
+
68
+ Includes some `ActiveModel` mix-ins (`ActiveModel::Validations` etc.).
69
+
70
+ Provides methods such as `valid?`.
71
+
72
+
73
+ ### `BinaryAddress`
74
+
75
+ **Inheritance**:
76
+ `Base` >
77
+ `BinaryAddress`
78
+
79
+ Model for a raw binary address.
80
+
81
+ Includes the `::Comparable` mix-in.
82
+
83
+ Class methods:
84
+
85
+ - `self.from_raw( str )`
86
+
87
+ Initializer. Creates a new object from a raw representation.
88
+
89
+ - `self.from_hex( str )`
90
+
91
+ Initializer. Creates a new object from a hex representation,
92
+ with or without "`:`" or "`-`" separators.
93
+
94
+ Instance methods:
95
+
96
+ - `bytes`
97
+
98
+ The raw bytes.
99
+
100
+ - `bytesize`
101
+
102
+ The number of bytes.
103
+
104
+ - `length`
105
+
106
+ Alias for `bytesize`.
107
+
108
+ - `ascii( opts = nil )`
109
+
110
+ An ASCII representation (hex format).
111
+
112
+ Default options are:
113
+
114
+ {
115
+ :sep => '', # separator, typically ":" or "-" or ""
116
+ :upcase => false, # use uppercase?
117
+ }
118
+
119
+ Returns `nil` if invalid.
120
+
121
+ - `to_int`
122
+
123
+ An integer representation.
124
+
125
+ - `starts_with?( other )`
126
+
127
+ Whether it starts with the other `BinaryAddress`.
128
+
129
+ - `start_with?( other )`
130
+
131
+ Alias for `starts_with?( other )`.
132
+
133
+
134
+ ### `DeviceIdentifier`
135
+
136
+ **Inheritance**:
137
+ `Base` >
138
+ `BinaryAddress` >
139
+ `DeviceIdentifier`
140
+
141
+ Model for a device identifier.
142
+
143
+ Validates that the raw address has a minimum length of 1 byte.
144
+
145
+
146
+ ### `MacAddress`
147
+
148
+ **Inheritance**:
149
+ `Base` >
150
+ `BinaryAddress` >
151
+ `DeviceIdentifier` >
152
+ `MacAddress`
153
+
154
+ Model for a MAC address.
155
+
156
+ Instance methods:
157
+
158
+ - `multicast?`
159
+
160
+ If it's a multicast MAC address (integer value of first byte odd).
161
+
162
+ - `null?`
163
+
164
+ If it's a null address (all 6 bytes \x00: 00:00:00:00:00:00).
165
+
166
+ - `pretty( opts = nil )`
167
+
168
+ A pretty ASCII representation (hex format).
169
+
170
+ Default options are:
171
+
172
+ {
173
+ :sep => ':', # separator, typically ":" or "-" or ""
174
+ :upcase => true, # use uppercase?
175
+ }
176
+
177
+ The default options are the same as for the inherited `ascii` method, except that the separator is "`:`" instead of "".
178
+
179
+ - `oui_raw`
180
+
181
+ The OUI (vendor) part (first 3 bytes) in raw format.
182
+
183
+
184
+ ### `MacAddressPartial`
185
+
186
+ **Inheritance**:
187
+ `Base` >
188
+ `BinaryAddress` >
189
+ `MacAddressPartial`
190
+
191
+ Model for a partial MAC address.
192
+
193
+
194
+ ### `MacAddressOui`
195
+
196
+ **Inheritance**:
197
+ `Base` >
198
+ `BinaryAddress` >
199
+ `MacAddressPartial` >
200
+ `MacAddressOui`
201
+
202
+ Model for the OUI (vendor) part of a MAC address.
203
+
204
+ Validates that the raw address has a length of 3 bytes.
205
+
206
+
@@ -0,0 +1,59 @@
1
+ require 'dev-id'
2
+ require 'active_model'
3
+
4
+ module ::DevId
5
+
6
+ # @private
7
+ class BasicActiveModel
8
+ extend ::ActiveModel::Naming
9
+ include ::ActiveModel::Validations
10
+ include ::ActiveModel::MassAssignmentSecurity
11
+ include ::ActiveModel::Conversion
12
+ # extend ::ActiveModel::Callbacks
13
+
14
+ validate :before, :do_before_validation
15
+
16
+ def initialize( attrs={} )
17
+ assign_attributes( attrs )
18
+ end
19
+
20
+ # see `activerecord/lib/active_record/attribute_assignment.rb`
21
+ def assign_attributes( new_attributes, options={} )
22
+ return unless new_attributes.present?
23
+
24
+ attributes = new_attributes.stringify_keys
25
+
26
+ unless options[:without_protection]
27
+ attributes = sanitize_for_mass_assignment( attributes, options[:as] || :default )
28
+ end
29
+
30
+ attributes.each { |k, v|
31
+ #setter_name = :"#{k}="
32
+ #send( setter_name, v ) if respond_to?( setter_name )
33
+ send( :"#{k}=", v )
34
+ }
35
+
36
+ #self
37
+ nil
38
+ end
39
+
40
+ def persisted?
41
+ false
42
+ end
43
+
44
+ def do_before_validation
45
+ @errors.clear
46
+ before_validation()
47
+ end
48
+
49
+ def before_validation
50
+ # override in sub-classes
51
+ end
52
+ end
53
+
54
+ # @private
55
+ class Base < BasicActiveModel
56
+ end
57
+
58
+ end
59
+
@@ -0,0 +1,136 @@
1
+ require 'dev-id/base'
2
+ require 'scanf'
3
+
4
+ module ::DevId
5
+
6
+ # Model for a raw binary address.
7
+ #
8
+ class BinaryAddress < Base
9
+
10
+ include ::Comparable
11
+
12
+ # The raw address.
13
+ attr_accessor :raw
14
+
15
+ def before_validation
16
+ if raw
17
+ raw = raw.to_s.force_encoding( ::Encoding::ASCII_8BIT )
18
+ end
19
+ end
20
+
21
+ validates_presence_of :raw
22
+
23
+ # Default options for conversion to ASCII in the `ascii`
24
+ # method.
25
+ DEFAULT_TO_ASCII_OPTS = {
26
+ :sep => '', # typically ":" or "-" or ""
27
+ :upcase => false,
28
+ }.freeze
29
+
30
+ def bytes
31
+ (raw || '').bytes
32
+ end
33
+
34
+ def bytesize
35
+ (raw || '').bytesize
36
+ end
37
+ alias :length :bytesize
38
+
39
+ # Construct a new instance from a raw string.
40
+ #
41
+ def self.from_raw( str )
42
+ addr = self.new( :raw => str )
43
+ end
44
+
45
+ # Construct a new instance from a hex string.
46
+ #
47
+ def self.from_hex( str )
48
+ addr = self.new()
49
+ str = str.to_s.dup
50
+ str.force_encoding( ::Encoding::ASCII_8BIT )
51
+ str.gsub!( /[:\-]/, '' )
52
+ raw = str.scanf( '%2X' ) { |x,| x.to_i.chr( ::Encoding::ASCII_8BIT ) }.
53
+ join( ''.force_encoding( ::Encoding::ASCII_8BIT ) )
54
+ addr.raw = raw
55
+ return addr
56
+ end
57
+
58
+ # ASCII representation.
59
+ #
60
+ def ascii( opts = nil )
61
+ return nil if ! valid?
62
+ opts = DEFAULT_TO_ASCII_OPTS.merge( opts || {} )
63
+ return self.bytes.map{ |b| (opts[:upcase] ? '%02X' : '%02x') % [b] }.join( opts[:sep] )
64
+ end
65
+
66
+ # `to_s` is an alias for `ascii`.
67
+ #
68
+ def to_s( opts = nil )
69
+ ascii( opts )
70
+ end
71
+
72
+ # If `other` is of the same class, compares the raw values.
73
+ # Returns `nil` unless `self` and `other` have a raw address.
74
+ # Returns `nil` if `other` is an instance of a different class.
75
+ #
76
+ def <=>( other )
77
+ return nil unless other.kind_of?( BinaryAddress )
78
+ return nil unless (self.raw && other.raw)
79
+ return self.raw <=> other.raw #OPTIMIZE ?
80
+ end
81
+
82
+ # `to_int` helps with `include?`.
83
+ #
84
+ # http://rhnh.net/2009/08/03/range-include-in-ruby-1-9
85
+ #
86
+ # Note: ActiveSupport (as of Version 3.2.1) messes with
87
+ # Range#include?() (in
88
+ # `lib/active_support/core_ext/range/include_range.rb`)
89
+ # even though they say "The native Range#include? behavior
90
+ # is untouched.", so you will have to use Range#cover?()
91
+ # instead.
92
+ #
93
+ def to_int
94
+ v = 0
95
+ self.bytes.to_a.reverse.each_with_index { |b,i|
96
+ vb = b
97
+ i.times {
98
+ vb = vb << 8
99
+ }
100
+ v += vb
101
+ }
102
+ return v
103
+ end
104
+
105
+ def ==( other )
106
+ return super unless other.kind_of?( BinaryAddress )
107
+ return false unless (self.raw && other.raw)
108
+ return self.raw == other.raw
109
+ end
110
+ alias :'eql?' :'=='
111
+
112
+ def starts_with?( other )
113
+ return super unless other.kind_of?( BinaryAddress )
114
+ return false unless (self.raw && other.raw)
115
+ return self.raw.start_with?( other.raw )
116
+ end
117
+ alias :'start_with?' :'starts_with?'
118
+
119
+ def =~( other )
120
+ return super unless other.kind_of?( BinaryAddress )
121
+ return false unless (self.raw && other.raw)
122
+ return (self.bytesize > other.bytesize) ?
123
+ self .raw.start_with?( other.raw ) :
124
+ other.raw.start_with?( self .raw )
125
+ end
126
+ alias :'eql?' :'=='
127
+
128
+ def !~( other )
129
+ return ! (self =~ other)
130
+ end
131
+
132
+ #TODO getbyte, [], byteslice
133
+
134
+ end
135
+ end
136
+
@@ -0,0 +1,14 @@
1
+ require 'dev-id/binary_address'
2
+ require 'scanf'
3
+
4
+ module ::DevId
5
+
6
+ # Model for a device identifier.
7
+ #
8
+ class DeviceIdentifier < BinaryAddress
9
+
10
+ validates_length_of :raw, :minimum => 1, :allow_blank => false, :allow_nil => true
11
+
12
+ end
13
+ end
14
+
@@ -0,0 +1,80 @@
1
+ require 'dev-id/device_identifier'
2
+ require 'dev-id/binary_address'
3
+
4
+ module ::DevId
5
+
6
+ # Model for a MAC address.
7
+ #
8
+ # 6 bytes.
9
+ #
10
+ class MacAddress < DeviceIdentifier
11
+
12
+ validates_length_of :raw, :is => 6
13
+
14
+ # Default options for conversion to ASCII in the `pretty`
15
+ # method.
16
+ DEFAULT_TO_PRETTY_OPTS = {
17
+ :sep => ':', # typically ":" or "-" or ""
18
+ :upcase => true,
19
+ }.freeze
20
+
21
+ # Whether the MAC address is a multicast address.
22
+ #
23
+ def multicast?
24
+ return nil if ! valid?
25
+ return (raw.getbyte(0).to_i % 2) != 0
26
+ end
27
+
28
+ # Whether the MAC address is the "null" address (6 NULL
29
+ # bytes).
30
+ #
31
+ def null?
32
+ return nil if ! valid?
33
+ return raw == (?\0.force_encoding( ::Encoding::ASCII_8BIT ) * 6)
34
+ end
35
+
36
+ # Pretty ASCII representation.
37
+ #
38
+ def pretty( opts = nil )
39
+ return nil if ! valid?
40
+ opts = DEFAULT_TO_PRETTY_OPTS.merge( opts || {} )
41
+ return ascii( opts )
42
+ end
43
+
44
+ # The OUI (vendor part) as a raw string.
45
+ #
46
+ def oui_raw
47
+ return nil if ! valid?
48
+ return raw.byteslice( 0, 3 )
49
+ end
50
+
51
+ # `to_s` is an alias for `pretty`.
52
+ #
53
+ def to_s( opts = nil )
54
+ pretty( opts )
55
+ end
56
+
57
+ end
58
+ end
59
+
60
+ module ::DevId
61
+
62
+ # Model for a partial MAC address.
63
+ #
64
+ class MacAddressPartial < BinaryAddress
65
+ end
66
+ end
67
+
68
+ module ::DevId
69
+
70
+ # Model for the OUI (vendor part) of a MAC address.
71
+ #
72
+ # 3 bytes.
73
+ #
74
+ class MacAddressOui < MacAddressPartial
75
+
76
+ validates_length_of :raw, :is => 3
77
+
78
+ end
79
+ end
80
+
@@ -0,0 +1,13 @@
1
+ # This file should not require anything, as it's loaded in the
2
+ # `*.gemspec` file.
3
+
4
+ module ::DevId
5
+
6
+ # The version of this Gem.
7
+ VERSION = [ 0, 0, 1 ].freeze
8
+
9
+ # The version of this Gem as a string.
10
+ VERSION_STR = VERSION.map(& :to_s).join('.').freeze
11
+
12
+ end
13
+
data/lib/dev-id.rb ADDED
@@ -0,0 +1,9 @@
1
+ # `DevId` namespace
2
+ module ::DevId
3
+ end
4
+
5
+ require 'dev-id/base'
6
+ require 'dev-id/binary_address'
7
+ require 'dev-id/device_identifier'
8
+ require 'dev-id/mac_address'
9
+
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: device-identifier
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Philipp Kempgen
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-04-17 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activemodel
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '3.2'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '3.2'
30
+ description: Models for device identifiers, e.g. MAC addresses for hardware clients
31
+ and arbitrary identifier strings for software clients.
32
+ email:
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - lib/dev-id/base.rb
38
+ - lib/dev-id/binary_address.rb
39
+ - lib/dev-id/device_identifier.rb
40
+ - lib/dev-id/mac_address.rb
41
+ - lib/dev-id/version.rb
42
+ - lib/dev-id.rb
43
+ - README.md
44
+ homepage: https://github.com/philipp-kempgen/device-identifier
45
+ licenses: []
46
+ post_install_message:
47
+ rdoc_options: []
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ requirements: []
63
+ rubyforge_project:
64
+ rubygems_version: 1.8.25
65
+ signing_key:
66
+ specification_version: 3
67
+ summary: Models for device identifiers.
68
+ test_files: []
69
+ has_rdoc: