braintree 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/LICENSE +22 -0
  2. data/README.rdoc +62 -0
  3. data/lib/braintree.rb +66 -0
  4. data/lib/braintree/address.rb +122 -0
  5. data/lib/braintree/base_module.rb +29 -0
  6. data/lib/braintree/configuration.rb +99 -0
  7. data/lib/braintree/credit_card.rb +231 -0
  8. data/lib/braintree/credit_card_verification.rb +31 -0
  9. data/lib/braintree/customer.rb +231 -0
  10. data/lib/braintree/digest.rb +20 -0
  11. data/lib/braintree/error_codes.rb +95 -0
  12. data/lib/braintree/error_result.rb +39 -0
  13. data/lib/braintree/errors.rb +29 -0
  14. data/lib/braintree/http.rb +105 -0
  15. data/lib/braintree/paged_collection.rb +55 -0
  16. data/lib/braintree/ssl_expiration_check.rb +28 -0
  17. data/lib/braintree/successful_result.rb +38 -0
  18. data/lib/braintree/test/credit_card_numbers.rb +50 -0
  19. data/lib/braintree/test/transaction_amounts.rb +10 -0
  20. data/lib/braintree/transaction.rb +360 -0
  21. data/lib/braintree/transaction/address_details.rb +15 -0
  22. data/lib/braintree/transaction/credit_card_details.rb +22 -0
  23. data/lib/braintree/transaction/customer_details.rb +13 -0
  24. data/lib/braintree/transparent_redirect.rb +110 -0
  25. data/lib/braintree/util.rb +94 -0
  26. data/lib/braintree/validation_error.rb +15 -0
  27. data/lib/braintree/validation_error_collection.rb +80 -0
  28. data/lib/braintree/version.rb +9 -0
  29. data/lib/braintree/xml.rb +12 -0
  30. data/lib/braintree/xml/generator.rb +80 -0
  31. data/lib/braintree/xml/libxml.rb +69 -0
  32. data/lib/braintree/xml/parser.rb +93 -0
  33. data/lib/ssl/securetrust_ca.crt +44 -0
  34. data/lib/ssl/valicert_ca.crt +18 -0
  35. data/spec/integration/braintree/address_spec.rb +352 -0
  36. data/spec/integration/braintree/credit_card_spec.rb +676 -0
  37. data/spec/integration/braintree/customer_spec.rb +664 -0
  38. data/spec/integration/braintree/http_spec.rb +201 -0
  39. data/spec/integration/braintree/test/transaction_amounts_spec.rb +29 -0
  40. data/spec/integration/braintree/transaction_spec.rb +900 -0
  41. data/spec/integration/spec_helper.rb +38 -0
  42. data/spec/script/httpsd.rb +27 -0
  43. data/spec/spec_helper.rb +41 -0
  44. data/spec/unit/braintree/address_spec.rb +86 -0
  45. data/spec/unit/braintree/configuration_spec.rb +190 -0
  46. data/spec/unit/braintree/credit_card_spec.rb +137 -0
  47. data/spec/unit/braintree/credit_card_verification_spec.rb +17 -0
  48. data/spec/unit/braintree/customer_spec.rb +103 -0
  49. data/spec/unit/braintree/digest_spec.rb +28 -0
  50. data/spec/unit/braintree/error_result_spec.rb +42 -0
  51. data/spec/unit/braintree/errors_spec.rb +81 -0
  52. data/spec/unit/braintree/http_spec.rb +42 -0
  53. data/spec/unit/braintree/paged_collection_spec.rb +128 -0
  54. data/spec/unit/braintree/ssl_expiration_check_spec.rb +92 -0
  55. data/spec/unit/braintree/successful_result_spec.rb +27 -0
  56. data/spec/unit/braintree/transaction/credit_card_details_spec.rb +22 -0
  57. data/spec/unit/braintree/transaction_spec.rb +136 -0
  58. data/spec/unit/braintree/transparent_redirect_spec.rb +154 -0
  59. data/spec/unit/braintree/util_spec.rb +142 -0
  60. data/spec/unit/braintree/validation_error_collection_spec.rb +128 -0
  61. data/spec/unit/braintree/validation_error_spec.rb +19 -0
  62. data/spec/unit/braintree/xml/libxml_spec.rb +51 -0
  63. data/spec/unit/braintree/xml_spec.rb +122 -0
  64. data/spec/unit/spec_helper.rb +1 -0
  65. metadata +118 -0
