music_ids 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0dcfa17ed18001f410a21d829f1b76e908d4434e
4
- data.tar.gz: cc4b1fb8380914370cab6d9de1b1748f70ee4299
3
+ metadata.gz: ab2b1cbddfb673d888c9dbf7f493cf87b4536c99
4
+ data.tar.gz: 7a3eb549ec25b0cce0af4424e7f981d237b9eb8f
5
5
  SHA512:
6
- metadata.gz: e1a729e07cea652ccacf911a0712b6b2a5c1696661ada9c65ebff2150edda6ab4a4bd461cfc9065e32f03bac7681f5ab968c72e206211c3095d471e1314e3e9d
7
- data.tar.gz: eafd21cf4c04b24c2fd9980343cc6d15bfbd9962836a1ebaa2560c07d6d393bbf8e8850cb87f14bf2c972ada9013e9d5fe981037033e7ee147aa43dec6de2403
6
+ metadata.gz: b955c505b78a891e7ca4fc2f03d9baddb7506e0c6faf97af297b17ec5b5594184ea41e587b24bf5cbabcad2a0a24a85be1ef1cd3129e9fc1a059dea3dcd10e66
7
+ data.tar.gz: eb5119e0309675bd2abf35eb71297f25e65f7ea95a87fa8387f91d745c6a48a73b377b938ac26b80fbcac5eb017a0e45ff3c61a3b4363bc3674bcd01c30b11b9
@@ -1,3 +1,5 @@
1
+ require 'music_ids/id'
2
+
1
3
  module MusicIds
2
4
  # The GRid class represents a Global Release Identifier, and
3
5
  # provides simple methods to parse and re-present them.
@@ -8,7 +10,7 @@ module MusicIds
8
10
  # often used as key identifiers in the delivery and reporting of digital
9
11
  # music products.
10
12
  #
11
- # You can get more details from
13
+ # You can get more details from
12
14
  # https://en.wikipedia.org/wiki/Global_Release_Identifier and
13
15
  # http://www.ifpi.org/grid.php
14
16
  #
@@ -33,112 +35,51 @@ module MusicIds
33
35
  # instance that will return <tt>false</tt> from <tt>#ok?</tt> and will return
34
36
  # nil from all the component methods like <tt>#issuer</tt>
35
37
  class GRid
36
- # See http://www.ifpi.org/downloads/GRid_Standard_v2_1.pdf §5
37
- WELL_FORMED_INPUT = /\AA1-?[A-Z0-9]{5}-?[A-Z0-9]{10}-?[A-Z0-9]\Z/
38
-
39
- class << self
40
- # Parse a GRid string into a GRid instance
41
- #
42
- # @param input [String] The input GRid string to parse
43
- # @param opts [Hash] Parsing options
44
- # @option opts [true, false] :relaxed (false) Whether to parse in relaxed mode
45
- # @return [GRid] the grid instance
46
- def parse(input, opts = {})
47
- input = input.to_s.upcase
48
- opts[:relaxed] ? parse_relaxed(input) : parse_strict(input)
49
- end
50
-
51
- private
52
-
53
- def parse_strict(input)
54
- if WELL_FORMED_INPUT.match(input)
55
- new(input.gsub('-', ''))
56
- else
57
- raise ArgumentError, "'#{input}' is not the right length to be a 12- or 15-character ISRC"
58
- end
59
- end
60
-
61
- def parse_relaxed(input)
62
- if WELL_FORMED_INPUT.match(input)
63
- new(input.gsub('-', ''))
64
- else
65
- new(input, ok: false)
66
- end
67
- end
68
- end
38
+ include Id
69
39
 
70
- # @api private
71
- # @param grid_string [String] The GRid string
72
- # @param opts [Hash]
73
- # @option opts [true, false] :ok (true) Whether the GRid is well-formed or not
74
- def initialize(grid_string, opts = {ok: true})
75
- @grid_string = grid_string.dup.freeze
76
- @ok = opts[:ok] ? true : false
40
+ # See http://www.ifpi.org/downloads/GRid_Standard_v2_1.pdf §5
41
+ def self.id_blocks
42
+ ['A1', '[A-Z0-9]{5}', '[A-Z0-9]{10}', '[A-Z0-9]']
77
43
  end
