opera-mobile-store-sdk 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,13 @@
1
+ require 'active_support/concern'
2
+ module Opera::MobileStore
3
+
4
+ module InspectableAttributes
5
+
6
+ extend ActiveSupport::Concern
7
+
8
+ def inspect
9
+ "<#{self.class.name} #{attributes.inspect}>"
10
+ end
11
+
12
+ end
13
+ end
@@ -1,105 +1,99 @@
1
- module Opera
2
- module MobileStore
3
- class PaymentInfo
1
+ require "active_model"
4
2
 
5
- include ActiveModel::Model
3
+ module Opera::MobileStore
4
+ class PaymentInfo
6
5
 
7
- def self.build_from_nokogiri_node(node)
8
- if node.present?
9
- type = node.xpath("string(@type)").strip.downcase
10
-
11
- case type
12
- when "check" then Check.build_from_nokogiri_node node
13
- when "wired" then Wired.build_from_nokogiri_node node
14
- when "paypal" then PayPal.build_from_nokogiri_node node
15
- when "none" then nil
16
- else raise "WTF?"
17
- end
18
- end
19
- end
6
+ include ActiveModel::Model
7
+ include ActiveModel::Serialization
20
8
 
21
- def type
22
- self.class.name.demodulize.downcase
23
- end
9
+ include Opera::MobileStore::InspectableAttributes
10
+
11
+ def type
12
+ self.class.name.demodulize.downcase
13
+ end
24
14
 
25
- def inspect
26
- attr_inspect = attributes.inject [] do |attributes, keyval|
27
- key, val = keyval
28
- attributes + ["#{key}: \"#{val}\""]
29
- end.join(", ")
15
+ def self.build_from_nokogiri_node(node)
16
+ if node.present?
17
+ type = node.xpath("string(@type)").strip.downcase
30
18
 
31
- "<#{self.class.name} #{attr_inspect}>"
19
+ case type
20
+ when "check" then Check.build_from_nokogiri_node node
21
+ when "wired" then Wired.build_from_nokogiri_node node
22
+ when "paypal" then PayPal.build_from_nokogiri_node node
23
+ when "none" then nil
24
+ else raise "WTF?"
25
+ end
32
26
  end
27
+ end
33
28
 
34
- class Check < PaymentInfo
35
- attr_accessor :name, :address
29
+ class Check < PaymentInfo
30
+ attr_accessor :name, :address
36
31
 
37
- def self.build_from_nokogiri_node(node)
38
- self.new(
39
- name: node.xpath("string(payment_check_name)"),
40
- address: node.xpath("string(payment_check_address)")
41
- )
42
- end
32
+ def self.build_from_nokogiri_node(node)
33
+ self.new(
34
+ name: node.xpath("string(payment_check_name)"),
35
+ address: node.xpath("string(payment_check_address)")
36
+ )
37
+ end
43
38
 
44
- def attributes
45
- [:name, :address].inject({}) do |hash, method|
46
- value = self.public_send method
47
- hash[method] = value unless value.nil?
48
- hash
49
- end
39
+ def attributes
40
+ [:name, :address].inject({}) do |hash, method|
41
+ value = self.public_send method
42
+ hash[method] = value unless value.nil?
43
+ hash
50
44
  end
51
45
  end
46
+ end
52
47
 
53
- class Wired < PaymentInfo
54
- attr_accessor :bank_account,
55
- :bank_name,
56
- :bank_address,
57
- :bank_swiftbic,
58
- :bank_iban,
59
- :bank_routing_number,
60
- :intermediary_bank_name,
61
- :intermediary_bank_address,
62
- :intermediary_bank_swiftbic,
63
- :intermediary_bank_iban
64
-
65
- def self.build_from_nokogiri_node(node)
66
- data = [
67
- :bank_account, :bank_name, :bank_address, :bank_swiftbic, :bank_iban,
68
- :bank_routing_number, :intermediary_bank_name, :intermediary_bank_address,
69
- :intermediary_bank_swiftbic, :intermediary_bank_iban
70
- ].inject({}) do |hash, attribute_name|
71
- value = node.xpath("string(payment_wired_#{attribute_name})").strip
72
- hash[attribute_name] = value if value.present?
73
- hash
74
- end
75
-
76
- self.new data
77
- end
48
+ class Wired < PaymentInfo
49
+ attr_accessor :bank_account,
50
+ :bank_name,
51
+ :bank_address,
52
+ :bank_swiftbic,
53
+ :bank_iban,
54
+ :bank_routing_number,
55
+ :intermediary_bank_name,
56
+ :intermediary_bank_address,
57
+ :intermediary_bank_swiftbic,
58
+ :intermediary_bank_iban
78
59
 