@@ -0,0 +1,38 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ require 'timeout'
4
+ require 'socket'
5
+
6
+
7
+ def start_ssl_server
8
+ web_server_pid_file = File.expand_path(File.join(File.dirname(__FILE__), "..", "httpsd.pid"))
9
+
10
+ TCPSocket.class_eval do
11
+ def self.wait_for_service(options)
12
+ Timeout::timeout(options[:timeout] || 20) do
13
+ loop do
14
+ begin
15
+ socket = TCPSocket.new(options[:host], options[:port])
16
+ socket.close
17
+ return
18
+ rescue Errno::ECONNREFUSED
19
+ sleep 0.5
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ FileUtils.rm(web_server_pid_file) if File.exist?(web_server_pid_file)
27
+ command = File.expand_path(File.join(File.dirname(__FILE__), "..", "script", "httpsd.rb"))
28
+ #puts command
29
+ `#{command} #{web_server_pid_file}`
30
+ #puts "== waiting for web server - port: #{8433}"
31
+ TCPSocket.wait_for_service :host => "127.0.0.1", :port => 8443
32
+
33
+ yield
34
+
35
+ 10.times { unless File.exists?(web_server_pid_file); sleep 1; end }
36
+ #puts "\n== killing web server - pid: #{File.read(web_server_pid_file).to_i}"
37
+ Process.kill "INT", File.read(web_server_pid_file).to_i
38
+ end
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ require 'webrick'
3
+ require 'webrick/https'
4
+ require 'openssl'
5
+
6
+ private_key_file = File.expand_path(File.join(File.dirname(__FILE__), "..", "ssl", "privateKey.key"))
7
+ cert_file = File.expand_path(File.join(File.dirname(__FILE__), "..", "ssl", "certificate.crt"))
8
+
9
+ pkey = OpenSSL::PKey::RSA.new(File.read(private_key_file))
10
+ cert = OpenSSL::X509::Certificate.new(File.read(cert_file))
11
+
12
+ pid_file = ARGV[0]
13
+
14
+ s = WEBrick::HTTPServer.new(
15
+ :Port => 8443,
16
+ :Logger => WEBrick::Log::new(nil, WEBrick::Log::ERROR),
17
+ :DocumentRoot => File.join(File.dirname(__FILE__)),
18
+ :ServerType => WEBrick::Daemon,
19
+ :SSLEnable => true,
20
+ :SSLVerifyClient => OpenSSL::SSL::VERIFY_NONE,
21
+ :SSLCertificate => cert,
22
+ :SSLPrivateKey => pkey,
23
+ :SSLCertName => [ [ "CN",WEBrick::Utils::getservername ] ],
24
+ :StartCallback => proc { File.open(pid_file, "w") { |f| f.write $$.to_s }}
25
+ )
26
+ trap("INT"){ s.shutdown }
27
+ s.start
@@ -0,0 +1,41 @@
1
+ unless defined?(SPEC_HELPER_LOADED)
2
+ SPEC_HELPER_LOADED = true
3
+
4
+ project_root = File.expand_path(File.dirname(__FILE__) + "/..")
5
+ require "rubygems"
6
+ gem "libxml-ruby", ENV["LIBXML_VERSION"] || "1.1.3"
7
+ gem "builder", ENV["BUILDER_VERSION"] || "2.1.2"
8
+ braintree_lib = "#{project_root}/lib"
9
+ $LOAD_PATH << braintree_lib
10
+ require "braintree"
11
+
12
+ Braintree::Configuration.environment = :development
13
+ Braintree::Configuration.merchant_id = "integration_merchant_id"
14
+ Braintree::Configuration.public_key = "integration_public_key"
15
+ Braintree::Configuration.private_key = "integration_private_key"
16
+ Braintree::Configuration.logger = Logger.new("/dev/null")
17
+ Braintree::Configuration.logger.level = Logger::INFO
18
+
19
+ Spec::Runner.configure do |config|
20
+ end
21
+
22
+ module SpecHelper
23
+ def self.stub_time_dot_now(desired_time)
24
+ Time.class_eval do
25
+ class << self
26
+ alias original_now now
27
+ end
28
+ end
29
+ (class << Time; self; end).class_eval do
30
+ define_method(:now) { desired_time }
31
+ end
32
+ yield
33
+ ensure
34
+ Time.class_eval do
35
+ class << self
36
+ alias now original_now
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,86 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe Braintree::Address do
4
+ describe "==" do
5
+ it "returns true if given an address with the same id and customer_id" do
6
+ first = Braintree::Address._new(:customer_id => "c1", :id => 'a1')
7
+ second = Braintree::Address._new(:customer_id => "c1", :id => "a1")
8
+
9
+ first.should == second
10
+ second.should == first
11
+ end
12
+
13
+ it "returns false if given an address with a different id and the same customer_id" do
14
+ first = Braintree::Address._new(:customer_id => "c1", :id => "a1")
15
+ second = Braintree::Address._new(:customer_id => "c1", :id => "not a1")
16
+
17
+ first.should_not == second
18
+ second.should_not == first
19
+ end
20
+
21
+ it "returns false if given an address with a different customer_id and the same id" do
22
+ first = Braintree::Address._new(:customer_id => "c1", :id => "a1")
23
+ second = Braintree::Address._new(:customer_id => "not c1", :id => "a1")
24
+
25
+ first.should_not == second
26
+ second.should_not == first
27
+ end
28
+
29
+ it "returns false when not given an address" do
30
+ address = Braintree::Address._new(:id => "a1")
31
+ address.should_not == "not an address"
32
+ end
33
+ end
34
+
35
+ describe "self.create" do
36
+ it "raises an ArgumentError if not given a :customer_id" do
37
+ expect do
38
+ Braintree::Address.create({})
39
+ end.to raise_error(ArgumentError, "Expected hash to contain a :customer_id")
40
+ end
41
+
42
+ it "raises if customer id contains invalid chars" do
43
+ expect do
44
+ Braintree::Address.create(:customer_id => "invalid@chars")
45
+ end.to raise_error(ArgumentError, ":customer_id contains invalid characters")
46
+ end
47
+
48
+ it "raises an exception if hash includes an invalid key" do
49
+ expect do
50
+ Braintree::Address.create(:street_address => "123 E Main St", :invalid_key => "foo")
51
+ end.to raise_error(ArgumentError, "invalid keys: invalid_key")
52
+ end
53
+ end
54
+
55
+ describe "self.update" do
56
+ it "raises an exception if hash includes an invalid key" do
57
+ expect do
58
+ Braintree::Address.update("customer_id", "address_id", :street_address => "456 E Main", :invalid_key => "foo")
59
+ end.to raise_error(ArgumentError, "invalid keys: invalid_key")
60
+ end
61
+ end
62
+
63
+ describe "self.find" do
64
+ it "raises an error if customer_id contains invalid chars" do
65
+ expect do
66
+ Braintree::Address.find("spaces not allowed", "address_id")
67
+ end.to raise_error(ArgumentError, "customer_id contains invalid characters")
68
+ end
69
+ end
70
+
71
+ describe "self.new" do
72
+ it "is protected" do
73
+ expect do
74
+ Braintree::Address.new
75
+ end.to raise_error(NoMethodError, /protected method .new/)
76
+ end
77
+ end
78
+
79
+ describe "update" do
80
+ it "raises an exception if hash includes an invalid key" do
81
+ expect do
82
+ Braintree::Address._new({}).update(:street_address => "456 E Main", :invalid_key2 => "foo")
83
+ end.to raise_error(ArgumentError, "invalid keys: invalid_key2")
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,190 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe Braintree::Configuration do
4
+
5
+ before do
6
+ @original_merchant_id = Braintree::Configuration.merchant_id
7
+ @original_public_key = Braintree::Configuration.public_key
8
+ @original_private_key = Braintree::Configuration.private_key
9
+ @original_environment = Braintree::Configuration.environment
10
+ end
11
+
12
+ after do
13
+ Braintree::Configuration.merchant_id = @original_merchant_id
14
+ Braintree::Configuration.public_key = @original_public_key
15
+ Braintree::Configuration.private_key = @original_private_key
16
+ Braintree::Configuration.environment = @original_environment
17
+ end
18
+
19
+ describe "self.base_merchant_path" do
20
+ it "returns /merchants/{merchant_id}" do
21
+ Braintree::Configuration.base_merchant_path.should == "/merchants/integration_merchant_id"
22
+ end
23
+ end
24
+
25
+ describe "self.base_merchant_url" do
26
+ it "returns the expected url for the development env" do
27
+ Braintree::Configuration.environment = :development
28
+ Braintree::Configuration.base_merchant_url.should == "http://localhost:3000/merchants/integration_merchant_id"
29
+ end
30
+
31
+ it "returns the expected url for the sandbox env" do
32
+ Braintree::Configuration.environment = :sandbox
33
+ Braintree::Configuration.base_merchant_url.should == "https://sandbox.braintreegateway.com:443/merchants/integration_merchant_id"
34
+ end
35
+
36
+ it "returns the expected url for the production env" do
37
+ Braintree::Configuration.environment = :production
38
+ Braintree::Configuration.base_merchant_url.should == "https://www.braintreegateway.com:443/merchants/integration_merchant_id"
39
+ end
40
+ end
41
+
42
+ describe "self.ca_file" do
43
+ it "qa" do
44
+ Braintree::Configuration.environment = :qa
45
+ ca_file = Braintree::Configuration.ca_file
46
+ ca_file.should match(/valicert_ca.crt$/)
47
+ File.exists?(ca_file).should == true
48
+ end
49
+
50
+ it "sandbox" do
51
+ Braintree::Configuration.environment = :sandbox
52
+ ca_file = Braintree::Configuration.ca_file
53
+ ca_file.should match(/valicert_ca.crt$/)
54
+ File.exists?(ca_file).should == true
55
+ end
56
+
57
+ it "production" do
58
+ Braintree::Configuration.environment = :production
59
+ ca_file = Braintree::Configuration.ca_file
60
+ ca_file.should match(/securetrust_ca.crt$/)
61
+ File.exists?(ca_file).should == true
62
+ end
63
+ end
64
+
65
+ describe "self.environment" do
66
+ it "raises an exception if it hasn't been set yet" do
67
+ Braintree::Configuration.instance_variable_set(:@environment, nil)
68
+ expect do
69
+ Braintree::Configuration.environment
70
+ end.to raise_error(Braintree::ConfigurationError, "Braintree::Configuration.environment needs to be set")
71
+ end
72
+ end
73
+
74
+ describe "self.environment=" do
75
+ it "raises an exception if the environment is invalid" do
76
+ expect do
77
+ Braintree::Configuration.environment = :invalid_environment
78
+ end.to raise_error(ArgumentError, ":invalid_environment is not a valid environment")
79
+ end
80
+ end
81
+
82
+ describe "self.logger" do
83
+ it "defaults to logging to stdout with log_level info" do
84
+ begin
85
+ old_logger = Braintree::Configuration.logger
86
+ Braintree::Configuration.logger = nil
87
+ Braintree::Configuration.logger.level.should == Logger::INFO
88
+ ensure
89
+ Braintree::Configuration.logger = old_logger
90
+ end
91
+ end
92
+ end
93
+
94
+ describe "self.merchant_id" do
95
+ it "raises an exception if it hasn't been set yet" do
96
+ Braintree::Configuration.instance_variable_set(:@merchant_id, nil)
97
+ expect do
98
+ Braintree::Configuration.merchant_id
99
+ end.to raise_error(Braintree::ConfigurationError, "Braintree::Configuration.merchant_id needs to be set")
100
+ end
101
+ end
102
+
103
+ describe "self.public_key" do
104
+ it "raises an exception if it hasn't been set yet" do
105
+ Braintree::Configuration.instance_variable_set(:@public_key, nil)
106
+ expect do
107
+ Braintree::Configuration.public_key
108
+ end.to raise_error(Braintree::ConfigurationError, "Braintree::Configuration.public_key needs to be set")
109
+ end
110
+ end
111
+
112
+ describe "self.private_key" do
113
+ it "raises an exception if it hasn't been set yet" do
114
+ Braintree::Configuration.instance_variable_set(:@private_key, nil)
115
+ expect do
116
+ Braintree::Configuration.private_key
117
+ end.to raise_error(Braintree::ConfigurationError, "Braintree::Configuration.private_key needs to be set")
118
+ end
119
+ end
120
+
121
+ describe "self.port" do
122
+ it "is 443 for production" do
123
+ Braintree::Configuration.environment = :production
124
+ Braintree::Configuration.port.should == 443
125
+ end
126
+
127
+ it "is 443 for sandbox" do
128
+ Braintree::Configuration.environment = :sandbox
129
+ Braintree::Configuration.port.should == 443
130
+ end
131
+
132
+ it "is 3000 for development" do
133
+ Braintree::Configuration.environment = :development
134
+ Braintree::Configuration.port.should == 3000
135
+ end
136
+ end
137
+
138
+ describe "self.protocol" do
139
+ it "is http for development" do
140
+ Braintree::Configuration.environment = :development
141
+ Braintree::Configuration.protocol.should == "http"
142
+ end
143
+
144
+ it "is https for production" do
145
+ Braintree::Configuration.environment = :production
146
+ Braintree::Configuration.protocol.should == "https"
147
+ end
148
+
149
+ it "is https for sandbox" do
150
+ Braintree::Configuration.environment = :sandbox
151
+ Braintree::Configuration.protocol.should == "https"
152
+ end
153
+
154
+ end
155
+
156
+ describe "self.server" do
157
+ it "is localhost for development" do
158
+ Braintree::Configuration.environment = :development
159
+ Braintree::Configuration.server.should == "localhost"
160
+ end
161
+
162
+ it "is www.braintreegateway.com for production" do
163
+ Braintree::Configuration.environment = :production
164
+ Braintree::Configuration.server.should == "www.braintreegateway.com"
165
+ end
166
+
167
+ it "is sandbox.braintreegateway.com for sandbox" do
168
+ Braintree::Configuration.environment = :sandbox
169
+ Braintree::Configuration.server.should == "sandbox.braintreegateway.com"
170
+ end
171
+ end
172
+
173
+ describe "self.ssl?" do
174
+ it "returns false for development" do
175
+ Braintree::Configuration.environment = :development
176
+ Braintree::Configuration.ssl?.should == false
177
+ end
178
+
179
+ it "returns true for production" do
180
+ Braintree::Configuration.environment = :production
181
+ Braintree::Configuration.ssl?.should == true
182
+ end
183
+
184
+ it "returns true for sandbox" do
185
+ Braintree::Configuration.environment = :sandbox
186
+ Braintree::Configuration.ssl?.should == true
187
+ end
188
+ end
189
+
190
+ end
@@ -0,0 +1,137 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe Braintree::CreditCard do
4
+ describe "self.create" do
5
+ it "raises an exception if attributes contain an invalid key" do
6
+ expect do
7
+ Braintree::CreditCard.create(:invalid_key => 'val')
8
+ end.to raise_error(ArgumentError, "invalid keys: invalid_key")
9
+ end
10
+ end
11
+
12
+ describe "self.create_from_transparent_redirect" do
13
+ it "raises an exception if the query string is forged" do
14
+ expect do
15
+ Braintree::CreditCard.create_from_transparent_redirect("forged=query_string")
16
+ end.to raise_error(Braintree::ForgedQueryString)
17
+ end
18
+ end
19
+
20
+ describe "self.create_credit_card_url" do
21
+ it "returns the url" do
22
+ Braintree::CreditCard.create_credit_card_url.should == "http://localhost:3000/merchants/integration_merchant_id/payment_methods/all/create_via_transparent_redirect_request"
23
+ end
24
+ end
25
+
26
+ describe "==" do
27
+ it "returns true if given a credit card with the same token" do
28
+ first = Braintree::CreditCard._new(:token => 123)
29
+ second = Braintree::CreditCard._new(:token => 123)
30
+
31
+ first.should == second
32
+ second.should == first
33
+ end
34
+
35
+ it "returns false if given a credit card with a different token" do
36
+ first = Braintree::CreditCard._new(:token => 123)
37
+ second = Braintree::CreditCard._new(:token => 124)
38
+
39
+ first.should_not == second
40
+ second.should_not == first
41
+ end
42
+
43
+ it "returns false if not given a credit card" do
44
+ credit_card = Braintree::CreditCard._new(:token => 123)
45
+ credit_card.should_not == "not a credit card"
46
+ end
47
+ end
48
+
49
+ describe "default?" do
50
+ it "is true if the credit card is the default credit card for the customer" do
51
+ Braintree::CreditCard._new(:default => true).default?.should == true
52
+ end
53
+
54
+ it "is false if the credit card is not the default credit card for the customer" do
55
+ Braintree::CreditCard._new(:default => false).default?.should == false
56
+ end
57
+ end
58
+
59
+ describe "expired?" do
60
+ it "is true if the payment method is this year and the month has passed" do
61
+ SpecHelper.stub_time_dot_now(Time.mktime(2009, 10, 20)) do
62
+ expired_pm = Braintree::CreditCard._new(:expiration_month => "09", :expiration_year => "2009")
63
+ expired_pm.expired?.should == true
64
+ end
65
+ end
66
+
67
+ it "is true if the payment method is in a previous year" do
68
+ expired_pm = Braintree::CreditCard._new(:expiration_month => "12", :expiration_year => (Time.now.year - 1).to_s)
69
+ expired_pm.expired?.should == true
70
+ end
71
+
72
+ it "is false if the payment method is not expired" do
73
+ not_expired_pm = Braintree::CreditCard._new(:expiration_month => "01", :expiration_year => (Time.now.year + 1).to_s)
74
+ not_expired_pm.expired?.should == false
75
+ end
76
+ end
77
+
78
+ describe "inspect" do
79
+ it "includes the token first" do
80
+ output = Braintree::CreditCard._new(:token => "cc123").inspect
81
+ output.should include("#<Braintree::CreditCard token: \"cc123\",")
82
+ end
83
+
84
+ it "includes all customer attributes" do
85
+ credit_card = Braintree::CreditCard._new(
86
+ :bin => "411111",
87
+ :card_type => "Visa",
88
+ :cardholder_name => "John Miller",
89
+ :created_at => Time.now,
90
+ :customer_id => "cid1",
91
+ :expiration_month => "01",
92
+ :expiration_year => "2020",
93
+ :last_4 => "1111",
94
+ :token => "tok1",
95
+ :updated_at => Time.now
96
+ )
97
+ output = credit_card.inspect
98
+ output.should include(%q(bin: "411111"))
99
+ output.should include(%q(card_type: "Visa"))
100
+ output.should include(%q(cardholder_name: "John Miller"))
101
+
102
+ output.should include(%q(customer_id: "cid1"))
103
+ output.should include(%q(expiration_month: "01"))
104
+ output.should include(%q(expiration_year: "2020"))
105
+ output.should include(%q(last_4: "1111"))
106
+ output.should include(%q(token: "tok1"))
107
+ output.should include(%Q(updated_at: #{credit_card.updated_at.inspect}))
108
+ output.should include(%Q(created_at: #{credit_card.created_at.inspect}))
109
+ end
110
+ end
111
+
112
+ describe "masked_number" do
113
+ it "uses the bin and last_4 to build the masked number" do
114
+ credit_card = Braintree::CreditCard._new(
115
+ :bin => "510510",
116
+ :last_4 => "5100"
117
+ )
118
+ credit_card.masked_number.should == "510510******5100"
119
+ end
120
+ end
121
+
122
+ describe "self.update" do
123
+ it "raises an exception if attributes contain an invalid key" do
124
+ expect do
125
+ Braintree::CreditCard._new({}).update(:invalid_key => 'val')
126
+ end.to raise_error(ArgumentError, "invalid keys: invalid_key")
127
+ end
128
+ end
129
+
130
+ describe "self.new" do
131
+ it "is protected" do
132
+ expect do
133
+ Braintree::CreditCard.new
134
+ end.to raise_error(NoMethodError, /protected method .new/)
135
+ end
136
+ end
137
+ end