78
44
 
79
- # Is this a well-formed GRid?
80
- # @return [true,false]
81
- def ok?
82
- @ok
45
+ # The prefix to use for generating a prefixed string representation of the GRID
46
+ # (see http://www.ifpi.org/downloads/GRid_Standard_v2_1.pdf §6
47
+ def self.prefix
48
+ @prefix ||= 'GRID'.freeze
83
49
  end
84
50
 
85
51
  # Return the GRid's two-letter scheme identifier
86
52
  # @return [String]
87
53
  def scheme
88
- return unless ok?
89
- @scheme ||= @grid_string[0,2].freeze
54
+ fetch(:@scheme) { |grid_string| grid_string[0,2] }
90
55
  end
91
56
 
92
57
  # Return the GRid's 5-character issuer code
93
58
  # @return [String]
94
59
  def issuer
95
- return unless ok?
96
- @issuer ||= @grid_string[2,5].freeze
60
+ fetch(:@issuer) { |grid_string| grid_string[2,5] }
97
61
  end
98
62
 
99
63
  # Return the GRid's 10-character release number.
100
64
  # @return [String]
101
65
  def release
102
- return unless ok?
103
- @release ||= @grid_string[7,10].freeze
66
+ fetch(:@release) { |grid_string| grid_string[7,10] }
104
67
  end
105
68
 
106
69
  # Return the GRid's check character.
107
70
  # @return [String]
108
71
  def check
109
- return unless ok?
110
- @check ||= @grid_string[17,1].freeze
111
- end
112
-
113
- # return the GRid as a normalised 18-character string
114
- # @reuturn [String]
115
- def to_s
116
- @grid_string.dup
72
+ fetch(:@check) { |grid_string| grid_string[17,1] }
117
73
  end
118
74
 
119
75
  def to_grid
120
76
  self
121
77
  end
122
78
 
123
- def ==(other)
124
- to_s == other.to_s
125
- end
126
-
127
- # Returns the GRid as a string, either the 18-character normalised string
128
- # (:data) or the 21-character display string (:full). Note that a
129
- # badly-formed GRid will simply return the original string whichever format
130
- # you ask for.
131
- # @param format [:data, :full] the output format to use
79
+ # Generate the hyphen-separated full display GRid string
132
80
  # @return [String]
133
- def as(format)
134
- case format
135
- when :data
136
- to_s
137
- when :full
138
- ok? ? "#{scheme}-#{issuer}-#{release}-#{check}" : to_s
139
- else
140
- raise ArgumentError, "format must be one of [:data, :full], but it was #{format.inspect}"
141
- end
81
+ def as_full
82
+ "#{scheme}-#{issuer}-#{release}-#{check}"
142
83
  end
143
84
  end
144
85
  end
