Showing
12 changed files
with
274 additions
and
52 deletions
Guardfile
0 → 100644
1 | +# A sample Guardfile | ||
2 | +# More info at https://github.com/guard/guard#readme | ||
3 | + | ||
4 | +## Uncomment and set this to only include directories you want to watch | ||
5 | +# directories %w(app lib config test spec features) \ | ||
6 | +# .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")} | ||
7 | + | ||
8 | +## Note: if you are using the `directories` clause above and you are not | ||
9 | +## watching the project directory ('.'), then you will want to move | ||
10 | +## the Guardfile to a watched dir and symlink it back, e.g. | ||
11 | +# | ||
12 | +# $ mkdir config | ||
13 | +# $ mv Guardfile config/ | ||
14 | +# $ ln -s config/Guardfile . | ||
15 | +# | ||
16 | +# and, you'll have to watch "config/Guardfile" instead of "Guardfile" | ||
17 | + | ||
18 | +# Note: The cmd option is now required due to the increasing number of ways | ||
19 | +# rspec may be run, below are examples of the most common uses. | ||
20 | +# * bundler: 'bundle exec rspec' | ||
21 | +# * bundler binstubs: 'bin/rspec' | ||
22 | +# * spring: 'bin/rspec' (This will use spring if running and you have | ||
23 | +# installed the spring binstubs per the docs) | ||
24 | +# * zeus: 'zeus rspec' (requires the server to be started separately) | ||
25 | +# * 'just' rspec: 'rspec' | ||
26 | + | ||
27 | +guard :rspec, cmd: 'bundle exec rspec --color --format d' do | ||
28 | + require 'guard/rspec/dsl' | ||
29 | + dsl = Guard::RSpec::Dsl.new(self) | ||
30 | + | ||
31 | + # Feel free to open issues for suggestions and improvements | ||
32 | + | ||
33 | + # RSpec files | ||
34 | + rspec = dsl.rspec | ||
35 | + watch(rspec.spec_helper) { rspec.spec_dir } | ||
36 | + watch(rspec.spec_support) { rspec.spec_dir } | ||
37 | + watch(rspec.spec_files) | ||
38 | + | ||
39 | + # Ruby files | ||
40 | + ruby = dsl.ruby | ||
41 | + dsl.watch_spec_files_for(ruby.lib_files) | ||
42 | + | ||
43 | + # Rails files | ||
44 | + rails = dsl.rails(view_extensions: %w(erb haml slim)) | ||
45 | + dsl.watch_spec_files_for(rails.app_files) | ||
46 | + dsl.watch_spec_files_for(rails.views) | ||
47 | + | ||
48 | + watch(rails.controllers) do |m| | ||
49 | + [ | ||
50 | + rspec.spec.call("routing/#{m[1]}_routing"), | ||
51 | + rspec.spec.call("controllers/#{m[1]}_controller"), | ||
52 | + rspec.spec.call("acceptance/#{m[1]}") | ||
53 | + ] | ||
54 | + end | ||
55 | + | ||
56 | + # Rails config changes | ||
57 | + watch(rails.spec_helper) { rspec.spec_dir } | ||
58 | + watch(rails.routes) { "#{rspec.spec_dir}/routing" } | ||
59 | + watch(rails.app_controller) { "#{rspec.spec_dir}/controllers" } | ||
60 | + | ||
61 | + # Capybara features specs | ||
62 | + watch(rails.view_dirs) { |m| rspec.spec.call("features/#{m[1]}") } | ||
63 | + watch(rails.layouts) { |m| rspec.spec.call("features/#{m[1]}") } | ||
64 | + | ||
65 | + # Turnip features and steps | ||
66 | + watch(%r{^spec/acceptance/(.+)\.feature$}) | ||
67 | + watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) do |m| | ||
68 | + Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' | ||
69 | + end | ||
70 | +end |
... | @@ -3,13 +3,14 @@ | ... | @@ -3,13 +3,14 @@ |
3 | require 'bundler/setup' | 3 | require 'bundler/setup' |
4 | require 'active_record' | 4 | require 'active_record' |
5 | require 'active_support' | 5 | require 'active_support' |
6 | +require 'var' | ||
7 | + | ||
6 | require_relative '../spec/mocks/var_database_mock.rb' | 8 | require_relative '../spec/mocks/var_database_mock.rb' |
7 | require_relative '../spec/mocks/var_models_mock.rb' | 9 | require_relative '../spec/mocks/var_models_mock.rb' |
8 | -require 'var' | ||
9 | 10 | ||
10 | -ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:") | 11 | +ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:') |
11 | ActiveRecord::Schema.verbose = false | 12 | ActiveRecord::Schema.verbose = false |
12 | VarDatabaseMock.setup_db | 13 | VarDatabaseMock.setup_db |
13 | 14 | ||
14 | -require "pry" | 15 | +require 'pry' |
15 | Pry.start | 16 | Pry.start | ... | ... |
... | @@ -52,7 +52,8 @@ module ActsAsChargeable | ... | @@ -52,7 +52,8 @@ module ActsAsChargeable |
52 | line_items: [{ | 52 | line_items: [{ |
53 | description: sync(:conekta, 'description'), quantity: 1, | 53 | description: sync(:conekta, 'description'), quantity: 1, |
54 | unit_price: sync(:conekta, 'amount'), name: sync(:conekta, 'name') | 54 | unit_price: sync(:conekta, 'amount'), name: sync(:conekta, 'name') |
55 | - }] } | 55 | + }] |
56 | + } | ||
56 | }.merge(conekta_type_of_charge(options))) | 57 | }.merge(conekta_type_of_charge(options))) |
57 | end | 58 | end |
58 | 59 | ||
... | @@ -61,8 +62,7 @@ module ActsAsChargeable | ... | @@ -61,8 +62,7 @@ module ActsAsChargeable |
61 | { card: options[:card_token] } | 62 | { card: options[:card_token] } |
62 | elsif options[:conekta_type] == 'oxxo' | 63 | elsif options[:conekta_type] == 'oxxo' |
63 | { cash: { type: 'oxxo', | 64 | { cash: { type: 'oxxo', |
64 | - expires_at: (Time.zone.today + 3.days).strftime('%Y-%m-%d') } | 65 | + expires_at: (Time.zone.today + 3.days).strftime('%Y-%m-%d') } } |
65 | - } | ||
66 | end | 66 | end |
67 | end | 67 | end |
68 | 68 | ||
... | @@ -176,13 +176,11 @@ module ActsAsChargeable | ... | @@ -176,13 +176,11 @@ module ActsAsChargeable |
176 | private | 176 | private |
177 | 177 | ||
178 | def clean_var_variables | 178 | def clean_var_variables |
179 | - if update_columns(var_status: nil, var_barcode: nil, var_barcode_url: nil, | 179 | + return { object: code } if update(var_status: nil, var_barcode: nil, |
180 | - var_id: nil, var_service: nil, var_payment_at: nil, | 180 | + var_barcode_url: nil, var_id: nil, |
181 | - var_payment_expires_at: nil) | 181 | + var_service: nil, var_payment_at: nil, |
182 | - { object: code } | 182 | + var_payment_expires_at: nil) |
183 | - else | 183 | + { error_message: 'Something went wrong' } |
184 | - { error_message: 'Something went wrong' } | ||
185 | - end | ||
186 | end | 184 | end |
187 | end | 185 | end |
188 | end | 186 | end | ... | ... |
... | @@ -5,16 +5,10 @@ require 'acts_as_chargeable' | ... | @@ -5,16 +5,10 @@ require 'acts_as_chargeable' |
5 | 5 | ||
6 | # Main Module | 6 | # Main Module |
7 | module Var | 7 | module Var |
8 | - | 8 | + VALID_SERVICES = [:conekta].freeze |
9 | - VALID_SERVICES = [:conekta] | ||
10 | @@var_classes = [] | 9 | @@var_classes = [] |
11 | 10 | ||
12 | class << self | 11 | class << self |
13 | - | ||
14 | - def valid_services | ||
15 | - VALID_SERVICES | ||
16 | - end | ||
17 | - | ||
18 | def var_classes | 12 | def var_classes |
19 | @@var_classes | 13 | @@var_classes |
20 | end | 14 | end |
... | @@ -24,26 +18,31 @@ module Var | ... | @@ -24,26 +18,31 @@ module Var |
24 | end | 18 | end |
25 | 19 | ||
26 | def create_charge(service, object, options = {}) | 20 | def create_charge(service, object, options = {}) |
27 | - return { error_message: 'Service is not supported' } unless VALID_SERVICES.include? service | 21 | + raise 'Service is not supported' unless supported_service? service |
28 | - return { error_message: "#{object.class} doesn't support charges" } unless object.respond_to?(:charge_with) | 22 | + raise "#{object.class} doesn't support charges" unless object.respond_to? :charge_with |
29 | - charge = object.charge_with(service, options) | 23 | + object.charge_with(service, options) |
30 | - charge | ||
31 | end | 24 | end |
32 | 25 | ||
33 | def conekta_webhook(params) | 26 | def conekta_webhook(params) |
34 | payment = params[:data][:object] | 27 | payment = params[:data][:object] |
35 | object = Var.find_charge payment[:id] | 28 | object = Var.find_charge payment[:id] |
36 | - object.update_columns(var_status: payment[:status]) | 29 | + update_object_var_data(object, payment) |
37 | - if object.var_payed? | ||
38 | - time = Time.strptime payment[:paid_at].to_s, '%s' | ||
39 | - amount = payment[:amount].to_f / 100.0 | ||
40 | - fee = payment[:fee].to_f / 100.0 | ||
41 | - object.update(var_fee: fee, var_paid_amount: amount, var_payment_method: payment[:payment_method][:object], var_payment_at: time) | ||
42 | - end | ||
43 | object | 30 | object |
44 | - rescue Exception => exception | 31 | + # rescue Exception => exception |
45 | - puts exception | 32 | + # puts exception |
46 | - false | 33 | + # false |
34 | + end | ||
35 | + | ||
36 | + def update_object_var_data(object, data) | ||
37 | + payment = data | ||
38 | + object.update_columns(var_status: payment[:status]) | ||
39 | + return object unless object.var_payed? | ||
40 | + time = Time.strptime payment[:paid_at].to_s, '%s' | ||
41 | + amount = payment[:amount].to_f / 100.0 | ||
42 | + fee = payment[:fee].to_f / 100.0 | ||
43 | + object.update(var_fee: fee, var_paid_amount: amount, | ||
44 | + var_payment_method: payment[:payment_method][:object], | ||
45 | + var_payment_at: time) | ||
47 | end | 46 | end |
48 | 47 | ||
49 | def find_charge(id) | 48 | def find_charge(id) |
... | @@ -52,6 +51,13 @@ module Var | ... | @@ -52,6 +51,13 @@ module Var |
52 | class_name.where(var_id: id) | 51 | class_name.where(var_id: id) |
53 | end.flatten.first | 52 | end.flatten.first |
54 | end | 53 | end |
54 | + | ||
55 | + private | ||
56 | + | ||
57 | + def supported_service?(service) | ||
58 | + VALID_SERVICES.include? service | ||
59 | + end | ||
60 | + | ||
55 | end | 61 | end |
56 | end | 62 | end |
57 | 63 | ... | ... |
spec/acts_as_chargeable_spec.rb
0 → 100644
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe ActsAsChargeable do | ||
4 | + context 'as a module' do | ||
5 | + it 'can be implemented in ActiveRecord' do | ||
6 | + expect(Product).to respond_to(:acts_as_chargeable) | ||
7 | + end | ||
8 | + end | ||
9 | +end | ||
10 | + | ||
11 | +# Tests for mock on Chargeable class | ||
12 | +describe Product do | ||
13 | + it { is_expected.to respond_to(:charge_with) } | ||
14 | + it { is_expected.to respond_to(:charge_with_conekta) } | ||
15 | + it { is_expected.to respond_to(:conekta_charge) } | ||
16 | + it { is_expected.to respond_to(:conekta_type_of_charge) } | ||
17 | + it { is_expected.to respond_to(:update_conekta_barcode) } | ||
18 | + it { is_expected.to respond_to(:manual_charge) } | ||
19 | + it { is_expected.to respond_to(:manual_discharge) } | ||
20 | + it { is_expected.to respond_to(:find_charge) } | ||
21 | + it { is_expected.to respond_to(:charged?) } | ||
22 | + it { is_expected.to respond_to(:find_conekta_charge) } | ||
23 | + it { is_expected.to respond_to(:instance_support?) } | ||
24 | + it { is_expected.to respond_to(:sync) } | ||
25 | + it { is_expected.to respond_to(:conekta_attributes) } | ||
26 | + it { is_expected.to respond_to(:paypal_attributes) } | ||
27 | + it { is_expected.to respond_to(:var_payed?) } | ||
28 | + it { is_expected.to respond_to(:cancel_oxxo_payment) } | ||
29 | + it { is_expected.to respond_to(:var_expired_by) } | ||
30 | +end |
... | @@ -3,7 +3,7 @@ class VarDatabaseMock | ... | @@ -3,7 +3,7 @@ class VarDatabaseMock |
3 | def setup_db | 3 | def setup_db |
4 | ActiveRecord::Schema.define(version: 1) do | 4 | ActiveRecord::Schema.define(version: 1) do |
5 | create_table :products do |t| | 5 | create_table :products do |t| |
6 | - t.string :code | 6 | + t.string :code |
7 | 7 | ||
8 | t.string :var_status, default: 'pending' | 8 | t.string :var_status, default: 'pending' |
9 | t.string :var_barcode_url | 9 | t.string :var_barcode_url | ... | ... |
1 | require 'pry' | 1 | require 'pry' |
2 | require 'active_record' | 2 | require 'active_record' |
3 | require 'active_support' | 3 | require 'active_support' |
4 | +require 'Var' | ||
5 | + | ||
4 | require 'mocks/var_database_mock' | 6 | require 'mocks/var_database_mock' |
5 | require 'mocks/var_models_mock' | 7 | require 'mocks/var_models_mock' |
6 | -require 'Var' | ||
7 | 8 | ||
8 | -ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:") | 9 | +ActiveRecord::Base.establish_connection(adapter: 'sqlite3', |
10 | + database: ':memory:') | ||
9 | ActiveRecord::Schema.verbose = false | 11 | ActiveRecord::Schema.verbose = false |
10 | VarDatabaseMock.setup_db | 12 | VarDatabaseMock.setup_db | ... | ... |
... | @@ -2,15 +2,129 @@ require 'spec_helper' | ... | @@ -2,15 +2,129 @@ require 'spec_helper' |
2 | 2 | ||
3 | describe Var do | 3 | describe Var do |
4 | context 'as a class' do | 4 | context 'as a class' do |
5 | - it { is_expected.to respond_to(:valid_services) } | ||
6 | it { is_expected.to respond_to(:var_classes) } | 5 | it { is_expected.to respond_to(:var_classes) } |
7 | it { is_expected.to respond_to(:add_var_class) } | 6 | it { is_expected.to respond_to(:add_var_class) } |
8 | it { is_expected.to respond_to(:create_charge) } | 7 | it { is_expected.to respond_to(:create_charge) } |
9 | it { is_expected.to respond_to(:conekta_webhook) } | 8 | it { is_expected.to respond_to(:conekta_webhook) } |
10 | it { is_expected.to respond_to(:find_charge) } | 9 | it { is_expected.to respond_to(:find_charge) } |
10 | + end | ||
11 | + | ||
12 | + it 'supports conekta' do | ||
13 | + expect(Var.send(:supported_service?, :conekta)).to be true | ||
14 | + end | ||
15 | + | ||
16 | + it 'holds var classes' do | ||
17 | + expect(Var.var_classes).to eq([Product]) | ||
18 | + class Dummy < ActiveRecord::Base | ||
19 | + acts_as_chargeable | ||
20 | + end | ||
21 | + expect(Var.var_classes).to eq([Product, Dummy]) | ||
22 | + end | ||
23 | + | ||
24 | + context 'when creating a charge' do | ||
25 | + it 'is delegates the call' do | ||
26 | + product = instance_double('Product') | ||
27 | + allow(product).to receive(:charge_with).and_return(:success) | ||
28 | + charge = Var.create_charge(:conekta, product, {}) | ||
29 | + expect(charge).to eq :success | ||
30 | + end | ||
31 | + | ||
32 | + it 'raises an error if service is not supported' do | ||
33 | + product = instance_double('Product') | ||
34 | + expect do | ||
35 | + Var.create_charge(:random_payment_service, product, {}) | ||
36 | + end.to raise_error 'Service is not supported' | ||
37 | + end | ||
38 | + | ||
39 | + it 'raises an error if object cannot be chargable' do | ||
40 | + product = instance_double('Product') | ||
41 | + expect do | ||
42 | + Var.create_charge(:conekta, product, {}) | ||
43 | + end.to raise_error "#{product.class} doesn't support charges" | ||
44 | + end | ||
45 | + end | ||
46 | + | ||
47 | + context 'when receiving a webhook from conekta' do | ||
48 | + | ||
49 | + let!(:chargable_product) do | ||
50 | + Product.new # Weird hack to enable connection | ||
51 | + instance_double('Product') | ||
52 | + end | ||
53 | + | ||
54 | + it 'handles Cargo creado con tarjeta' do | ||
55 | + params = {"data":{"object":{"id":"5511d4ce2412294cf6000081","livemode":false,"created_at":1427231950,"status":"pending_payment","currency":"MXN","description":"Stogies","reference_id":"9839-wolf_pack","failure_code":nil,"failure_message":nil,"monthly_installments":nil,"object":"charge","amount":20000,"paid_at":nil,"fee":963,"customer_id":"","refunds":[],"payment_method":{"name":"Jorge Lopez","exp_month":"12","exp_year":"19","auth_code":nil,"object":"card_payment","last4":"4242","brand":"visa"},"details":{"name":nil,"phone":nil,"email":nil,"line_items":[]}},"previous_attributes":{}},"livemode":false,"webhook_status":"pending","id":"5511d4ce2412294cf6000084","object":"event","type":"charge.created","created_at":1427231950,"webhook_logs":[{"id":"webhl_nPzGMBeQmMUu7aQ","url":"http://requestb.in/1em0jsx1","failed_attempts":0,"last_http_response_status":-1,"object":"webhook_log","last_attempted_at":0}]} | ||
56 | + | ||
57 | + allow(Var).to receive(:find_charge).and_return chargable_product | ||
58 | + allow(chargable_product).to receive(:update_columns).and_return true | ||
59 | + allow(chargable_product).to receive(:var_payed?).and_return false | ||
60 | + allow(chargable_product).to receive(:var_id).and_return '5511d4ce2412294cf6000081' | ||
61 | + | ||
62 | + result = Var.conekta_webhook params | ||
63 | + expect(result.var_id).to eq('5511d4ce2412294cf6000081') | ||
64 | + | ||
65 | + # TODO: Define what is actually being teted | ||
66 | + | ||
67 | + pending | ||
68 | + end | ||
69 | + | ||
70 | + it 'handles Cargo pagado con tarjeta' do | ||
71 | + pending | ||
72 | + end | ||
73 | + | ||
74 | + it 'handles Cargo de OXXO creado' do | ||
75 | + pending | ||
76 | + end | ||
77 | + | ||
78 | + it 'handles Cargo de OXXO pagado' do | ||
79 | + pending | ||
80 | + end | ||
81 | + | ||
82 | + xit 'handles Cargo de SPEI creado' do | ||
83 | + pending | ||
84 | + end | ||
85 | + | ||
86 | + xit 'handles Cargo de SPEI pagado' do | ||
87 | + pending | ||
88 | + end | ||
89 | + | ||
90 | + xit 'handles Plan creado' do | ||
91 | + pending | ||
92 | + end | ||
93 | + | ||
94 | + xit 'handles Crear un customer sin tarjeta y sin plan' do | ||
95 | + pending | ||
96 | + end | ||
97 | + | ||
98 | + xit 'handles Customer creado con una tarjeta y sin plan' do | ||
99 | + pending | ||
100 | + end | ||
101 | + | ||
102 | + xit 'handles Customer creado con tarjeta y con plan (suscripción)' do | ||
103 | + pending | ||
104 | + end | ||
105 | + | ||
106 | + xit 'handles Suscripción creada' do | ||
107 | + pending | ||
108 | + end | ||
109 | + | ||
110 | + xit 'handles Suscripción pagada' do | ||
111 | + pending | ||
112 | + end | ||
113 | + | ||
114 | + xit 'handles Suscripción activa' do | ||
115 | + pending | ||
116 | + end | ||
117 | + | ||
118 | + xit 'handles Contracargo creado' do | ||
119 | + pending | ||
120 | + end | ||
121 | + | ||
122 | + xit 'handles Contracargo ganado' do | ||
123 | + pending | ||
124 | + end | ||
11 | 125 | ||
12 | - it 'returns conekta as a valid service' do | 126 | + xit 'handles Contracargo perdido' do |
13 | - expect(Var.valid_services).to eq([:conekta]) | 127 | + pending |
14 | end | 128 | end |
15 | end | 129 | end |
16 | end | 130 | end | ... | ... |
... | @@ -5,7 +5,7 @@ require 'var/version' | ... | @@ -5,7 +5,7 @@ require 'var/version' |
5 | Gem::Specification.new do |spec| | 5 | Gem::Specification.new do |spec| |
6 | spec.name = 'var' | 6 | spec.name = 'var' |
7 | spec.version = Var::VERSION | 7 | spec.version = Var::VERSION |
8 | - spec.authors = ['abrahamrq', 'chelord', 'rgp'] | 8 | + spec.authors = %w(abrahamrq chelord rgp) |
9 | spec.email = ['abraham.rq03@gmail.com'] | 9 | spec.email = ['abraham.rq03@gmail.com'] |
10 | 10 | ||
11 | spec.summary = 'Payment gateway for Conekta, Paypal' | 11 | spec.summary = 'Payment gateway for Conekta, Paypal' |
... | @@ -17,7 +17,7 @@ Gem::Specification.new do |spec| | ... | @@ -17,7 +17,7 @@ Gem::Specification.new do |spec| |
17 | if spec.respond_to?(:metadata) | 17 | if spec.respond_to?(:metadata) |
18 | spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'" | 18 | spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'" |
19 | else | 19 | else |
20 | - fail 'RubyGems 2.0+ is required to protect against public gem pushes.' | 20 | + raise 'RubyGems 2.0+ is required to protect against public gem pushes.' |
21 | end | 21 | end |
22 | 22 | ||
23 | spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } | 23 | spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } |
... | @@ -28,15 +28,15 @@ Gem::Specification.new do |spec| | ... | @@ -28,15 +28,15 @@ Gem::Specification.new do |spec| |
28 | spec.add_dependency 'conekta', '~> 0.5' | 28 | spec.add_dependency 'conekta', '~> 0.5' |
29 | spec.add_dependency 'paypal-sdk-rest' | 29 | spec.add_dependency 'paypal-sdk-rest' |
30 | spec.add_dependency 'activerecord', '>= 4.0', '< 5.1' | 30 | spec.add_dependency 'activerecord', '>= 4.0', '< 5.1' |
31 | - spec.add_dependency "activesupport" | 31 | + spec.add_dependency 'activesupport' |
32 | spec.add_development_dependency 'bundler', '~> 1.10.a' | 32 | spec.add_development_dependency 'bundler', '~> 1.10.a' |
33 | spec.add_development_dependency 'rake', '~> 10.0' | 33 | spec.add_development_dependency 'rake', '~> 10.0' |
34 | 34 | ||
35 | - spec.add_development_dependency "rspec" | 35 | + spec.add_development_dependency 'rspec' |
36 | - spec.add_development_dependency "rspec-nc" | 36 | + spec.add_development_dependency 'rspec-nc' |
37 | - spec.add_development_dependency "guard" | 37 | + spec.add_development_dependency 'guard' |
38 | - spec.add_development_dependency "guard-rspec" | 38 | + spec.add_development_dependency 'guard-rspec' |
39 | - spec.add_development_dependency "pry" | 39 | + spec.add_development_dependency 'pry' |
40 | - spec.add_development_dependency "pry-remote" | 40 | + spec.add_development_dependency 'pry-remote' |
41 | - spec.add_development_dependency "pry-nav" | 41 | + spec.add_development_dependency 'pry-nav' |
42 | end | 42 | end | ... | ... |
-
Please register or login to post a comment