braintree 2.2.0 → 2.3.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/lib/braintree.rb +1 -4
- data/lib/braintree/credit_card.rb +7 -6
- data/lib/braintree/credit_card_verification.rb +3 -2
- data/lib/braintree/customer.rb +13 -6
- data/lib/braintree/error_codes.rb +18 -7
- data/lib/braintree/error_result.rb +7 -1
- data/lib/braintree/ssl_expiration_check.rb +0 -5
- data/lib/braintree/subscription.rb +1 -0
- data/lib/braintree/transaction.rb +6 -1
- data/lib/braintree/transparent_redirect.rb +31 -0
- data/lib/braintree/version.rb +2 -2
- data/lib/braintree/xml/parser.rb +10 -2
- data/lib/braintree/xml/rexml.rb +71 -0
- data/spec/integration/braintree/credit_card_spec.rb +48 -6
- data/spec/integration/braintree/customer_spec.rb +128 -4
- data/spec/{unit → integration}/braintree/ssl_expiration_check_spec.rb +6 -14
- data/spec/integration/braintree/subscription_spec.rb +24 -11
- data/spec/integration/braintree/transaction_spec.rb +20 -4
- data/spec/integration/braintree/transparent_redirect_spec.rb +217 -2
- data/spec/spec_helper.rb +50 -2
- data/spec/unit/braintree/credit_card_spec.rb +2 -21
- data/spec/unit/braintree/credit_card_verification_spec.rb +3 -2
- data/spec/unit/braintree/customer_spec.rb +80 -0
- data/spec/unit/braintree/error_result_spec.rb +40 -0
- data/spec/unit/braintree/xml/parser_spec.rb +51 -0
- data/spec/unit/braintree/xml/rexml_spec.rb +51 -0
- metadata +28 -19
data/lib/braintree.rb
CHANGED
@@ -12,10 +12,6 @@ require "time"
|
|
12
12
|
require "zlib"
|
13
13
|
|
14
14
|
require "builder"
|
15
|
-
require "libxml"
|
16
|
-
unless ::LibXML::XML.respond_to?(:default_keep_blanks=)
|
17
|
-
raise LoadError, "The version of libxml that you're using is not compatible with the Braintree gem."
|
18
|
-
end
|
19
15
|
|
20
16
|
module Braintree
|
21
17
|
end
|
@@ -55,6 +51,7 @@ require "braintree/version.rb"
|
|
55
51
|
require "braintree/xml.rb"
|
56
52
|
require "braintree/xml/generator.rb"
|
57
53
|
require "braintree/xml/libxml.rb"
|
54
|
+
require "braintree/xml/rexml.rb"
|
58
55
|
require "braintree/xml/parser.rb"
|
59
56
|
|
60
57
|
Braintree::SSLExpirationCheck.check_dates
|
@@ -46,10 +46,12 @@ module Braintree
|
|
46
46
|
|
47
47
|
# The transparent redirect URL to use to create a credit card.
|
48
48
|
def self.create_credit_card_url
|
49
|
+
warn "[DEPRECATED] CreditCard.create_credit_card_url is deprecated. Please use TransparentRedirect.url"
|
49
50
|
"#{Braintree::Configuration.base_merchant_url}/payment_methods/all/create_via_transparent_redirect_request"
|
50
51
|
end
|
51
52
|
|
52
53
|
def self.create_from_transparent_redirect(query_string)
|
54
|
+
warn "[DEPRECATED] CreditCard.create_from_transparent_redirect is deprecated. Please use TransparentRedirect.confirm"
|
53
55
|
params = TransparentRedirect.parse_and_validate_query_string query_string
|
54
56
|
_do_create("/payment_methods/all/confirm_transparent_redirect_request", :id => params[:id])
|
55
57
|
end
|
@@ -107,12 +109,14 @@ module Braintree
|
|
107
109
|
end
|
108
110
|
|
109
111
|
def self.update_from_transparent_redirect(query_string)
|
112
|
+
warn "[DEPRECATED] CreditCard.update_via_transparent_redirect_request is deprecated. Please use TransparentRedirect.confirm"
|
110
113
|
params = TransparentRedirect.parse_and_validate_query_string query_string
|
111
114
|
_do_update(:post, "/payment_methods/all/confirm_transparent_redirect_request", :id => params[:id])
|
112
115
|
end
|
113
116
|
|
114
117
|
# The transparent redirect URL to use to update a credit card.
|
115
118
|
def self.update_credit_card_url
|
119
|
+
warn "[DEPRECATED] CreditCard.update_credit_card_url is deprecated. Please use TransparentRedirect.url"
|
116
120
|
"#{Braintree::Configuration.base_merchant_url}/payment_methods/all/update_via_transparent_redirect_request"
|
117
121
|
end
|
118
122
|
|
@@ -163,10 +167,7 @@ module Braintree
|
|
163
167
|
|
164
168
|
# Returns true if the credit card is expired.
|
165
169
|
def expired?
|
166
|
-
|
167
|
-
return expiration_month.to_i < Time.now.month
|
168
|
-
end
|
169
|
-
expiration_year.to_i < Time.now.year
|
170
|
+
@expired
|
170
171
|
end
|
171
172
|
|
172
173
|
def inspect # :nodoc:
|
@@ -233,7 +234,7 @@ module Braintree
|
|
233
234
|
self.new *args
|
234
235
|
end
|
235
236
|
|
236
|
-
def self._do_create(url, params) # :nodoc:
|
237
|
+
def self._do_create(url, params=nil) # :nodoc:
|
237
238
|
response = Http.post url, params
|
238
239
|
if response[:credit_card]
|
239
240
|
SuccessfulResult.new(:credit_card => new(response[:credit_card]))
|
@@ -263,7 +264,7 @@ module Braintree
|
|
263
264
|
billing_address_params = [:company, :country_name, :extended_address, :first_name, :last_name, :locality, :postal_code, :region, :street_address]
|
264
265
|
signature = [
|
265
266
|
:cardholder_name, :cvv, :expiration_date, :expiration_month, :expiration_year, :number, :token,
|
266
|
-
{:options => [:make_default, :verify_card]},
|
267
|
+
{:options => [:make_default, :verification_merchant_account_id, :verify_card]},
|
267
268
|
{:billing_address => billing_address_params}
|
268
269
|
]
|
269
270
|
|
@@ -3,7 +3,7 @@ module Braintree
|
|
3
3
|
include BaseModule
|
4
4
|
|
5
5
|
attr_reader :avs_error_response_code, :avs_postal_code_response_code, :avs_street_address_response_code,
|
6
|
-
:cvv_response_code, :processor_response_code, :processor_response_text, :status
|
6
|
+
:cvv_response_code, :merchant_account_id, :processor_response_code, :processor_response_text, :status
|
7
7
|
|
8
8
|
def initialize(attributes) # :nodoc:
|
9
9
|
set_instance_variables_from_hash(attributes)
|
@@ -13,7 +13,8 @@ module Braintree
|
|
13
13
|
attr_order = [
|
14
14
|
:status, :processor_response_code, :processor_response_text,
|
15
15
|
:cvv_response_code, :avs_error_response_code,
|
16
|
-
:avs_postal_code_response_code, :avs_street_address_response_code
|
16
|
+
:avs_postal_code_response_code, :avs_street_address_response_code,
|
17
|
+
:merchant_account_id
|
17
18
|
]
|
18
19
|
formatted_attrs = attr_order.map do |attr|
|
19
20
|
"#{attr}: #{send(attr).inspect}"
|
data/lib/braintree/customer.rb
CHANGED
@@ -52,18 +52,16 @@ module Braintree
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def self.create_customer_url
|
55
|
+
warn "[DEPRECATED] Customer.create_customer_url is deprecated. Please use TransparentRedirect.url"
|
55
56
|
"#{Braintree::Configuration.base_merchant_url}/customers/all/create_via_transparent_redirect_request"
|
56
57
|
end
|
57
58
|
|
58
59
|
def self.create_from_transparent_redirect(query_string)
|
60
|
+
warn "[DEPRECATED] Customer.create_from_transparent_redirect is deprecated. Please use TransparentRedirect.confirm"
|
59
61
|
params = TransparentRedirect.parse_and_validate_query_string query_string
|
60
62
|
_do_create("/customers/all/confirm_transparent_redirect_request", :id => params[:id])
|
61
63
|
end
|
62
64
|
|
63
|
-
def self.create_customer_transparent_redirect_url
|
64
|
-
"#{Braintree::Configuration.base_merchant_url}/customers"
|
65
|
-
end
|
66
|
-
|
67
65
|
def self.credit(customer_id, transaction_attributes)
|
68
66
|
Transaction.credit(transaction_attributes.merge(:customer_id => customer_id))
|
69
67
|
end
|
@@ -118,10 +116,12 @@ module Braintree
|
|
118
116
|
end
|
119
117
|
|
120
118
|
def self.update_customer_url
|
119
|
+
warn "[DEPRECATED] Customer.update_customer_url is deprecated. Please use TransparentRedirect.url"
|
121
120
|
"#{Braintree::Configuration.base_merchant_url}/customers/all/update_via_transparent_redirect_request"
|
122
121
|
end
|
123
122
|
|
124
123
|
def self.update_from_transparent_redirect(query_string)
|
124
|
+
warn "[DEPRECATED] Customer.update_from_transparent_redirect is deprecated. Please use TransparentRedirect.confirm"
|
125
125
|
params = TransparentRedirect.parse_and_validate_query_string(query_string)
|
126
126
|
_do_update(:post, "/customers/all/confirm_transparent_redirect_request", :id => params[:id])
|
127
127
|
end
|
@@ -208,7 +208,7 @@ module Braintree
|
|
208
208
|
]
|
209
209
|
end
|
210
210
|
|
211
|
-
def self._do_create(url, params) # :nodoc:
|
211
|
+
def self._do_create(url, params=nil) # :nodoc:
|
212
212
|
response = Http.post url, params
|
213
213
|
if response[:customer]
|
214
214
|
SuccessfulResult.new(:customer => new(response[:customer]))
|
@@ -235,7 +235,14 @@ module Braintree
|
|
235
235
|
end
|
236
236
|
|
237
237
|
def self._update_signature # :nodoc:
|
238
|
-
|
238
|
+
credit_card_signature = CreditCard._update_signature - [:customer_id]
|
239
|
+
credit_card_options = credit_card_signature.find { |item| item.respond_to?(:keys) && item.keys == [:options] }
|
240
|
+
credit_card_options[:options] << :update_existing_token
|
241
|
+
[
|
242
|
+
:company, :email, :fax, :first_name, :id, :last_name, :phone, :website,
|
243
|
+
{:credit_card => credit_card_signature},
|
244
|
+
{:custom_fields => :_any_key_}
|
245
|
+
]
|
239
246
|
end
|
240
247
|
end
|
241
248
|
end
|
@@ -24,29 +24,34 @@ module Braintree
|
|
24
24
|
BillingAddressIdIsInvalid = "91702"
|
25
25
|
CardholderNameIsTooLong = "81723"
|
26
26
|
CreditCardTypeIsNotAccepted = "81703"
|
27
|
-
|
27
|
+
CreditCardTypeIsNotAcceptedBySubscriptionMerchantAccount = "81718"
|
28
28
|
CustomerIdIsInvalid = "91705"
|
29
|
-
|
29
|
+
CustomerIdIsRequired = "91704"
|
30
30
|
CvvIsInvalid = "81707"
|
31
|
+
CvvIsRequired = "81706"
|
31
32
|
ExpirationDateConflict = "91708"
|
32
|
-
ExpirationDateIsRequired = "81709"
|
33
33
|
ExpirationDateIsInvalid = "81710"
|
34
|
+
ExpirationDateIsRequired = "81709"
|
34
35
|
ExpirationDateYearIsInvalid = "81711"
|
35
36
|
ExpirationMonthIsInvalid = "81712"
|
36
37
|
ExpirationYearIsInvalid = "81713"
|
37
|
-
NumberIsRequired = "81714"
|
38
|
-
NumberIsInvalid = "81715"
|
39
38
|
NumberHasInvalidLength = "81716"
|
39
|
+
NumberIsInvalid = "81715"
|
40
|
+
NumberIsRequired = "81714"
|
40
41
|
NumberMustBeTestNumber = "81717"
|
41
42
|
TokenInvalid = "91718"
|
42
43
|
TokenIsInUse = "91719"
|
43
|
-
TokenIsTooLong = "91720"
|
44
44
|
TokenIsNotAllowed = "91721"
|
45
45
|
TokenIsRequired = "91722"
|
46
|
+
TokenIsTooLong = "91720"
|
47
|
+
|
48
|
+
module Options
|
49
|
+
UpdateExistingTokenIsInvalid = "91723"
|
50
|
+
end
|
46
51
|
end
|
47
52
|
|
48
53
|
module Customer
|
49
|
-
|
54
|
+
CompanyIsTooLong = "81601"
|
50
55
|
CustomFieldIsInvalid = "91602"
|
51
56
|
CustomFieldIsTooLong = "81603"
|
52
57
|
EmailIsInvalid = "81604"
|
@@ -67,6 +72,11 @@ module Braintree
|
|
67
72
|
module Subscription
|
68
73
|
CannotEditCanceledSubscription = "81901"
|
69
74
|
IdIsInUse = "81902"
|
75
|
+
MerchantAccountIdIsInvalid = "91901"
|
76
|
+
PaymentMethodTokenCardTypeIsNotAccepted = "91902"
|
77
|
+
PaymentMethodTokenIsInvalid = "91903"
|
78
|
+
PaymentMethodTokenNotAssociatedWithCustomer = "91905"
|
79
|
+
PlanIdIsInvalid = "91904"
|
70
80
|
PriceCannotBeBlank = "81903"
|
71
81
|
PriceFormatIsInvalid = "81904"
|
72
82
|
StatusIsCanceled = "81905"
|
@@ -81,6 +91,7 @@ module Braintree
|
|
81
91
|
AmountIsRequired = "81502"
|
82
92
|
AmountIsInvalid = "81503"
|
83
93
|
AmountIsTooLarge = "81528"
|
94
|
+
BillingAddressConflict = "91530"
|
84
95
|
CannotBeVoided = "91504"
|
85
96
|
CannotRefundCredit = "91505"
|
86
97
|
CannotRefundUnlessSettled = "91506"
|
@@ -27,7 +27,13 @@ module Braintree
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def inspect # :nodoc:
|
30
|
-
|
30
|
+
if @credit_card_verification
|
31
|
+
verification_inspect = " credit_card_verification: #{@credit_card_verification.inspect}"
|
32
|
+
end
|
33
|
+
if @transaction
|
34
|
+
transaction_inspect = " transaction: #{@transaction.inspect}"
|
35
|
+
end
|
36
|
+
"#<#{self.class} params:{...} errors:<#{@errors._inner_inspect}>#{verification_inspect}#{transaction_inspect}>"
|
31
37
|
end
|
32
38
|
|
33
39
|
# Always returns false.
|
@@ -6,7 +6,6 @@ module Braintree
|
|
6
6
|
|
7
7
|
def self.check_dates # :nodoc:
|
8
8
|
{
|
9
|
-
"QA" => qa_expiration_date,
|
10
9
|
"Sandbox" => sandbox_expiration_date,
|
11
10
|
"Production" => production_expiration_date
|
12
11
|
}.each do |host, expiration_date|
|
@@ -24,9 +23,5 @@ module Braintree
|
|
24
23
|
def self.sandbox_expiration_date # :nodoc:
|
25
24
|
Date.civil(2010, 12, 1)
|
26
25
|
end
|
27
|
-
|
28
|
-
def self.qa_expiration_date # :nodoc:
|
29
|
-
Date.civil(2010, 12, 1)
|
30
|
-
end
|
31
26
|
end
|
32
27
|
end
|
@@ -156,6 +156,7 @@ module Braintree
|
|
156
156
|
|
157
157
|
attr_reader :avs_error_response_code, :avs_postal_code_response_code, :avs_street_address_response_code
|
158
158
|
attr_reader :amount, :created_at, :credit_card_details, :customer_details, :id
|
159
|
+
attr_reader :currency_iso_code
|
159
160
|
attr_reader :custom_fields
|
160
161
|
attr_reader :cvv_response_code
|
161
162
|
attr_reader :merchant_account_id
|
@@ -167,9 +168,11 @@ module Braintree
|
|
167
168
|
attr_reader :processor_response_code
|
168
169
|
# The response text from the processor.
|
169
170
|
attr_reader :processor_response_text
|
171
|
+
attr_reader :refund_id, :refunded_transaction_id
|
170
172
|
# See Transaction::Status
|
171
173
|
attr_reader :status
|
172
174
|
attr_reader :status_history
|
175
|
+
attr_reader :subscription_id
|
173
176
|
# Will either be "sale" or "credit"
|
174
177
|
attr_reader :type
|
175
178
|
attr_reader :updated_at
|
@@ -184,12 +187,14 @@ module Braintree
|
|
184
187
|
end
|
185
188
|
|
186
189
|
def self.create_from_transparent_redirect(query_string)
|
190
|
+
warn "[DEPRECATED] Transaction.create_from_transparent_redirect is deprecated. Please use TransparentRedirect.confirm"
|
187
191
|
params = TransparentRedirect.parse_and_validate_query_string query_string
|
188
192
|
_do_create("/transactions/all/confirm_transparent_redirect_request", :id => params[:id])
|
189
193
|
end
|
190
194
|
|
191
195
|
# The URL to use to create transactions via transparent redirect.
|
192
196
|
def self.create_transaction_url
|
197
|
+
warn "[DEPRECATED] Transaction.create_transaction_url is deprecated. Please use TransparentRedirect.url"
|
193
198
|
"#{Braintree::Configuration.base_merchant_url}/transactions/all/create_via_transparent_redirect_request"
|
194
199
|
end
|
195
200
|
|
@@ -383,7 +388,7 @@ module Braintree
|
|
383
388
|
end
|
384
389
|
end
|
385
390
|
|
386
|
-
def self._do_create(url, params) # :nodoc:
|
391
|
+
def self._do_create(url, params=nil) # :nodoc:
|
387
392
|
response = Http.post url, params
|
388
393
|
if response[:transaction]
|
389
394
|
SuccessfulResult.new(:transaction => new(response[:transaction]))
|
@@ -26,15 +26,38 @@ module Braintree
|
|
26
26
|
CreateCreditCardSignature = TransparentRedirectKeys + [{:credit_card => CreditCard._create_signature}] # :nodoc:
|
27
27
|
UpdateCreditCardSignature = TransparentRedirectKeys + [:payment_method_token, {:credit_card => CreditCard._update_signature}] # :nodoc:
|
28
28
|
|
29
|
+
module Kind
|
30
|
+
CreateCustomer = "create_customer"
|
31
|
+
UpdateCustomer = "update_customer"
|
32
|
+
CreatePaymentMethod = "create_payment_method"
|
33
|
+
UpdatePaymentMethod = "update_payment_method"
|
34
|
+
CreateTransaction = "create_transaction"
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.confirm(query_string)
|
38
|
+
params = TransparentRedirect.parse_and_validate_query_string query_string
|
39
|
+
confirmation_klass = {
|
40
|
+
Kind::CreateCustomer => Braintree::Customer,
|
41
|
+
Kind::UpdateCustomer => Braintree::Customer,
|
42
|
+
Kind::CreatePaymentMethod => Braintree::CreditCard,
|
43
|
+
Kind::UpdatePaymentMethod => Braintree::CreditCard,
|
44
|
+
Kind::CreateTransaction => Braintree::Transaction
|
45
|
+
}[params[:kind]]
|
46
|
+
|
47
|
+
confirmation_klass._do_create("/transparent_redirect_requests/#{params[:id]}/confirm")
|
48
|
+
end
|
49
|
+
|
29
50
|
# Returns the tr_data string for creating a credit card.
|
30
51
|
def self.create_credit_card_data(params)
|
31
52
|
Util.verify_keys(CreateCreditCardSignature, params)
|
53
|
+
params[:kind] = Kind::CreatePaymentMethod
|
32
54
|
_data(params)
|
33
55
|
end
|
34
56
|
|
35
57
|
# Returns the tr_data string for creating a customer.
|
36
58
|
def self.create_customer_data(params)
|
37
59
|
Util.verify_keys(CreateCustomerSignature, params)
|
60
|
+
params[:kind] = Kind::CreateCustomer
|
38
61
|
_data(params)
|
39
62
|
end
|
40
63
|
|
@@ -58,6 +81,7 @@ module Braintree
|
|
58
81
|
# Returns the tr_data string for creating a transaction.
|
59
82
|
def self.transaction_data(params)
|
60
83
|
Util.verify_keys(TransactionSignature, params)
|
84
|
+
params[:kind] = Kind::CreateTransaction
|
61
85
|
transaction_type = params[:transaction] && params[:transaction][:type]
|
62
86
|
unless %w[sale credit].include?(transaction_type)
|
63
87
|
raise ArgumentError, "expected transaction[type] of sale or credit, was: #{transaction_type.inspect}"
|
@@ -77,6 +101,7 @@ module Braintree
|
|
77
101
|
unless params[:payment_method_token]
|
78
102
|
raise ArgumentError, "expected params to contain :payment_method_token of payment method to update"
|
79
103
|
end
|
104
|
+
params[:kind] = Kind::UpdatePaymentMethod
|
80
105
|
_data(params)
|
81
106
|
end
|
82
107
|
|
@@ -92,9 +117,15 @@ module Braintree
|
|
92
117
|
unless params[:customer_id]
|
93
118
|
raise ArgumentError, "expected params to contain :customer_id of customer to update"
|
94
119
|
end
|
120
|
+
params[:kind] = Kind::UpdateCustomer
|
95
121
|
_data(params)
|
96
122
|
end
|
97
123
|
|
124
|
+
# Returns the URL to which Transparent Redirect Requests should be posted
|
125
|
+
def self.url
|
126
|
+
"#{Braintree::Configuration.base_merchant_url}/transparent_redirect_requests"
|
127
|
+
end
|
128
|
+
|
98
129
|
def self._data(params) # :nodoc:
|
99
130
|
raise ArgumentError, "expected params to contain :redirect_url" unless params[:redirect_url]
|
100
131
|
tr_data_segment = Util.hash_to_query_string(params.merge(
|
data/lib/braintree/version.rb
CHANGED
data/lib/braintree/xml/parser.rb
CHANGED
@@ -11,13 +11,21 @@ module Braintree
|
|
11
11
|
"boolean" => Proc.new { |boolean| %w(1 true).include?(boolean.strip) },
|
12
12
|
}
|
13
13
|
|
14
|
-
def self.hash_from_xml(xml)
|
15
|
-
standardized_hash_structure =
|
14
|
+
def self.hash_from_xml(xml, parser = _determine_parser)
|
15
|
+
standardized_hash_structure = parser.parse(xml)
|
16
16
|
with_underscores_in_keys = _unrename_keys(standardized_hash_structure)
|
17
17
|
typecasted_xml = _typecast_xml_value(with_underscores_in_keys)
|
18
18
|
Util.symbolize_keys(typecasted_xml)
|
19
19
|
end
|
20
20
|
|
21
|
+
def self._determine_parser
|
22
|
+
if defined?(::LibXml::XML) && ::LibXml::XML.respond_to?(:default_keep_blanks=)
|
23
|
+
::Braintree::Xml::Libxml
|
24
|
+
else
|
25
|
+
::Braintree::Xml::Rexml
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
21
29
|
def self._typecast_xml_value(value)
|
22
30
|
case value.class.to_s
|
23
31
|
when 'Hash'
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# Portions of this code were copied and modified from Ruby on Rails, released
|
2
|
+
# under the MIT license, copyright (c) 2005-2009 David Heinemeier Hansson
|
3
|
+
module Braintree
|
4
|
+
module Xml
|
5
|
+
module Rexml
|
6
|
+
|
7
|
+
CONTENT_KEY = '__content__'.freeze
|
8
|
+
|
9
|
+
def self.parse(string)
|
10
|
+
require 'rexml/document' unless defined?(REXML::Document)
|
11
|
+
doc = REXML::Document.new(string)
|
12
|
+
_merge_element!({}, doc.root)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self._merge_element!(hash, element)
|
16
|
+
_merge!(hash, element.name, _collapse(element))
|
17
|
+
end
|
18
|
+
|
19
|
+
def self._collapse(element)
|
20
|
+
hash = _get_attributes(element)
|
21
|
+
|
22
|
+
if element.has_elements?
|
23
|
+
element.each_element {|child| _merge_element!(hash, child) }
|
24
|
+
_merge_texts!(hash, element) unless _empty_content?(element)
|
25
|
+
hash
|
26
|
+
else
|
27
|
+
_merge_texts!(hash, element)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self._merge_texts!(hash, element)
|
32
|
+
unless element.has_text?
|
33
|
+
hash
|
34
|
+
else
|
35
|
+
# must use value to prevent double-escaping
|
36
|
+
_merge!(
|
37
|
+
hash,
|
38
|
+
CONTENT_KEY,
|
39
|
+
element.texts.map { |t| t.value}.join
|
40
|
+
)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def self._merge!(hash, key, value)
|
45
|
+
if hash.has_key?(key)
|
46
|
+
if hash[key].instance_of?(Array)
|
47
|
+
hash[key] << value
|
48
|
+
else
|
49
|
+
hash[key] = [hash[key], value]
|
50
|
+
end
|
51
|
+
elsif value.instance_of?(Array)
|
52
|
+
hash[key] = [value]
|
53
|
+
else
|
54
|
+
hash[key] = value
|
55
|
+
end
|
56
|
+
hash
|
57
|
+
end
|
58
|
+
|
59
|
+
def self._get_attributes(element)
|
60
|
+
attributes = {}
|
61
|
+
element.attributes.each { |n,v| attributes[n] = v }
|
62
|
+
attributes
|
63
|
+
end
|
64
|
+
|
65
|
+
def self._empty_content?(element)
|
66
|
+
element.texts.join.strip == ""
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|