@@ -0,0 +1,105 @@
1
+ module MusicIds
2
+ module Id
3
+ module ClassMethods
4
+ # Parse an identifier string into an instance
5
+ #
6
+ # @param input [String] The input identifier string to parse
7
+ # @param opts [Hash] Parsing options
8
+ # @option opts [true, false] :relaxed (false) Whether to parse in relaxed mode
9
+ # @return [ISRC] the ISRC instance
10
+ def parse(input, opts = {})
11
+ input = input.to_s.upcase
12
+ opts[:relaxed] ? parse_relaxed(input) : parse_strict(input)
13
+ end
14
+
15
+ private
16
+
17
+ def well_formed_id_matcher
18
+ @matcher ||= begin
19
+ Regexp.compile("\\A(?:#{prefix}:)?(#{id_blocks.join('-')}|#{id_blocks.join('')})\\Z")
20
+ end
21
+ end
22
+
23
+ def parse_strict(input)
24
+ parse_string(input) { |input|
25
+ raise ArgumentError, "'#{input}' is not the right length to be a #{self.class}"
26
+ }
27
+ end
28
+
29
+ def parse_relaxed(input)
30
+ parse_string(input) { |input|
31
+ new(input, ok: false)
32
+ }
33
+ end
34
+
35
+ def parse_string(input)
36
+ if match = well_formed_id_matcher.match(input)
37
+ new(match[1].gsub('-', ''))
38
+ else
39
+ yield(input)
40
+ end
41
+ end
42
+ end
43
+
44
+ def self.included(base)
45
+ base.extend(ClassMethods)
46
+ end
47
+
48
+ # @api private
49
+ # @param isrc_string [String] The ISRC string
50
+ # @param opts [Hash]
51
+ # @option opts [true, false] :ok (true) Whether the ISRC is well-formed or not
52
+ def initialize(id_string, opts = {ok: true})
53
+ @id_string = id_string.dup.freeze
54
+ @ok = opts[:ok] ? true : false
55
+ end
56
+
57
+ # Is this a well-formed ID?
58
+ # @return [true,false]
59
+ def ok?
60
+ @ok
61
+ end
62
+
63
+ # return the ID as a normalised string
64
+ # @return [String]
65
+ def to_s
66
+ @id_string.dup
67
+ end
68
+
69
+ def ==(other)
70
+ to_s == other.to_s
71
+ end
72
+
73
+ # Returns the ID as a string, either as the normalised canonical string
74
+ # (:data) or the format specified for 'full' display (:full). Note that a
75
+ # badly-formed ID will simply return the original string whichever format
76
+ # you ask for.
77
+ # @param format [:data, :full, :prefixed] the output format to use
78
+ # @return [String]
79
+ def as(format)
80
+ case format
81
+ when :data
82
+ to_s
83
+ when :full
84
+ ok? ? as_full : to_s
85
+ when :prefixed
86
+ "#{prefix}:#{as_full}"
87
+ else
88
+ raise ArgumentError, "format must be one of [:data, :full, :prefixed], but it was #{format.inspect}"
89
+ end
90
+ end
91
+
92
+ # Return the prefix for the identifier
93
+ def prefix
94
+ self.class.prefix
95
+ end
96
+
97
+ private
98
+
99
+ def fetch(ivar)
100
+ return unless ok?
101
+ return instance_variable_get(ivar) if instance_variable_defined?(ivar)
102
+ instance_variable_set(ivar, yield(@id_string).freeze)
103
+ end
104
+ end
105
+ end
@@ -1,3 +1,5 @@
1
+ require 'music_ids/id'
2
+
1
3
  module MusicIds
2
4
  # The ISRC class represents an International Standard Recording Code, and
3
5
  # provides simple methods to parse and re-present them.
@@ -43,116 +45,54 @@ module MusicIds
43
45
  # instance that will return <tt>false</tt> from <tt>#ok?</tt> and will return
44
46
  # nil from all the component methods like <tt>#registrant</tt>
45
47
  class ISRC
46
- # See http://www.ifpi.org/content/library/isrc_handbook.pdf §3.5
47
- WELL_FORMED_INPUT = /\A[A-Z]{2}-?[A-Z0-9]{3}-?[0-9]{2}-?[0-9]{5}\Z/
48
-
49
- class << self
50
- # Parse an ISRC string into an ISRC instance
51
- #
52
- # @param input [String] The input ISRC string to parse
53
- # @param opts [Hash] Parsing options
54
- # @option opts [true, false] :relaxed (false) Whether to parse in relaxed mode
55
- # @return [ISRC] the ISRC instance
56
- def parse(input, opts = {})
57
- input = input.to_s.upcase
58
- opts[:relaxed] ? parse_relaxed(input) : parse_strict(input)
59
- end
60
-
61
- private
62
-
63
- def parse_strict(input)
64
- if WELL_FORMED_INPUT.match(input)
65
- new(input.gsub('-', ''))
66
- else
67
- raise ArgumentError, "'#{input}' is not the right length to be a 12- or 15-character ISRC"
68
- end
69
- end
70
-
71
- def parse_relaxed(input)
72
- if WELL_FORMED_INPUT.match(input)
73
- new(input.gsub('-', ''))
74
- else
75
- new(input, ok: false)
76
- end
77
- end
78
- end
48
+ include Id
79
49
 