79
- def attributes
80
- [
81
- :bank_account, :bank_name, :bank_address, :bank_swiftbic, :bank_iban,
82
- :bank_routing_number, :intermediary_bank_name, :intermediary_bank_address,
83
- :intermediary_bank_swiftbic, :intermediary_bank_iban
84
- ].inject({}) do |hash, method|
85
- value = self.public_send method
86
- hash[method] = value unless value.nil?
87
- hash
88
- end
60
+ def self.build_from_nokogiri_node(node)
61
+ data = [
62
+ :bank_account, :bank_name, :bank_address, :bank_swiftbic, :bank_iban,
63
+ :bank_routing_number, :intermediary_bank_name, :intermediary_bank_address,
64
+ :intermediary_bank_swiftbic, :intermediary_bank_iban
65
+ ].inject({}) do |hash, attribute_name|
66
+ value = node.xpath("string(payment_wired_#{attribute_name})").strip
67
+ hash[attribute_name] = value if value.present?
68
+ hash
89
69
  end
70
+
71
+ self.new data
90
72
  end
91
73
 
92
- class PayPal < PaymentInfo
93
- attr_accessor :account
94
- def self.build_from_nokogiri_node(node)
95
- self.new(account: node.xpath("string(account)").strip)
74
+ def attributes
75
+ [
76
+ :bank_account, :bank_name, :bank_address, :bank_swiftbic, :bank_iban,
77
+ :bank_routing_number, :intermediary_bank_name, :intermediary_bank_address,
78
+ :intermediary_bank_swiftbic, :intermediary_bank_iban
79
+ ].inject({}) do |hash, method|
80
+ value = self.public_send method
81
+ hash[method] = value unless value.nil?
82
+ hash
96
83
  end
84
+ end
85
+ end
97
86
 
98
- def attributes
99
- { account: account }
100
- end
87
+ class PayPal < PaymentInfo
88
+ attr_accessor :account
89
+ def self.build_from_nokogiri_node(node)
90
+ self.new(account: node.xpath("string(account)").strip)
101
91
  end
102
92
 
93
+ def attributes
94
+ { account: account }
95
+ end
103
96
  end
97
+
104
98
  end
105
99
  end
@@ -1,212 +1,207 @@
1
1
  require "active_model"
2
2
 
3
- module Opera
4
- module MobileStore
5
- class Product
3
+ module Opera::MobileStore
4
+ class Product
6
5
 
7
- FIELDS = [
8
- :id, :code, :category_id, :cp_product_id, :app_type, :author_id,
9
- :support_url, :version, :requirements, :price, :adult_content, :rating,
10
- :currency, :product_type, :weight, :updated_at, :added_at, :keywords,
11
- :rating, :images, :eula, :subsites, :builds, :i18n,
12
- :released_at, # Release Date
13
- :download_count # Download count at Opera Mobile Store
14
- ].freeze
6
+ FIELDS = [
7
+ :id, :code, :category_id, :cp_product_id, :app_type, :author_id,
8
+ :support_url, :version, :requirements, :price, :adult_content, :rating,
9
+ :currency, :product_type, :weight, :updated_at, :added_at, :keywords,
10
+ :rating, :images, :eula, :subsites, :builds, :i18n,
11
+ :released_at, # Release Date
12
+ :download_count # Download count at Opera Mobile Store
13
+ ].freeze
15
14
 
16
- include ActiveModel::Model
17
- include ActiveModel::Serialization
15
+ include ActiveModel::Model
16
+ include ActiveModel::Serialization
18
17
 
19
- include Opera::MobileStoreSDK::APIAccessible
18
+ include Opera::MobileStore::InspectableAttributes
20
19
 
21
- # All attributes are Read-Only...
22
- attr_accessor *FIELDS
20
+ include Opera::MobileStoreSDK::APIAccessible
23
21
 
