metal_archives 0.8.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +59 -7
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +14 -0
  5. data/.travis.yml +11 -0
  6. data/Gemfile +2 -0
  7. data/{LICENSE → LICENSE.md} +0 -0
  8. data/README.md +77 -9
  9. data/Rakefile +5 -3
  10. data/lib/metal_archives.rb +8 -0
  11. data/lib/metal_archives/configuration.rb +28 -7
  12. data/lib/metal_archives/error.rb +37 -30
  13. data/lib/metal_archives/http_client.rb +21 -42
  14. data/lib/metal_archives/middleware/headers.rb +38 -0
  15. data/lib/metal_archives/middleware/rewrite_endpoint.rb +38 -0
  16. data/lib/metal_archives/models/artist.rb +51 -65
  17. data/lib/metal_archives/models/band.rb +41 -39
  18. data/lib/metal_archives/models/base_model.rb +88 -59
  19. data/lib/metal_archives/models/label.rb +7 -6
  20. data/lib/metal_archives/parsers/artist.rb +110 -99
  21. data/lib/metal_archives/parsers/band.rb +168 -156
  22. data/lib/metal_archives/parsers/label.rb +54 -52
  23. data/lib/metal_archives/parsers/parser.rb +73 -71
  24. data/lib/metal_archives/utils/collection.rb +7 -1
  25. data/lib/metal_archives/utils/lru_cache.rb +11 -4
  26. data/lib/metal_archives/utils/nil_date.rb +54 -0
  27. data/lib/metal_archives/utils/range.rb +16 -8
  28. data/lib/metal_archives/version.rb +3 -1
  29. data/metal_archives.gemspec +21 -11
  30. data/spec/configuration_spec.rb +101 -0
  31. data/spec/factories/artist_factory.rb +37 -0
  32. data/spec/factories/band_factory.rb +60 -0
  33. data/spec/factories/nil_date_factory.rb +9 -0
  34. data/spec/factories/range_factory.rb +8 -0
  35. data/spec/models/artist_spec.rb +142 -0
  36. data/spec/models/band_spec.rb +179 -0
  37. data/spec/models/base_model_spec.rb +217 -0
  38. data/spec/parser_spec.rb +19 -0
  39. data/spec/spec_helper.rb +111 -0
  40. data/spec/support/factory_girl.rb +5 -0
  41. data/spec/support/metal_archives.rb +26 -0
  42. data/spec/utils/collection_spec.rb +72 -0
  43. data/spec/utils/lru_cache_spec.rb +53 -0
  44. data/spec/utils/nil_date_spec.rb +98 -0
  45. data/spec/utils/range_spec.rb +62 -0
  46. metadata +142 -57
  47. data/test/base_model_test.rb +0 -111
  48. data/test/configuration_test.rb +0 -57
  49. data/test/parser_test.rb +0 -37
  50. data/test/property/artist_property_test.rb +0 -43
  51. data/test/property/band_property_test.rb +0 -94
  52. data/test/query/artist_query_test.rb +0 -109
  53. data/test/query/band_query_test.rb +0 -152
  54. data/test/test_helper.rb +0 -25
  55. data/test/utils/collection_test.rb +0 -51
  56. data/test/utils/lru_cache_test.rb +0 -22
  57. data/test/utils/range_test.rb +0 -42
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryGirl.define do
4
+ factory :artist, :class => MetalArchives::Artist do
5
+ id { Faker::Number.number [1, 2, 3, 4].sample }
6
+ name { Faker::Name.name }
7
+ gender { %i[male female].sample }
8
+ biography { Faker::Lorem.words(200).join ' ' }
9
+ trivia { Faker::Lorem.words(200).join ' ' }
10
+
11
+ country { ISO3166::Country[Faker::Address.country_code] }
12
+ location { Faker::Address.city }
13
+
14
+ date_of_birth { Faker::Date.birthday 18, 65 }
15
+
16
+ links do
17
+ 3.times.collect do
18
+ {
19
+ :url => Faker::Internet.url,
20
+ :type => %i[official unofficial unlisted_bands].sample,
21
+ :title => Faker::Lorem.words(4).join(' ')
22
+ }
23
+ end
24
+ end
25
+
26
+ trait :has_died do
27
+ date_of_death { Faker::Date.between date_of_birth, Date.today }
28
+ cause_of_death { %w(Suicide N/A Accident Cancer Illness Murder).sample }
29
+ end
30
+
31
+ trait :with_aliases do
32
+ aliases do
33
+ 3.times.collect { Faker::Name.name }
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryGirl.define do
4
+ factory :band, :class => MetalArchives::Band do
5
+ id { Faker::Number.number [1, 2, 3, 4].sample }
6
+ name { Faker::Name.name }
7
+ status { %i[active split_up on_hold unknown changed_name disputed].sample }
8
+
9
+ comment { Faker::Lorem.words(200).join ' ' }
10
+
11
+ country { ISO3166::Country[Faker::Address.country_code] }
12
+ location { Faker::Address.city }
13
+
14
+ date_formed { Faker::Date.birthday 0, 50 }
15
+ date_active { build_list :range }
16
+
17
+ label { [build(:label), nil].sample }
18
+ independent { label.nil? }
19
+
20
+ logo { Faker::Internet.url }
21
+ photo { Faker::Internet.url }
22
+
23
+ genres do
24
+ 3.times.collect do
25
+ "#{%w(Black Death Doom Power Progressive Speed Thrash).sample} Metal"
26
+ end
27
+ end
28
+
29
+ lyrical_themes do
30
+ 3.times.collect do
31
+ ['Fantasy', 'Epic battles', 'Tales', 'Myths', 'Legends', 'Feelings', 'Life', 'Eden', 'Glory', 'the Four Elements', 'Metal'].sample
32
+ end
33
+ end
34
+
35
+ similar do
36
+ 4.times.collect do
37
+ {
38
+ :band => build(:band),
39
+ :score => Faker::Number.between(1, 100)
40
+ }
41
+ end
42
+ end
43
+
44
+ links do
45
+ 3.times.collect do
46
+ {
47
+ :url => Faker::Internet.url,
48
+ :type => %i[official unofficial unlisted_bands].sample,
49
+ :title => Faker::Lorem.words(4).join(' ')
50
+ }
51
+ end
52
+ end
53
+
54
+ trait :with_aliases do
55
+ aliases do
56
+ 3.times.collect { Faker::Name.name }
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryGirl.define do
4
+ factory :nil_date, :class => MetalArchives::NilDate do
5
+ year { Faker::Date.backward(99).year }
6
+ month { Faker::Date.backward(99).month }
7
+ day { Faker::Date.backward(99).day }
8
+ end
9
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryGirl.define do
4
+ factory :range, :class => MetalArchives::Range do
5
+ send(:begin) { Faker::Date.birthday 0, 50 }
6
+ send(:end) { Faker::Date.birthday }
7
+ end
8
+ end
@@ -0,0 +1,142 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe MetalArchives::Artist do
4
+ describe 'properties' do
5
+ it 'Alberto Rionda has properties' do
6
+ artist = MetalArchives::Artist.find 60908
7
+
8
+ expect(artist).to be_instance_of MetalArchives::Artist
9
+ expect(artist.id).to eq 60908
10
+ expect(artist.name).to eq 'Alberto Rionda'
11
+ expect(artist.aliases).to be_empty
12
+ expect(artist.country).to eq ISO3166::Country['ES']
13
+ expect(artist.location).to eq 'Oviedo, Asturias'
14
+ expect(artist.date_of_birth).to eq Date.new(1972, 9, 2)
15
+ expect(artist.gender).to eq :male
16
+ expect(artist.biography).to match 'Avalanch'
17
+ expect(artist.trivia).to match 'Sanctuarium Estudios'
18
+ expect(artist.photo).to be_instance_of URI::HTTPS
19
+ expect(artist.photo.path).to eq '/images/6/0/9/0/60908_artist.jpg'
20
+ end
21
+
22
+ it 'Lemmy Kilmister has properties' do
23
+ artist = MetalArchives::Artist.find 260
24
+
25
+ expect(artist).to be_instance_of MetalArchives::Artist
26
+ expect(artist.name).to eq 'Ian Fraser Kilmister'
27
+ expect(artist.aliases).to include 'Lemmy Kilmister'
28
+ expect(artist.date_of_death).to eq Date.new(2015, 12, 28)
29
+ expect(artist.links.length).to eq 5
30
+ expect(artist.links.count { |l| l[:type] == :official }).to eq 1
31
+ expect(artist.links.count { |l| l[:type] == :unofficial }).to eq 2
32
+ expect(artist.links.count { |l| l[:type] == :unlisted_bands }).to eq 2
33
+ expect(artist.links.select { |l| l[:type] == :official }.first[:url]).to eq 'https://www.facebook.com/OfficialLemmy'
34
+ expect(artist.links.select { |l| l[:type] == :official }.first[:title]).to eq 'Facebook'
35
+ end
36
+
37
+ it 'maps query parameters' do
38
+ expect(MetalArchives::Parsers::Artist.map_params(:name => 'name')[:query]).to eq 'name'
39
+ end
40
+
41
+ it 'rewrites URIs' do
42
+ old_endpoint = MetalArchives.config.endpoint
43
+ MetalArchives.config.endpoint = 'https://foo.bar/'
44
+
45
+ artist = MetalArchives::Artist.find! 60908
46
+
47
+ expect(artist.photo.scheme).to eq 'https'
48
+ expect(artist.photo.host).to eq 'foo.bar'
49
+
50
+ MetalArchives.config.endpoint = old_endpoint
51
+ end
52
+ end
53
+
54
+ describe 'methods' do
55
+ describe 'find' do
56
+ it 'finds an artist' do
57
+ artist = MetalArchives::Artist.find 60908
58
+
59
+ expect(artist).to be_instance_of MetalArchives::Artist
60
+ expect(artist.name).to eq 'Alberto Rionda'
61
+ end
62
+
63
+ it 'lazily loads' do
64
+ artist = MetalArchives::Artist.find -1
65
+
66
+ expect(artist).to be_instance_of MetalArchives::Artist
67
+ end
68
+ end
69
+
70
+ describe 'find!' do
71
+ it 'finds an artist' do
72
+ artist = MetalArchives::Artist.find! 60908
73
+
74
+ expect(artist).to be_instance_of MetalArchives::Artist
75
+ expect(artist.name).to eq 'Alberto Rionda'
76
+ end
77
+
78
+ it 'raises on invalid id' do
79
+ expect(-> { MetalArchives::Artist.find! -1 }).to raise_error MetalArchives::Errors::APIError
80
+ expect(-> { MetalArchives::Artist.find! 0 }).to raise_error MetalArchives::Errors::InvalidIDError
81
+ expect(-> { MetalArchives::Artist.find! nil }).to raise_error MetalArchives::Errors::InvalidIDError
82
+ end
83
+ end
84
+
85
+ describe 'find_by' do
86
+ it 'finds an artist' do
87
+ artist = MetalArchives::Artist.find_by :name => 'Alberto Rionda'
88
+
89
+ expect(artist).to be_instance_of MetalArchives::Artist
90
+ expect(artist.id).to eq 60908
91
+ end
92
+
93
+ it 'returns nil on invalid id' do
94
+ artist = MetalArchives::Artist.find_by :name => 'SomeNonExistantName'
95
+
96
+ expect(artist).to be_nil
97
+ end
98
+ end
99
+
100
+ describe 'find_by!' do
101
+ it 'finds an artist' do
102
+ artist = MetalArchives::Artist.find_by! :name => 'Alberto Rionda'
103
+
104
+ expect(artist).to be_instance_of MetalArchives::Artist
105
+ expect(artist.id).to eq 60908
106
+ end
107
+
108
+ it 'returns nil on invalid id' do
109
+ artist = MetalArchives::Artist.find_by! :name => 'SomeNonExistantName'
110
+
111
+ expect(artist).to be_nil
112
+ end
113
+ end
114
+
115
+ describe 'search' do
116
+ it 'returns a collection' do
117
+ collection = MetalArchives::Artist.search 'Alberto Rionda'
118
+
119
+ expect(collection).to be_instance_of MetalArchives::Collection
120
+ expect(collection.first).to be_instance_of MetalArchives::Artist
121
+ end
122
+
123
+ it 'returns a collection' do
124
+ expect(MetalArchives::Artist.search('Alberto Rionda').count).to eq 1
125
+ expect(MetalArchives::Artist.search('Name').count).to eq 10
126
+ expect(MetalArchives::Artist.search('SomeNonExistantName').count).to eq 0
127
+ expect(MetalArchives::Artist.search 'SomeNonExistantName').to be_empty
128
+ expect(MetalArchives::Artist.search('Filip').count).to be > 200
129
+ end
130
+
131
+ it 'returns an empty collection' do
132
+ expect(MetalArchives::Artist.search 'SomeNoneExistantName').to be_empty
133
+ end
134
+ end
135
+
136
+ describe 'all' do
137
+ it 'returns a collection' do
138
+ expect(MetalArchives::Artist.all).to be_instance_of MetalArchives::Collection
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,179 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe MetalArchives::Band do
4
+ describe 'properties' do
5
+ it 'Pathfinder has properties' do
6
+ band = MetalArchives::Band.find 122302
7
+
8
+ expect(band).to be_instance_of MetalArchives::Band
9
+ expect(band.name).to eq 'Pathfinder'
10
+ expect(band.aliases).to be_empty
11
+ expect(band.country).to eq ISO3166::Country['PL']
12
+ expect(band.location).to eq 'Poznań'
13
+ expect(band.date_formed).to eq Date.new(2006)
14
+ expect(band.date_active).to eq [MetalArchives::Range.new(Date.new(2006), nil)]
15
+ expect(band.status).to eq :active
16
+ expect(band.genres).to eq ['Symphonic Power']
17
+ expect(band.lyrical_themes.sort).to eq ['Fantasy', 'Battles', 'Glory', 'The Four Elements', 'Metal'].sort
18
+ expect(band.comment).to match 'Pathfinder was founded by'
19
+ expect(band.logo).to be_instance_of URI::HTTPS
20
+ expect(band.logo.path).to eq '/images/1/2/2/3/122302_logo.jpg'
21
+ expect(band.photo).to be_instance_of URI::HTTPS
22
+ expect(band.photo.path).to eq '/images/1/2/2/3/122302_photo.jpg'
23
+ expect(band.independent).not_to be true
24
+ expect(band.similar.length).to eq 19
25
+ expect(band.links.length).to eq 15
26
+ expect(band.links.count { |l| l[:type] == :official }).to eq 12
27
+ expect(band.links.count { |l| l[:type] == :merchandise }).to eq 3
28
+ expect(band.links.select { |l| l[:type] == :merchandise }.first[:url]).to eq 'http://www.amazon.com/Fifth-Element-Pathfinder/dp/B007MNNCVW'
29
+ expect(band.links.select { |l| l[:type] == :merchandise }.first[:title]).to eq 'Amazon'
30
+ end
31
+
32
+ it 'Lemmy Kilmister has properties' do
33
+ band = MetalArchives::Band.find 32
34
+
35
+ expect(band).to be_instance_of MetalArchives::Band
36
+ expect(band.name).to eq 'Rhapsody of Fire'
37
+ expect(band.aliases).to match %w(Thundercross Rhapsody)
38
+ end
39
+
40
+ it 'maps status' do
41
+ expect(MetalArchives::Parsers::Band.send(:map_status, nil)).to eq ''
42
+ expect(MetalArchives::Parsers::Band.send(:map_status, :active)).to eq 'Active'
43
+ expect(MetalArchives::Parsers::Band.send(:map_status, :split_up)).to eq 'Split-up'
44
+ expect(MetalArchives::Parsers::Band.send(:map_status, :on_hold)).to eq 'On hold'
45
+ expect(MetalArchives::Parsers::Band.send(:map_status, :unknown)).to eq 'Unknown'
46
+ expect(MetalArchives::Parsers::Band.send(:map_status, :changed_name)).to eq 'Changed name'
47
+ expect(MetalArchives::Parsers::Band.send(:map_status, :disputed)).to eq 'Disputed'
48
+
49
+ expect(-> { MetalArchives::Parsers::Band.send(:map_status, :invalid_status) }).to raise_error MetalArchives::Errors::ParserError
50
+ end
51
+
52
+ it 'rewrites URIs' do
53
+ old_endpoint = MetalArchives.config.endpoint
54
+ MetalArchives.config.endpoint = 'https://foo.bar/'
55
+
56
+ band = MetalArchives::Band.find! 122302
57
+
58
+ expect(band.logo.scheme).to eq 'https'
59
+ expect(band.logo.host).to eq 'foo.bar'
60
+
61
+ expect(band.logo.scheme).to eq 'https'
62
+ expect(band.photo.host).to eq 'foo.bar'
63
+
64
+ MetalArchives.config.endpoint = old_endpoint
65
+ end
66
+ end
67
+
68
+ describe 'methods' do
69
+ describe 'find' do
70
+ it 'finds a band' do
71
+ band = MetalArchives::Band.find 3540361100
72
+
73
+ expect(band).not_to be_nil
74
+ expect(band).to be_instance_of MetalArchives::Band
75
+ expect(band.id).to eq 3540361100
76
+ expect(band.name).to eq 'Alquimia'
77
+ expect(band.country).to eq ISO3166::Country['ES']
78
+
79
+ expect(band.logo).to be_instance_of URI::HTTPS
80
+ expect(band.logo.path).to eq '/images/3/5/4/0/3540361100_logo.gif'
81
+
82
+ expect(band.photo).to be_instance_of URI::HTTPS
83
+ expect(band.photo.path).to eq '/images/3/5/4/0/3540361100_photo.jpg'
84
+ end
85
+
86
+ it 'lazily loads' do
87
+ band = MetalArchives::Band.find -1
88
+
89
+ expect(band).to be_instance_of MetalArchives::Band
90
+ end
91
+ end
92
+
93
+ describe 'find!' do
94
+ it 'finds a band' do
95
+ band = MetalArchives::Band.find! 3540361100
96
+
97
+ expect(band).to be_instance_of MetalArchives::Band
98
+ expect(band.name).to eq 'Alquimia'
99
+ end
100
+
101
+ it 'raises on invalid id' do
102
+ expect(-> { MetalArchives::Band.find! -1 }).to raise_error MetalArchives::Errors::APIError
103
+ expect(-> { MetalArchives::Band.find! 0 }).to raise_error MetalArchives::Errors::InvalidIDError
104
+ expect(-> { MetalArchives::Band.find! nil }).to raise_error MetalArchives::Errors::InvalidIDError
105
+ end
106
+ end
107
+
108
+ describe 'find_by' do
109
+ it 'finds a band' do
110
+ band = MetalArchives::Band.find_by :name => 'Falconer'
111
+
112
+ expect(band).to be_instance_of MetalArchives::Band
113
+ expect(band.id).to eq 74
114
+ end
115
+
116
+ it 'returns nil on invalid id' do
117
+ band = MetalArchives::Band.find_by :name => 'SomeNonExistantName'
118
+
119
+ expect(band).to be_nil
120
+ end
121
+ end
122
+
123
+ describe 'find_by!' do
124
+ it 'finds a band' do
125
+ band = MetalArchives::Band.find_by! :name => 'Falconer'
126
+
127
+ expect(band).to be_instance_of MetalArchives::Band
128
+ expect(band.id).to eq 74
129
+ end
130
+
131
+ it 'returns nil on invalid id' do
132
+ band = MetalArchives::Band.find_by! :name => 'SomeNonExistantName'
133
+
134
+ expect(band).to be_nil
135
+ end
136
+ end
137
+
138
+ describe 'search' do
139
+ it 'returns a collection' do
140
+ collection = MetalArchives::Band.search 'Alquimia'
141
+
142
+ expect(collection).to be_instance_of MetalArchives::Collection
143
+ expect(collection.first).to be_instance_of MetalArchives::Band
144
+ end
145
+
146
+ it 'returns an empty collection' do
147
+ expect(MetalArchives::Band.search 'SomeNoneExistantName').to be_empty
148
+ end
149
+
150
+ it 'searches by name' do
151
+ expect(MetalArchives::Band.search_by(:name => 'Alquimia').count).to eq 5
152
+ expect(MetalArchives::Band.search_by(:name => 'Lost Horizon').count).to eq 3
153
+ expect(MetalArchives::Band.search_by(:name => 'Lost Horizon', :exact => true).count).to eq 2
154
+ expect(MetalArchives::Band.search_by(:name => 'Alquimia', :genre => 'Melodic Power').count).to eq 2
155
+ end
156
+
157
+ it 'searches by year' do
158
+ expect(MetalArchives::Band.search_by(:name => 'Alquimia', :year => MetalArchives::Range.new(nil, nil)).count).to eq 5
159
+ expect(MetalArchives::Band.search_by(:name => 'Alquimia', :year => MetalArchives::Range.new(Date.new(2013), nil)).count).to eq 1
160
+ expect(MetalArchives::Band.search_by(:name => 'Alquimia', :year => MetalArchives::Range.new(Date.new(2008), Date.new(2008))).count).to eq 1
161
+ expect(MetalArchives::Band.search_by(:name => 'Alquimia', :year => MetalArchives::Range.new(Date.new(2008), Date.new(2013))).count).to eq 2
162
+ expect(MetalArchives::Band.search_by(:name => 'Alquimia', :year => MetalArchives::Range.new(nil, Date.new(2013))).count).to eq 5
163
+ end
164
+
165
+ it 'searches by country' do
166
+ expect(MetalArchives::Band.search_by(:name => 'Alquimia', :country => ISO3166::Country['ES']).count).to eq 1
167
+ expect(MetalArchives::Band.search_by(:name => 'Alquimia', :country => ISO3166::Country['AR']).count).to eq 3
168
+ expect(MetalArchives::Band.search_by(:name => 'Alquimia', :country => ISO3166::Country['AR']).count).to eq 3
169
+ expect(MetalArchives::Band.search_by(:name => 'Alquimia', :label => 'Mutus Liber').count).to eq 1
170
+ end
171
+ end
172
+
173
+ describe 'all' do
174
+ it 'returns a collection' do
175
+ expect(MetalArchives::Band.all).to be_instance_of MetalArchives::Collection
176
+ end
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,217 @@
1
+ # frozen_string_literal: true
2
+
3
+
4
+ ##
5
+ # Sample model without :id property or :assemble method
6
+ #
7
+ class ModelOne < MetalArchives::BaseModel
8
+ property :property_one
9
+ end
10
+
11
+ ##
12
+ # Sample model without :assemble method
13
+ #
14
+ class ModelTwo < MetalArchives::BaseModel
15
+ property :id
16
+ property :property_one
17
+ end
18
+
19
+ ##
20
+ # Sample complete model
21
+ #
22
+ class ModelThree < MetalArchives::BaseModel
23
+ property :id
24
+ property :property_one
25
+
26
+ def assemble
27
+ { :property_one => 'Property One' }
28
+ end
29
+ end
30
+
31
+ ##
32
+ # Sample complete model
33
+ #
34
+ class ModelFour < MetalArchives::BaseModel
35
+ property :id
36
+ property :property_one
37
+
38
+ def assemble
39
+ { :property_one => 'Property One' }
40
+ end
41
+ end
42
+
43
+ ##
44
+ # Sample invalid model
45
+ #
46
+ class ModelFive < MetalArchives::BaseModel
47
+ property :id
48
+ property :property_one
49
+
50
+ def assemble
51
+ raise MetalArchives::Errors::APIError
52
+ end
53
+ end
54
+
55
+ RSpec.describe MetalArchives::BaseModel do
56
+ it 'requires an :id property' do
57
+ expect(-> { ModelOne.new(:property_one => 'foo') }).to raise_error MetalArchives::Errors::NotImplementedError
58
+ end
59
+
60
+ it 'requires an :assemble method' do
61
+ expect(-> { ModelTwo.new(:id => 'foo').property_one }).to raise_error MetalArchives::Errors::NotImplementedError
62
+ end
63
+
64
+ it 'defines methods' do
65
+ model = ModelTwo.new :id => 'foo'
66
+
67
+ expect(model).to respond_to :id
68
+ expect(model).to respond_to :id=
69
+ expect(model).to respond_to :id?
70
+ expect(model).to respond_to :property_one
71
+ expect(model).to respond_to :property_one=
72
+ expect(model).to respond_to :property_one?
73
+ expect(model).not_to respond_to :property_two
74
+ expect(model).not_to respond_to :property_two=
75
+ expect(model).not_to respond_to :property_two?
76
+ end
77
+
78
+ it 'returns properties' do
79
+ model = ModelThree.new :id => 'foo', :property_one => 'bar'
80
+
81
+ expect(model.id).to eq 'foo'
82
+ expect(model.property_one).to eq 'bar'
83
+ end
84
+
85
+ it 'sets properties' do
86
+ model = ModelThree.new :id => 'foo', :property_one => 'bar'
87
+
88
+ model.id = 'baz'
89
+ model.property_one = 'bat'
90
+
91
+ expect(model.id).to eq 'baz'
92
+ expect(model.property_one).to eq 'bat'
93
+ end
94
+
95
+ it 'checks properties' do
96
+ model = ModelThree.new :id => 'foo', :property_one => 'bar'
97
+ model2 = ModelThree.new :id => 'foo'
98
+ model2.load!
99
+ model2.property_one = nil
100
+
101
+ expect(model.id?).to be true
102
+ expect(model.property_one?).to be true
103
+
104
+ expect(model2.id?).to be true
105
+ expect(model2.property_one?).to be false
106
+ end
107
+
108
+ it 'calls assemble' do
109
+ model = ModelThree.new :id => 'foo'
110
+
111
+ expect(model.id).to eq 'foo'
112
+ expect(model.property_one).to eq 'Property One'
113
+ end
114
+
115
+ it 'lazily loads' do
116
+ model = ModelThree.new :id => 'foo'
117
+
118
+ expect(model).to be_instance_variable_defined '@id'
119
+ expect(model).not_to be_instance_variable_defined '@property_one'
120
+
121
+ model.property_one
122
+
123
+ expect(model).to be_instance_variable_defined '@id'
124
+ expect(model).to be_instance_variable_defined '@property_one'
125
+ expect(model.property_one).to eq 'Property One'
126
+ end
127
+
128
+
129
+ it 'implements the load! operation' do
130
+ model = ModelThree.new :id => 'foo'
131
+
132
+ expect(model).to be_instance_variable_defined '@id'
133
+ expect(model).not_to be_instance_variable_defined '@property_one'
134
+
135
+ model.load!
136
+
137
+ expect(model).to be_instance_variable_defined '@id'
138
+ expect(model).to be_instance_variable_defined '@property_one'
139
+ expect(model.property_one).to eq 'Property One'
140
+ end
141
+
142
+ it 'implements the equal operator' do
143
+ m1 = ModelThree.new :id => 'id_one'
144
+ m2 = ModelThree.new :id => 'id_one'
145
+ m3 = ModelThree.new :id => 'id_two'
146
+ m4 = ModelFour.new :id => 'id_one'
147
+
148
+ expect(m1).to eq m2
149
+ expect(m2).not_to eq m3
150
+ expect(m1).not_to eq m3
151
+ expect(m1).not_to eq m4
152
+ expect(m2).not_to eq m4
153
+ end
154
+
155
+ describe 'loaded?' do
156
+ it 'has a :loaded? method' do
157
+ expect(ModelThree.new).to respond_to :loaded?
158
+ end
159
+
160
+ it 'returns false on lazy load' do
161
+ m = ModelThree.new :id => 'id_one'
162
+
163
+ expect(m).not_to be_loaded
164
+ end
165
+
166
+ it 'returns true on load!' do
167
+ m = ModelThree.new :id => 'id_one'
168
+ m.load!
169
+
170
+ expect(m).to be_loaded
171
+ end
172
+ end
173
+
174
+ describe 'cached?' do
175
+ context 'valid model' do
176
+ it 'has a :cached? method' do
177
+ expect(ModelThree.new).to respond_to :cached?
178
+ end
179
+
180
+ it "doesn't cache lazily loaded objects" do
181
+ m = ModelThree.new :id => 'id_one'
182
+
183
+ expect(m).not_to be_loaded
184
+ expect(m).not_to be_cached
185
+ end
186
+
187
+ it 'caches loaded objects' do
188
+ m = ModelThree.new :id => 'id_one'
189
+ m.load!
190
+
191
+ expect(m).to be_loaded
192
+ expect(m).to be_cached
193
+ end
194
+ end
195
+
196
+ context 'invalid model' do
197
+ it 'has a :cached? method' do
198
+ expect(ModelFive.new).to respond_to :cached?
199
+ end
200
+
201
+ it "doesn't cache lazily loaded objects" do
202
+ m = ModelFive.new :id => 'id_one'
203
+
204
+ expect(m).not_to be_loaded
205
+ expect(m).not_to be_cached
206
+ end
207
+
208
+ it "doesn't cache loaded invalid objects" do
209
+ m = ModelFive.new :id => 'id_one'
210
+ expect(-> { m.load! }).to raise_error MetalArchives::Errors::APIError
211
+
212
+ expect(m).not_to be_loaded
213
+ expect(m).not_to be_cached
214
+ end
215
+ end
216
+ end
217
+ end