80
- # @api private
81
- # @param isrc_string [String] The ISRC string
82
- # @param opts [Hash]
83
- # @option opts [true, false] :ok (true) Whether the ISRC is well-formed or not
84
- def initialize(isrc_string, opts = {ok: true})
85
- @isrc_string = isrc_string.dup.freeze
86
- @ok = opts[:ok] ? true : false
50
+ # See http://www.ifpi.org/content/library/isrc_handbook.pdf §3.5
51
+ def self.id_blocks
52
+ ['[A-Z]{2}', '[A-Z0-9]{3}', '[0-9]{2}', '[0-9]{5}']
87
53
  end
88
54
 
89
- # Is this a well-formed ISRC?
90
- # @return [true,false]
91
- def ok?
92
- @ok
55
+ # The prefix to use for generating a prefixed string representation of the ISRC
56
+ # (see http://www.ifpi.org/downloads/GRid_Handbook_V2_0_final.pdf §9.2 / §9.3
57
+ def self.prefix
58
+ @prefix ||= 'ISRC'.freeze
93
59
  end
94
60
 
95
61
  # Return the ISRC's two-letter country code
96
62
  # @return [String]
97
63
  def country
98
- return unless ok?
99
- @country ||= @isrc_string[0,2].freeze
64
+ fetch(:@country) { |isrc_string| isrc_string[0,2] }
100
65
  end
101
66
 
102
67
  # Return the ISRC's three-character registrant code
103
68
  # @return [String]
104
69
  def registrant
105
- return unless ok?
106
- @registrant ||= @isrc_string[2,3].freeze
70
+ fetch(:@registrant) { |isrc_string| isrc_string[2,3] }
107
71
  end
108
72
 
109
73
  # Return the ISRC's two-digit year.
110
74
  #
111
75
  # Note that year > 40 is a 19YY year, and 00 to 39 are 20YY years
112
- # see http://www.ifpi.org/content/library/isrc_handbook.pdf section 4.8
76
+ # see http://www.ifpi.org/content/library/isrc_handbook.pdf §4.8
113
77
  # @return [String]
114
78
  def year
115
- return unless ok?
116
- @year ||= @isrc_string[5,2].freeze
79
+ fetch(:@year) { |isrc_string| isrc_string[5,2] }
117
80
  end
118
81
 
119
82
  # Return the ISRC's five-character designation code.
120
- #
121
83
  # @return [String]
122
84
  def designation
123
- return unless ok?
124
- @designation ||= @isrc_string[7,5].freeze
125
- end
126
-
127
- # return the ISRC as a normalised 12-character string
128
- # @reuturn [String]
129
- def to_s
130
- @isrc_string.dup
85
+ fetch(:@designation) { |isrc_string| isrc_string[7,5] }
131
86
  end
132
87
 
133
88
  def to_isrc
134
89
  self
135
90
  end
136
91
 
137
- def ==(other)
138
- to_s == other.to_s
139
- end
140
-
141
- # Returns the ISRC as a string, either the 12-character normalised string
142
- # (:data) or the 15-character display string (:full). Note that a
143
- # badly-formed ISRC will simply return the original string whichever format
144
- # you ask for.
145
- # @param format [:data, :full] the output format to use
92
+ # Generate the hyphen-separated full display ISRC string
146
93
  # @return [String]
147
- def as(format)
148
- case format
149
- when :data
150
- to_s
151
- when :full
152
- ok? ? "#{country}-#{registrant}-#{year}-#{designation}" : to_s
153
- else
154
- raise ArgumentError, "format must be one of [:data, :full], but it was #{format.inspect}"
155
- end
94
+ def as_full
95
+ "#{country}-#{registrant}-#{year}-#{designation}"
156
96
  end
157
97
  end
158
98
  end
@@ -1,3 +1,3 @@
1
1
  module MusicIds
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: music_ids
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Patterson
@@ -89,6 +89,7 @@ files:
89
89
  - bin/setup
90
90
  - lib/music_ids.rb
91
91
  - lib/music_ids/grid.rb
92
+ - lib/music_ids/id.rb
92
93
  - lib/music_ids/isrc.rb
93
94
  - lib/music_ids/version.rb
94
95
  - music_ids.gemspec