24
- def category
25
- Category.find category_id if category_id.present?
26
- end
27
-
28
- def category=(given_category)
29
- @category_id = given_category.id
30
- end
22
+ # All attributes are Read-Only...
23
+ attr_accessor *FIELDS
31
24
 
32
- def author
33
- Author.find author_id if author_id.present?
34
- end
25
+ def category
26
+ Category.find category_id if category_id.present?
27
+ end
35
28
 
36
- def author=(given_author)
37
- @author_id = given_author.id
38
- end
29
+ def category=(given_category)
30
+ @category_id = given_category.id
31
+ end
39
32
 
40
- def title(key = "en")
41
- required_data = i18n.detect do |x|
42
- x.language_code == key.to_s
43
- end.title
44
- required_data.present? ? required_data : title('en')
45
- end
33
+ def author
34
+ Developer.find author_id if author_id.present?
35
+ end
46
36
 
47
- def short_description(key = "en")
48
- required_data = i18n.detect do |x|
49
- x.language_code == key.to_s
50
- end.short_description
51
- required_data.present? ? required_data : short_description('en')
52
- end
37
+ def author=(given_author)
38
+ @author_id = given_author.id
39
+ end
53
40
 
54
- def long_description(key = "en")
55
- required_data = i18n.detect do |x|
56
- x.language_code == key.to_s
57
- end.long_description
58
- required_data.present? ? required_data : long_description('en')
59
- end
41
+ def title(key = "en")
42
+ required_data = i18n.detect do |x|
43
+ x.language_code == key.to_s
44
+ end.title
45
+ required_data.present? ? required_data : title('en')
46
+ end
60
47
 
61
- def available_language_codes
62
- i18n.map(&:language_code)
63
- end
48
+ def short_description(key = "en")
49
+ required_data = i18n.detect do |x|
50
+ x.language_code == key.to_s
51
+ end.short_description
52
+ required_data.present? ? required_data : short_description('en')
53
+ end
64
54
 
65
- def attributes
66
- FIELDS.inject({}) do |hsh, field_name|
67
- field_value = self.public_send field_name
68
- hsh[field_name.to_s] = field_value if field_value.present?
69
- hsh
70
- end
71
- end
55
+ def long_description(key = "en")
56
+ required_data = i18n.detect do |x|
57
+ x.language_code == key.to_s
58
+ end.long_description
59
+ required_data.present? ? required_data : long_description('en')
60
+ end
72
61
 
73
- # Override of serializable_hash:
74
- #
75
- # In the case of the category and author of a product, since we can't
76
- # query the OMS API for a single entity directly, we'll replace the entity
77
- # id field (category_id, author_id) with the serializable hash of the
78
- # actual object (category, author) as part of the serializable hash:
79
- def serializable_hash(options = nil)
80
- attributes.inject({}) do |shsh, keyval|
81
- field_name, field_value = keyval
82
-
83
- case field_name
84
- when 'category_id', 'author_id'
85
- field_name = field_name[0..-4]
86
- field_value = self.send(field_name).serializable_hash
87
- when 'i18n', 'images', 'builds' # Array of special objects
88
- field_value = field_value.map(&:serializable_hash)
89
- end
62
+ def available_language_codes
63
+ i18n.map(&:language_code)
64
+ end
90
65
 
91
- shsh[field_name] = field_value
92
- shsh
93
- end
66
+ def attributes
67
+ FIELDS.inject({}) do |hsh, field_name|
68
+ field_value = self.public_send field_name
69
+ hsh[field_name.to_s] = field_value if field_value.present?
70
+ hsh
94
71
  end
72
+ end
95
73
 
