Giter VIP home page Giter VIP logo

mercadopago's Introduction

MercadoPago Gem

Developed by Kauplus. Maintained by OmbuLabs.

This is a Ruby client for all the services offered by MercadoPago.

You should read the MercadoPago API documentation before you use this gem. This gem works with hashes and only deals with requests/responses. That's why you will need an understanding of their services.

You can read the documentation of the MercadoPago API here:

Installation

mercadopago 2.3.0 needs Ruby >= 2.0.0. Ruby 1.9.3 does not support TLS v1.2, which is required by MercadoPago starting June 30th 2018.

To install the last version of the gem:

gem install mercadopago

If you are using bundler, add this to your Gemfile:

gem 'mercadopago'

Access Credentials

To use this gem, you will need the client_id and client_secret for a MercadoPago account.

In any case, this gem will not store this information. In order to find out your MercadoPago credentials, you can go here:

How to use

Client creation

The first thing to do is create a client. The client will authenticate with MercadoPago and will allow you to interact with the MercadoPago API.

# Use your credentials
client_id = '1234'
client_secret = 'abcdefghijklmnopqrstuvwxyz'

mp_client = MercadoPago::Client.new(client_id, client_secret)

If any error occurred while authenticating with MercadoPago, an AccessError will be raised. If nothing goes wrong, no errors are raised and you are ready to use the API.

Payment Creation

Your request will need a hash to explain what the payment is for. For example:

data = {
  external_reference: "OPERATION-ID-1234",
  items: [
    {
      id:           "Código 123",
      title:        "Example T-Shirt",
      description:  "Red XL T-Shirt",
      quantity:     1,
      unit_price:   10.50,
      currency_id:  "BRL",
      picture_url:  "http://www.site.com/image/123.png"
    }
  ],
  payer: {
    name:     "John",
    surname:  "Mikel",
    email:    "[email protected]"
  },
  back_urls: {
    pending: "https://www.site.com/pending",
    success: "http://www.site.com/success",
    failure: "http://www.site.com/failure"
  }
}

payment = mp_client.create_preference(data)

If everything worked out alright, you will get a response like this:

{
  "payment_methods"    => {},
  "init_point"         => "https://www.mercadopago.com/mlb/checkout/pay?pref_id=abcdefgh-9999-9999-ab99-999999999999",
  "sandbox_init_point" => "https://sandbox.mercadopago.com/mlb/checkout/pay?pref_id=abcdefgh-9999-9999-ab99-999999999999",
  "collector_id"       => 123456789,
  "back_urls" => {
    "pending"=> "https://www.site.com/pending",
    "success"=> "http://www.site.com/success",
    "failure"=> "http://www.site.com/failure"
  },
  "sponsor_id" => nil,
  "expiration_date_from"  => nil,
  "additional_info"       => "",
  "marketplace_fee"       => 0,
  "date_created"          => "2012-05-07T20:07:52.293-04:00",
  "subscription_plan_id"  => nil,
  "id"                    => "abcdefgh-9999-9999-ab99-999999999999",
  "expiration_date_to"    => nil,
  "expires"               => false,
  "external_reference"    => "OPERATION-ID-1234",
  "payer" => {
    "email"   => "[email protected]",
    "name"    => "John",
    "surname" => "Mikel"
  },
  "items" => [
    {
      "id"          => "Código 123",
      "currency_id" => "BRL",
      "title"       => "Example T-Shirt",
      "description" => "Red XL T-Shirt",
      "picture_url" => "http://www.site.com.br/image/123.png",
      "quantity"    => 1,
      "unit_price"  => 10.50
    }
  ],
  "client_id"   => "963",
  "marketplace" => "NONE"
}

Payment Status Verification

To check the payment status you will need the payment ID. Only then you can call the MercadoPago IPN.

# Use the payment ID received on the IPN.
payment_id = '987654321'

notification = mp_client.notification(payment_id)

You will get a response like this one:

{
  "collection" => {
    "id"                  => 987654321,
    "site_id"             => "MLB",
    "operation_type"      => "regular_payment",
    "order_id"            => nil,
    "external_reference"  => "OPERATION-ID-1234",
    "status"              => "approved",
    "status_detail"       => "approved",
    "payment_type"        => "credit_card",
    "date_created"        => "2012-05-05T14:22:43Z",
    "last_modified"       => "2012-05-05T14:35:13Z",
    "date_approved"       => "2012-05-05T14:22:43Z",
    "money_release_date"  => "2012-05-19T14:22:43Z",
    "currency_id"         => "BRL",
    "transaction_amount"  => 10.50,
    "shipping_cost"       => 0,
    "total_paid_amount"   => 10.50,
    "finance_charge"      => 0,
    "net_received_amount" => 0,
    "marketplace"         => "NONE",
    "marketplace_fee"     => nil,
    "reason"              => "Example T-Shirt",
    "payer" => {
      "id"          => 543219876,
      "first_name"  => "John",
      "last_name"   => "Mikel",
      "nickname"    => "JOHNMIKEL",
      "phone" => {
        "area_code" => nil,
        "number"    => "551122334455",
        "extension" => nil
      },
      "email" => "[email protected]",
      "identification" => {
        "type"    => nil,
        "number"  => nil
      }
    },
    "collector" => {
      "id"          => 123456789,
      "first_name"  => "Bill",
      "last_name"   => "Receiver",
      "phone" => {
        "area_code" => nil,
        "number"    => "1122334455",
        "extension" => nil
      },
      "email"     => "[email protected]",
      "nickname"  => "BILLRECEIVER"
    }
  }
}

Search in the collections

To search over the collections (payments that you may be processing) you need to create a hash with the params that you want to search for an send it to the search method of the client instance.

# Create a hash to search for
search_hash = { external_reference: 'OPERATION-ID-1234' }

search = mp_client.search(search_hash)

You will get a response like this one:

{
  "results"=>[
    {
      "collection" => {
        "marketplace"   =>"NONE",
        "sponsor_id"    =>nil,
        "status"        => "approved",
        "status_detail" => "approved",
        "payer" => {
          "id"          => 543219876,
          "first_name"  => "John",
          "last_name"   => "Mikel",
          "nickname"    => "JOHNMIKEL",
          "phone" => {
            "area_code" => nil,
            "number"    => "551122334455",
            "extension" => nil
          },
          "email" => "[email protected]",
          "identification" => {
            "type"    => nil,
            "number"  => nil
          }
        },
        "currency_id"         => "BRL",
        "external_reference"  => "OPERATION-ID-1234",
        "transaction_amount"  => 10.50,
        "shipping_cost"       => 0,
        "total_paid_amount"   => 10.50,
        "id"                  => 987654321,
        "status_code"         => nil,
        "reason"              => "Example T-Shirt",
        "collector_id"        => 99678614,
        "date_created"        => "2012-05-05T14:22:43Z",
        "last_modified"       => "2012-05-05T14:35:13Z",
        "date_approved"       => "2012-05-05T14:22:43Z",
        "money_release_date"  => "2012-05-19T14:22:43Z",
        "released"            => "yes",
        "operation_type"      => "regular_payment",
        "payment_type"        => "credit_card",
        "site_id"             => "MLB"
      }
    }
  ],
  "paging" => {
    "total"   => 1,
    "limit"   => 30,
    "offset"  => 0
  }
}

And the parameters that could be used in the search hash are:

id: Payment identifier
site_id: Country identifier: Argentina: MLA; Brasil: MLB.
date_created: Creation date. Ej: range=date_created&begin_date=NOW-1DAYS&end_date=NOW (Ver ISO-8601).
date_approved: Approval date. Ej: range=date_approved&begin_date=NOW-1DAYS&end_date=NOW (Ver ISO-8601).
last_modified: Last modified date. Ej: range=last_modified&begin_date=NOW-1DAYS&end_date=NOW (Ver ISO-8601).
money_release_date: Date of the payment's release. Ej: range=money_release_date&begin_date=NOW-1DAYS&end_date=NOW (Ver ISO-8601).
payer_id: Buyer's identifier.
reason: Description of what's being paid.
transaction_amount: Amount of the transaction.
currency_id: Currency type. Argentina: ARS (peso argentino); USD (Dólar estadounidense); Brasil: BRL (Real).
external_reference: Field used by the seller as aditional reference.
mercadopago_fee: MercadoPago's comission fee.
net_received_amount: Amount payable to the seller without mercadopago_fee.
total_paid_amount: Obtained by adding: transaction_amount, shipping_cost and the amount paid by the buyer (including credit card's financing).
shipping_cost: Shipping cost.
status:
    pending: The payment process is incomplete.
    approved: The payment has been credited.
    in_process: The payment is under review.
    rejected: The payment has been rejected.
    cancelled: The payment is canceled after timeout or by either party.
    refunded: The payment has been refunded.
    in_mediation: The payment is in dispute.
status_detail: Payment status detail.
released: When the amount is available or not. Possible values are yes or no.
operation_type:
    regular_payment: A payment.
    money_transfer: A money wire.
    recurring_payment: Active subscription recurring payment.
    subscription_payment: Subscription fee.

Auto Pagination

It is also possible to inform if whether or not the result should be automatically paginated to return all payments. By default MercadoPago return only 30 payments on each request and if you setting up auto_paginate to true, will be made as many requests as needed to return all payments that matches with your search.

# Create a hash to search for
search_hash = { external_reference: 'OPERATION-ID-1234' }

# setup the auto_paginate to true
mp_client.auto_paginate = true

# do the desired search
search = mp_client.search(search_hash)

Sandbox mode

The sandbox mode can be enabled/disabled as follows:

mp_client.sandbox_mode(true)  # Enables sandbox
mp_client.sandbox_mode(false) # Disables sandbox

Recurring Payment Creation

Your request will need a hash to explain what the recurring payment is for. For example:

data = {
  payer_email:        "[email protected]",
  back_url:           "http://www.site.com/return",
  reason:             "Monthly Magazine",
  external_reference: "OPERATION-ID-1234",
  auto_recurring: {
    frequency:          1,
    frequency_type:     "months",
    transaction_amount: 12.55,
    currency_id:        "BRL"
  }
}

If everything worked out alright, you will get a response like this:

{
   "id"                 => "f8ad8asd8asd98asd89add980",
   "payer_id"           => 131231333,
   "payer_email"        => "[email protected]",
   "back_url"           => "http://www.site.com/return",
   "collector_id"       => 3131231231,
   "application_id"     => 83818921839,
   "status"             => "authorized",
   "reason"             => "Monthly Magazine",
   "external_reference" => "OPERATION-ID-1234",
   "date_created"       => "2014-08-03T20:47:53.970-04:00",
   "last_modified"      => "2014-08-03T20:51:00.264-04:00",
   "init_point"         => "https://www.mercadopago.com/mlb/debits/new?preapproval_id=8ad8asd8ada8da8dad88sa",
   "auto_recurring" => {
    "frequency"          => 1,
    "frequency_type"     => "months",
    "transaction_amount" => 12.55,
    "currency_id"        => "BRL"
   }
}

Recurring Payment Status Verification Next Recurring Payments by IPN

To check the recurring payment status you will need the preapproval ID next recurring payments. Only then you can call the MercadoPago IPN.

# Use the preapproval ID received on the IPN.
preapproval_id = '987654321'

notification = mp_client.notification_authorized(preapproval_id)

You will get a response like this one:

Status code: 200 OK

{
    "preapproval_id":     "preapproval_id",
    "id":                 "authorized_payment_id",
    "type":               "online",
    "status":             "processed",
    "date_created":       "2014-05-22T11:53:37.074-04:00",
    "last_modified":      "2014-05-22T11:53:37.074-04:00",
    "transaction_amount": 150,
    "currency_id":        "BRL",
    "payment":
    {
        "id":            "payment_id",
        "status":        "approved",
        "status_detail": "accredited"
    }
}

Recurring Payment Status Verification by IPN

To check the recurring payment status you will need the preapproval ID. Only then you can call the MercadoPago IPN.

# Use the preapproval ID received on the IPN.
preapproval_id = '987654321'

notification = mp_client.notification_preapproval(preapproval_id)

You will get a response like this one:

Status code: 200 OK

{
  "id":                 "preapproval_id",
  "payer_id":           12345,
  "payer_email":        "[email protected]",
  "back_url":           "https://www.mysite.com/afterAuth",
  "collector_id":       12345,
  "application_id":     10648,
  "status":             "authorized",
  "init_point":         "https://www.mercadopago.com/mlb/debits/new?preapproval_id=preapproval_id",
  "sandbox_init_point": "https://www.mercadopago.com/mlb/debits/new?preapproval_id=preapproval_id",
  "external_reference": "OP-1234",
  "reason":             "Detailed description about your service",
  "auto_recurring": {
    "frequency":          1,
    "frequency_type":     "months",
    "transaction_amount": 60,
    "currency_id":        "BRL"
  },
  "date_created":  "2012-08-31T11:50:26.648-04:00",
  "last_modified": "2012-08-31T11:50:26.648-04:00"
}

Recurring Payment Cancellation

To cancel a recurring payment you will need the preapproval ID.

# Use the preapproval ID received on the IPN.
preapproval_id = '987654321'

cancellation = mp_client.cancel_preapproval_payment(preapproval_id)

You will get a response like this one:

Status code: 200 OK

{
  "id":                 "preapproval_id",
  "payer_id":           12345,
  "payer_email":        "[email protected]",
  "back_url":           "https://www.mysite.com/afterAuth",
  "collector_id":       12345,
  "application_id":     10648,
  "status":             "cancelled",
  "reason":             "reason text",
  "external_reference": "OP-1234",
  "date_created":  "2012-08-31T11:50:26.648-04:00",
  "last_modified": "2012-08-31T11:50:26.648-04:00",
  "auto_recurring": {
    "frequency":          1,
    "frequency_type":     "months",
    "transaction_amount": 60,
    "currency_id":        "BRL"
  }
}

Errors

Errors will also be hashes with status code, message and error key.

For example, if you request payment method status for an invalid operation, you will see something like this:

{
 "message"  => "Resource not found",
 "error"    => "not_found",
 "status"   => 404,
 "cause"    => []
}

Tests

This gem has tests for a few methods. To check if it is working properly, just run:

rake test

Changelog

2.3.0 (thanks Miguelcldn, etagwerker, schmierkov and mauro-oto)

  • Added ability for client to perform custom GET and POST requests.
  • Added cancel recurring payments endpoint.
  • Better code style + DRYer code.
  • Added VCR gem for tests.
  • Documentation fixes.

2.2.0 (thanks gulymaestro)

Added support to the sandbox mode.

2.1.0 (thanks jamessonfaria)

Added functionality to create and get recurring payments. Also added support for recurring payments notification.

2.0.2

Request uses Faraday HTTP client instead of RestClient for better SSL support.

2.0.1

Added the refresh_access_token method to the authentication module.

2.0.0 (thanks leanucci and cavi21)

Implemented basic access to the collection search method. Changed the test credentials. Using Ruby 1.9 hash format. Added documentation for collection search.

1.0.2

Changed documentation according to the new client intercace, added a notification method to the client and added a new test.

1.0.1 (thanks etagwerker)

Added client interface, renamed "Mercadopago" to "MercadoPago", translated project summary to English and added tests for a few methods.

0.0.1

First release. It's possible to authenticate with the MercadoPago APIs, create payments and check payment status.

Copyright

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

mercadopago's People

Contributors

barbolo avatar cleicar avatar emilystorch avatar etagwerker avatar gulymaestro avatar jamessonfaria avatar mauro-oto avatar miguelcldn avatar rafaelivan avatar sirkosi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mercadopago's Issues

Problems with authentication?

I haven't been able to log in for the last couple of days.
It seems the problem is that refresh_token is taken as mandatory, but oauth is not returning it (copied the responde below).

Are you aware of the problem? Planning to solve it?

{"access_token":"XXXX","live_mode":true,"user_id":xxxxx,"token_type":"bearer","expires_in":21600,"scope":"offline_access payments read write"}%

Redirecting to make payment

Hi, I'm implementing the API using PHP and modal mode. I want to know if this is the right way to redirect the page to back_url after making the payment.

JavaScript onreturn:

<script type="text/javascript">
    function checkoutReturn(json){
        if( json.back_url != null && json.collection_id != null  ){
            var url = json.back_url + '?id='+json.collection_id
            window.top.location = url;
            console.log('collection_id: '+json.collection_id);
            console.log('preference_id: '+json.preference_id);
        }
        else{
            console.log('Ventana de mercado pago cerrada');
        }
    }
</script>

HTML:

<a href="https://www.mercadopago.com/checkout/pay?pref_id=<?php echo $d['identificador_de_la_preferencia']; ?>" name="MP-Checkout" class="btn btn_pagar_con_opcion" mp-mode="modal" onreturn="checkoutReturn">&nbsp;</a>

PHP

$mp = new MP("XXXXX", "XXXXX");
$productos = array();
$redireccionamientos = new stdClass();
$redireccionamientos->success = "https://www.mysite.com/caja/terminar/MercadoPagoSuccess.php";
$redireccionamientos->failure = "https://www.mysite.com/caja/terminar/MercadoPagoFailure.php";
$redireccionamientos->pending = "https://www.mysite.com/caja/terminar/MercadoPagoPending.php";
foreach( $_SESSION['carrito']['productos'] as $producto ){
    $producto_datos = Modelos_Productos::obtenerProducto(SISTEMA_TIENDA_PAIS, SISTEMA_ID_TIENDA, $producto['id']);
    $fila = new stdClass();
    $fila->id           =   $producto['id'];
    $fila->title        =   $producto['nombre'];
    if( !empty( $producto_datos['descripcion'] ) ){
        $fila->description  =   util_eliminar_html(util_preparar_var($producto_datos['descripcion'],'html_limpio'));
    }
    $fila->quantity     =   $producto['cantidad'];
    $fila->unit_price   =   5; //$producto['precio_venta'];
    $fila->currency_id  =   "MXN";
    //$fila->picture_url  =   "http://imgs.cdn.com/?tp=p&amp;id=".$producto['id']."&amp;t=340x260";
    array_push($productos, $fila);
}

$player = new stdClass();
$player->name = $_SESSION['cliente']['nombre'];
$player->surname = $_SESSION['cliente']['nombre_completo'];
$player->email = $_SESSION['cliente']['email'];
$exclusiones_tipos_pago = array();
$payment_methods = new stdClass();
//array_push( $exclusiones_tipos_pago, array("id"=>"debit_card") );
//array_push( $exclusiones_tipos_pago, array("id"=>"credit_card") );
array_push( $exclusiones_tipos_pago, array("id"=>"ticket") );
array_push( $exclusiones_tipos_pago, array("id"=>"atm") );
$payment_methods->excluded_payment_types = $exclusiones_tipos_pago;
$datos = array (
    "items" => $productos,
    "payer"=> $player,
    "payment_methods" => $payment_methods
);
$resultado = $mp->create_preference($datos);

Authentication related tests are failing

Hi,

Just ran the test suite and the following cases failed:

  • test_that_authentication_fails_with_wrong_parameters
  • test_that_request_fails_with_wrong_token
  • test_that_refresh_token_works

It seems that the MercadoPago API error handling has changed. For example, on the access token refresh test, the API now responds with a 400, saying that the user "has not grant for application" (which is kind of weird).

Should I update the tests to reflect these new error responses?

Thanks.

Release v2.2.1 or v2.3.0

  • Update README with changes between v2.2.0 and master
  • Git tag new version and update Github
  • gem build + gem push

Add ability to auto paginate results

I was requesting a collection of payments and didn't realize there were more payments that I could fetch via pagination params (limit and offset).

Similar to what https://github.com/octokit/octokit.rb#pagination provides, we could have an auto_paginate attribute on either the MercadoPago module or the MercadoPago::Collection class which auto paginates the results and returns all of them instead of providing a response with pagination attributes.

Make the collection module to be an Enumerable

We changed the behavior of the search method in PR #43 to allow to paginate the results, but we realized that this module isn't efficient.

To solve this issue would be great if we turn the module into a Enumerable that can lazily load all the records.

IPN on Sandbox mode

Hi guys, I was wondering if your gem can be used in sandbox mode when I'm doing a GET request with my purchase ID to the IPN system.

Because when I'm excuting mp.notification(@payment_id), I get {"message"=>"Resource XXXXXXX not found", "error"=>"not_found", "status"=>404, "cause"=>[]} as response, but when I do the request manually pointing to https://api.mercadolibre.com/sandbox/collections/notifications/XXXXXXX' everything works as expected. (notice the /sandbox/)

Thanks!

Add VCR to tests

We should make sure that the tests use recorded responses from Mercado Pago.

How to use it?

I have no idea how to use the gem :s, where must I have to put this code???

Use your credentials

client_id = '1234'
client_secret = 'abcdefghijklmnopqrstuvwxyz'

mp_client = MercadoPago::Client.new(client_id, client_secret)

And how can I send the Post request?

Security Issue JSON

What chance do we have to update the JSON gem? Since it presents a security problem.

Name: json
Version: 1.8.6
CVE: CVE-2020-10663
GHSA: GHSA-jphg-qwrw-7w9g
Criticality: High
URL: https://www.ruby-lang.org/en/news/2020/03/19/json-dos-cve-2020-10663/
Title: json Gem for Ruby Unsafe Object Creation Vulnerability (additional fix)
Solution: upgrade to '>= 2.3.0'

Problems with connection with SSL

client_id = xxxxxx
client_secret = xxxxxxx

mp_client = MercadoPago::Client.new(client_id, client_secret)

NoMethodError: undefined method `response' for #<Errno::ECONNRESET: Connection reset by peer - SSL_connect>

I've tried with the following versions:

ruby-1.9.3-p448
ruby-2.0.0-p247

Also cloned the repo and all tests fail on those versions.

I've tried on a STAGING server and didn't had that problem.

Authentication error

My mistake begins very early, mp_client = MercadoPago::Client.new(client_id, client_secret) i enter my clien_id and my client_secret but it's returned a 500 error.

PS: I'm working on a ruby on rails app.

gemspec warnings on `gem build`

We should add versions to the gems in the gemspec file:

WARNING:  open-ended dependency on json (>= 1.4.6) is not recommended
  if json is semantically versioned, use:
    add_runtime_dependency 'json', '~> 1.4', '>= 1.4.6'
WARNING:  open-ended dependency on faraday (>= 0.9.0) is not recommended
  if faraday is semantically versioned, use:
    add_runtime_dependency 'faraday', '~> 0.9', '>= 0.9.0'
WARNING:  open-ended dependency on pry (>= 0, development) is not recommended
  if pry is semantically versioned, use:
    add_development_dependency 'pry', '~> 0'
WARNING:  open-ended dependency on rake (>= 0, development) is not recommended
  if rake is semantically versioned, use:
    add_development_dependency 'rake', '~> 0'
WARNING:  open-ended dependency on byebug (>= 0, development) is not recommended
  if byebug is semantically versioned, use:
    add_development_dependency 'byebug', '~> 0'
WARNING:  open-ended dependency on test-unit (>= 0, development) is not recommended
  if test-unit is semantically versioned, use:
    add_development_dependency 'test-unit', '~> 0'
WARNING:  open-ended dependency on vcr (>= 0, development) is not recommended
  if vcr is semantically versioned, use:
    add_development_dependency 'vcr', '~> 0'
WARNING:  open-ended dependency on webmock (>= 0, development) is not recommended
  if webmock is semantically versioned, use:
    add_development_dependency 'webmock', '~> 0'

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.