96
- def self.deserialize(serializable_hash)
97
- attributes_hash = serializable_hash.inject({}) do |hsh, keyval|
98
- field_name, field_value = keyval
99
-
100
- case field_name
101
- when 'category'
102
- field_value = Category.deserialize field_value
103
- when 'author'
104
- field_value = Author.deserialize field_value
105
- when 'i18n'
106
- field_value = field_value.map do |item_serializable_hash|
107
- ProductLocalization.deserialize item_serializable_hash
108
- end
109
- when 'images'
110
- field_value = field_value.map do |item_serializable_hash|
111
- ProductImage.deserialize item_serializable_hash
112
- end
113
- when 'builds' # Array of special objects
114
- field_value = field_value.map do |item_serializable_hash|
115
- Build.deserialize item_serializable_hash
116
- end
117
- end
118
-
119
- hsh[field_name] = field_value
120
- hsh
74
+ # Override of serializable_hash:
75
+ #
76
+ # In the case of the category and author of a product, since we can't
77
+ # query the OMS API for a single entity directly, we'll replace the entity
78
+ # id field (category_id, author_id) with the serializable hash of the
79
+ # actual object (category, author) as part of the serializable hash:
80
+ def serializable_hash(options = nil)
81
+ attributes.inject({}) do |shsh, keyval|
82
+ field_name, field_value = keyval
83
+
84
+ case field_name
85
+ when 'category_id', 'author_id'
86
+ field_name = field_name[0..-4]
87
+ field_value = self.send(field_name).serializable_hash
88
+ when 'i18n', 'images', 'builds' # Array of special objects
89
+ field_value = field_value.map(&:serializable_hash)
121
90
  end
122
91
 
123
- self.new attributes_hash
92
+ shsh[field_name] = field_value
93
+ shsh
124
94
  end
95
+ end
125
96
 
126
- # TODO: Move this implementation to the SDK namespace
127
- def self.build_from_nokogiri_node(node)
128
-
129
- category_id = node.xpath("number(category/@id)").to_i
130
- author_id = node.xpath("number(author/@id)").to_i
131
-
132
- # Initialize the category unless it's already in it's Identity Map:
133
- Category.new(
134
- id: category_id,
135
- code: node.xpath("string(category/@code)"),
136
- name: node.xpath("string(category)")
137
- ) unless Category.registered? category_id
138
-
139
- # Initialize the author unless it's already in it's Identity Map:
140
- unless Author.registered? author_id
141
- author_attributes = {
142
- id: author_id,
143
- name: node.xpath("string(author)"),
144
- email: node.xpath("string(author_email)")
145
- }
146
- author_attributes.delete(:email) unless author_attributes[:email].present?
147
-
148
- Author.new author_attributes
97
+ def self.deserialize(serializable_hash)
98
+ attributes_hash = serializable_hash.inject({}) do |hsh, keyval|
99
+ field_name, field_value = keyval
100
+
101
+ case field_name
102
+ when 'category'
103
+ field_value = Category.deserialize field_value
104
+ when 'author'
105
+ field_value = Author.deserialize field_value
106
+ when 'i18n'
107
+ field_value = field_value.map do |item_serializable_hash|
108
+ ProductLocalization.deserialize item_serializable_hash
109
+ end
110
+ when 'images'
111
+ field_value = field_value.map do |item_serializable_hash|
112
+ ProductImage.deserialize item_serializable_hash
113
+ end
114
+ when 'builds' # Array of special objects
115
+ field_value = field_value.map do |item_serializable_hash|
116
+ Build.deserialize item_serializable_hash
117
+ end
149
118
  end
150
119
 
151
- data = {
152
- id: node.xpath("number(@id)").to_i,
153
- code: node.xpath("string(@code)"),
154
- cp_product_id: node.xpath("number(cp_product_id)").to_i,
155
-
156
- category_id: category_id,
157
- author_id: author_id,
158
- app_type: node.xpath("string(apptype)"),
159
- released_at: DateTime.parse(node.xpath "string(release_date)"),
160
- download_count: node.xpath("number(downloads_count)").to_i,
161
- support_url: node.xpath("string(support_url)"),
162
- version: node.xpath("string(version)"),
163
- # TODO: process requirements node
164
-
165
- # Product localization in English:
166
- i18n: [
167
- ProductLocalization.new({
168
- language_code: "en",
169
- title: node.xpath("string(product_name)").strip,
170
- short_description: node.xpath("string(short_description)").strip,
171
- long_description: node.xpath("string(long_description)").strip
172
- }.select { |key, val| val.present? })
173
- ],
174
-
175
- price: node.xpath("number(price)"),
176
- currency: node.xpath("string(currency)"),
177
- product_type: node.xpath("string(type)"),
178
- weight: node.xpath("number(weight)").to_i,
179
- updated_at: DateTime.parse(node.xpath "string(update_date)"),
180
- added_at: DateTime.parse(node.xpath "string(add_date)"),
181
-
182
- keywords: node.xpath("keywords/keyword").map do |x|
183
- value = x.text.strip
184
- value.present? ? Opera::MobileStoreSDK.html_entities.decode(value) : nil
185
- end.compact,
186
-
187
- images: node.xpath("images/*").map do |i|
188
- ProductImage.build_from_nokogiri_node i
189
- end,
190
-
191
- builds: node.xpath("builds/build").map do |b|
192
- Build.build_from_nokogiri_node b
193
- end
120
+ hsh[field_name] = field_value
121
+ hsh
122
+ end
194
123
 
195
- }
124
+ self.new attributes_hash
125
+ end
196
126
 
197
- node.xpath("translates/language").each do |language_node|
198
- data[:i18n] << ProductLocalization.new({
199
- # We'll ignore the "@code" attribute... only Opera Devs knows WTF with it.
200
- language_code: language_node.xpath("string(@iso)").strip,
201
- title: node.xpath("string(title)").strip,
127
+ # TODO: Move this implementation to the SDK namespace
128
+ def self.build_from_nokogiri_node(node)
129
+
130
+ # Initialize the category unless it's already in it's Identity Map:
131
+ category_id = node.xpath("number(category/@id)").to_i
132
+ Category.new(
133
+ id: category_id,
134
+ code: node.xpath("string(category/@code)"),
135
+ name: node.xpath("string(category)")
136
+ ) unless Category.identity_mapped? category_id
137
+
138
+ # Initialize the category unless it's already in it's Identity Map:
139
+ author_id = node.xpath("number(author/@id)").to_i
140
+ Developer.new(
141
+ id: author_id,
142
+ name: node.xpath("string(author)"),
143
+ email: node.xpath("string(author_email)")
144
+ ) unless Developer.identity_mapped? author_id
145
+
146
+ data = {
147
+ id: node.xpath("number(@id)").to_i,
148
+ code: node.xpath("string(@code)"),
149
+ cp_product_id: node.xpath("number(cp_product_id)").to_i,
150
+
151
+ category_id: category_id,
152
+ author_id: author_id,
153
+
154
+ app_type: node.xpath("string(apptype)"),
155
+ released_at: DateTime.parse(node.xpath "string(release_date)"),
156
+ download_count: node.xpath("number(downloads_count)").to_i,
157
+ support_url: node.xpath("string(support_url)"),
158
+ version: node.xpath("string(version)"),
159
+ # TODO: process requirements node
160
+
161
+ # Product localization in English:
162
+ i18n: [
163
+ ProductLocalization.new({
164
+ language_code: "en",
165
+ title: node.xpath("string(product_name)").strip,
202
166
  short_description: node.xpath("string(short_description)").strip,
203
- long_description: node.xpath("string(description)").strip
167
+ long_description: node.xpath("string(long_description)").strip
204
168
  }.select { |key, val| val.present? })
169
+ ],
170
+
171
+ price: node.xpath("number(price)"),
172
+ currency: node.xpath("string(currency)"),
173
+ product_type: node.xpath("string(type)"),
174
+ weight: node.xpath("number(weight)").to_i,
175
+ updated_at: DateTime.parse(node.xpath "string(update_date)"),
176
+ added_at: DateTime.parse(node.xpath "string(add_date)"),
177
+
178
+ keywords: node.xpath("keywords/keyword").map do |x|
179
+ value = x.text.strip
180
+ value.present? ? Opera::MobileStoreSDK.html_entities.decode(value) : nil
181
+ end.compact,
182
+
183
+ images: node.xpath("images/*").map do |i|
184
+ ProductImage.build_from_nokogiri_node i
185
+ end,
186
+
187
+ builds: node.xpath("builds/build").map do |b|
188
+ Build.build_from_nokogiri_node b
205
189
  end
206
190
 
207
- self.new data
191
+ }
192
+
193
+ node.xpath("translates/language").each do |language_node|
194
+ data[:i18n] << ProductLocalization.new({
195
+ # We'll ignore the "@code" attribute... only Opera Devs knows WTF with it.
196
+ language_code: language_node.xpath("string(@iso)").strip,
197
+ title: node.xpath("string(title)").strip,
198
+ short_description: node.xpath("string(short_description)").strip,
199
+ long_description: node.xpath("string(description)").strip
200
+ }.select { |key, val| val.present? })
208
201
  end
209
202
 
203
+ self.new data
210
204
  end
205
+
211
206
  end
212
207
  end