diff --git a/.qlty/.gitignore b/.qlty/.gitignore new file mode 100644 index 0000000..3036618 --- /dev/null +++ b/.qlty/.gitignore @@ -0,0 +1,7 @@ +* +!configs +!configs/** +!hooks +!hooks/** +!qlty.toml +!.gitignore diff --git a/.qlty/configs/.standard.yml b/.qlty/configs/.standard.yml new file mode 100644 index 0000000..7cbd2f0 --- /dev/null +++ b/.qlty/configs/.standard.yml @@ -0,0 +1,5 @@ +ignore: + - "**/*": + - Style/StringLiterals # Use single quotes for strings + - Layout/MultilineMethodCallIndentation # Indentation of multiline method calls + - Layout/SpaceInsideHashLiteralBraces # Allow space inside hash literal braces diff --git a/.qlty/configs/.yamllint.yaml b/.qlty/configs/.yamllint.yaml new file mode 100644 index 0000000..d22fa77 --- /dev/null +++ b/.qlty/configs/.yamllint.yaml @@ -0,0 +1,8 @@ +rules: + document-start: disable + quoted-strings: + required: only-when-needed + extra-allowed: ["{|}"] + key-duplicates: {} + octal-values: + forbid-implicit-octal: true diff --git a/.qlty/qlty.toml b/.qlty/qlty.toml new file mode 100644 index 0000000..1d845d8 --- /dev/null +++ b/.qlty/qlty.toml @@ -0,0 +1,101 @@ +# This file was automatically generated by `qlty init`. +# You can modify it to suit your needs. +# We recommend you to commit this file to your repository. +# +# This configuration is used by both Qlty CLI and Qlty Cloud. +# +# Qlty CLI -- Code quality toolkit for developers +# Qlty Cloud -- Fully automated Code Health Platform +# +# Try Qlty Cloud: https://qlty.sh +# +# For a guide to configuration, visit https://qlty.sh/d/config +# Or for a full reference, visit https://qlty.sh/d/qlty-toml +config_version = "0" + +exclude_patterns = [ + "*_min.*", + "*-min.*", + "*.min.*", + "**/.yarn/**", + "**/*.d.ts", + "**/assets/**", + "**/bower_components/**", + "**/build/**", + "**/cache/**", + "**/config/**", + "**/db/**", + "**/deps/**", + "**/dist/**", + "**/extern/**", + "**/external/**", + "**/generated/**", + "**/Godeps/**", + "**/gradlew/**", + "**/mvnw/**", + "**/node_modules/**", + "**/protos/**", + "**/seed/**", + "**/target/**", + "**/templates/**", + "**/testdata/**", + "**/vendor/**", +] + +test_patterns = [ + "**/test/**", + "**/spec/**", + "**/*.test.*", + "**/*.spec.*", + "**/*_test.*", + "**/*_spec.*", + "**/test_*.*", + "**/spec_*.*", +] + +[smells] +mode = "comment" + +[[source]] +name = "default" +default = true + + +[[plugin]] +name = "actionlint" + +[[plugin]] +name = "checkov" + +[[plugin]] +name = "markdownlint" +mode = "comment" + +[[plugin]] +name = "osv-scanner" + +[[plugin]] +name = "prettier" + +[[plugin]] +name = "ripgrep" +mode = "comment" + +[[plugin]] +name = "rubocop" + +[[plugin]] +name = "standardrb" + +[[plugin]] +name = "trivy" +drivers = [ + "config", + "fs-vuln", +] + +[[plugin]] +name = "trufflehog" + +[[plugin]] +name = "yamllint" diff --git a/.standard.yml b/.standard.yml deleted file mode 100644 index 3a0787a..0000000 --- a/.standard.yml +++ /dev/null @@ -1,3 +0,0 @@ -# For available configuration options, see: -# https://github.com/testdouble/standard -ruby_version: 2.6 diff --git a/CHANGELOG.md b/CHANGELOG.md index fd8c893..6ff971a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ ## [Unreleased] +## [0.2.0] - 2025-06-27 + +- Added contacts and payment API calls +- Improved configuration and specifications + ## [0.1.0] - 2024-12-12 - Initial release diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..aefd129 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,86 @@ +PATH + remote: . + specs: + ohme (0.2.0) + typhoeus (>= 1.4) + +GEM + remote: https://rubygems.org/ + specs: + ast (2.4.3) + diff-lcs (1.6.1) + ethon (0.16.0) + ffi (>= 1.15.0) + ffi (1.15.5) + json (2.10.2) + language_server-protocol (3.17.0.4) + lint_roller (1.1.0) + parallel (1.26.3) + parser (3.3.7.4) + ast (~> 2.4.1) + racc + prism (1.4.0) + racc (1.8.1) + rainbow (3.1.1) + rake (13.2.1) + regexp_parser (2.10.0) + rexml (3.4.1) + rspec (3.13.0) + rspec-core (~> 3.13.0) + rspec-expectations (~> 3.13.0) + rspec-mocks (~> 3.13.0) + rspec-core (3.13.3) + rspec-support (~> 3.13.0) + rspec-expectations (3.13.3) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-mocks (3.13.2) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-support (3.13.2) + rubocop (1.64.1) + json (~> 2.3) + language_server-protocol (>= 3.17.0) + parallel (~> 1.10) + parser (>= 3.3.0.2) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 1.8, < 3.0) + rexml (>= 3.2.5, < 4.0) + rubocop-ast (>= 1.31.1, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 2.4.0, < 3.0) + rubocop-ast (1.44.0) + parser (>= 3.3.7.2) + prism (~> 1.4) + rubocop-performance (1.21.1) + rubocop (>= 1.48.1, < 2.0) + rubocop-ast (>= 1.31.1, < 2.0) + ruby-progressbar (1.13.0) + standard (1.37.0) + language_server-protocol (~> 3.17.0.2) + lint_roller (~> 1.0) + rubocop (~> 1.64.0) + standard-custom (~> 1.0.0) + standard-performance (~> 1.4) + standard-custom (1.0.2) + lint_roller (~> 1.0) + rubocop (~> 1.50) + standard-performance (1.4.0) + lint_roller (~> 1.1) + rubocop-performance (~> 1.21.0) + typhoeus (1.4.0) + ethon (>= 0.9.0) + unicode-display_width (2.6.0) + +PLATFORMS + x86_64-darwin-20 + x86_64-linux + +DEPENDENCIES + ohme! + rake (~> 13.0) + rspec (~> 3.0) + standard (~> 1.3) + +BUNDLED WITH + 2.3.12 diff --git a/README.md b/README.md index 85bb420..dab91fb 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,46 @@ # Ohme -Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/ohme`. To experiment with that code, run `bin/console` for an interactive prompt. - -TODO: Delete this and the text above, and describe your gem +A Ruby connector for the Ohme API, a tool for integrating with the Ohme CRM platform. This gem simplifies interaction with the Ohme API, allowing developers to easily perform operations such as retrieving data, creating resources, and managing entities within the Ohme ecosystem. ## Installation Install the gem and add to the application's Gemfile by executing: - $ bundle add ohme + bundle add ohme If bundler is not being used to manage dependencies, install the gem by executing: - $ gem install ohme + gem install ohme ## Usage -TODO: Write usage instructions here +### Configuration Initialization + +First, configure the Ohme client with your credentials and settings: + +```ruby +require 'ohme' +require 'json' + +config = Ohme::Configuration.new do |c| + c.client_name = 'your_client_name' + c.client_secret = 'your_client_secret' +end +``` + +Then, initialize the client using your configuration: + +```ruby +client = Ohme::Client.new(config) +``` + +You can now use the API endpoints. For example, to list contacts: + +```ruby +contact_api = Ohme::API::Contact.new(client) +contacts = contact_api.index +puts contacts +``` ## Development @@ -26,7 +50,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To ## Contributing -Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/ohme. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/ohme/blob/main/CODE_OF_CONDUCT.md). +Bug reports and pull requests are welcome on GitHub at . This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/Treize37/ohme/blob/main/CODE_OF_CONDUCT.md). ## License @@ -34,4 +58,4 @@ The gem is available as open source under the terms of the [MIT License](https:/ ## Code of Conduct -Everyone interacting in the Ohme project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/ohme/blob/main/CODE_OF_CONDUCT.md). +Everyone interacting in the Ohme project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/Treize37/ohme/blob/main/CODE_OF_CONDUCT.md). diff --git a/Rakefile b/Rakefile index df40677..d38c45d 100644 --- a/Rakefile +++ b/Rakefile @@ -1,10 +1,10 @@ # frozen_string_literal: true -require "bundler/gem_tasks" -require "rspec/core/rake_task" +require 'bundler/gem_tasks' +require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec) -require "standard/rake" +require 'standard/rake' -task default: %i[spec standard] +task default: %i[spec] diff --git a/lib/ohme.rb b/lib/ohme.rb index 2aaab41..37685be 100644 --- a/lib/ohme.rb +++ b/lib/ohme.rb @@ -1,7 +1,12 @@ # frozen_string_literal: true -require_relative "ohme/version" +require_relative 'ohme/version' +require_relative 'ohme/configuration' +require_relative 'ohme/client' +require_relative 'ohme/api/contact' +require_relative 'ohme/api/payment' +# Ohme API client gem main module. module Ohme class Error < StandardError; end # Your code goes here... diff --git a/lib/ohme/api/contact.rb b/lib/ohme/api/contact.rb new file mode 100644 index 0000000..e5325f2 --- /dev/null +++ b/lib/ohme/api/contact.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +module Ohme + module API + # The Contact class provides methods to interact with the Ohme API's + # contacts endpoint. + # It allows you to list, create, read, update, and delete contacts. + class Contact + # Initializes a new Contact instance with a client. + # + # @param client [Ohme::Client] An instance of the Ohme client to + # make API requests + # @return [Ohme::API::Contact] A new instance of the Contact class + def initialize(client = Ohme::Client.new) + @client = client + end + + # Fetches the list of contacts + # + # @param params [Hash] Optional query parameters + # @return [Hash] The response from the API + def index(params = {}) + @client.get('contacts', params) + end + + # Creates a new contact + # + # @param body [Hash] The contact data to be sent in the request body + # @return [Hash] The response from the API + def create(body) + @client.post('contacts', body) + end + + # Updates a contact by ID + # + # @param id [String] The ID of the contact to update + # @param body [Hash] The contact data to be updated + # @return [Hash] The response from the API + def update(id, body) + @client.put("contacts/#{id}", body) + end + + # Fetches a contact by ID + # + # @param id [String] The ID of the contact to retrieve + # @return [Hash] The response from the API + def show(id) + @client.get("contacts/#{id}") + end + + # Deletes a contact by ID + # + # @param id [String] The ID of the contact to delete + # @return [nil] The response from the API + def delete(id) + @client.delete("contacts/#{id}") + end + end + end +end diff --git a/lib/ohme/api/payment.rb b/lib/ohme/api/payment.rb new file mode 100644 index 0000000..f412f48 --- /dev/null +++ b/lib/ohme/api/payment.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +module Ohme + module API + # The Payment class provides methods to interact with the Ohme API's + # payments endpoint. + # It allows you to list, create, read, update, and delete payments. + class Payment + def initialize(client = Ohme::Client.new) + @client = client + end + + # Fetches the list of payments + # + # @param params [Hash] Optional query parameters + # @return [Hash] The response from the API + def index(params = {}) + @client.get('payments', params) + end + + # Creates a new payment + # + # @param body [Hash] The payment data to be sent in the request body + # @return [Hash] The response from the API + def create(body) + @client.post('payments', body) + end + + # Updates a payment by ID + # + # @param id [String] The ID of the payment to update + # @param body [Hash] The payment data to be updated + # @return [Hash] The response from the API + def update(id, body) + @client.put("payments/#{id}", body) + end + + # Fetches a payment by ID + # + # @param id [String] The ID of the payment to retrieve + # @return [Hash] The response from the API + def show(id) + @client.get("payments/#{id}") + end + + # Deletes a payment by ID + # + # @param id [String] The ID of the payment to delete + # @return [nil] The response from the API + def delete(id) + @client.delete("payments/#{id}") + end + end + end +end diff --git a/lib/ohme/client.rb b/lib/ohme/client.rb new file mode 100644 index 0000000..037d23c --- /dev/null +++ b/lib/ohme/client.rb @@ -0,0 +1,113 @@ +# frozen_string_literal: true + +require 'typhoeus' +require_relative 'configuration' + +module Ohme + # Client for interacting with the Ohme API + class Client + # Initializes the client with the configuration + # + # @param configuration [Ohme::Configuration] The configuration object + # @return [Ohme::Client] A new instance of the Ohme client + def initialize(configuration = Ohme::Configuration.new) + @configuration = configuration + @configuration.validate! + end + + # Performs a GET request + # + # @param endpoint [String] The API endpoint to request + # @param params [Hash] Optional query parameters + # @return [Hash] The response from the API + def get(endpoint, params = {}) + request(:get, endpoint, params: params) + end + + # Performs a POST request + # + # @param endpoint [String] The API endpoint to request + # @param body [Hash] The request body to send + # @return [Hash] The response from the API + def post(endpoint, body = {}) + request(:post, endpoint, body: body) + end + + # Performs a PUT request + # + # @param endpoint [String] The API endpoint to request + # @param body [Hash] The request body to send + # @return [Hash] The response from the API + def put(endpoint, body = {}) + request(:put, endpoint, body: body) + end + + # Performs a DELETE request + # + # @param endpoint [String] The API endpoint to request + # @param params [Hash] Optional query parameters + # @return [nil] The response from the API (nil for DELETE requests) + def delete(endpoint, params = {}) + request(:delete, endpoint, params: params) + end + + private + + # Private: Performs an HTTP request + # + # @param method [Symbol] The HTTP method (get, post, put, delete) + # @param endpoint [String] The API endpoint to request + # @param options [Hash] Optional parameters for the request + # @return [Hash, nil] The parsed response from the API or nil for DELETE + def request(method, endpoint, options = {}) + response = Typhoeus::Request.new( + build_url(endpoint), + method: method, + headers: build_headers, + params: options[:params], + body: options[:body]&.to_json, + timeout: @configuration.timeout + ).run + + handle_response(response) + end + + # Private: Builds the full URL for the API request + # + # @param endpoint [String] The API endpoint to request + # @return [String] The full URL for the request + def build_url(endpoint) + "#{@configuration.base_url}#{@configuration.version}/#{endpoint}" + end + + # Private: Builds the headers for the request + # + # @return [Hash] The headers to be sent with the request + def build_headers + { + 'client-name' => @configuration.client_name, + 'client-secret' => @configuration.client_secret, + 'Content-Type' => 'application/json', + 'Accept' => 'application/json' + } + end + + # Private: Handles the API response + # + # @param response [Typhoeus::Response] The response from the API + # @return [Hash, nil] The parsed response or nil for DELETE requests + def handle_response(response) + if response.timed_out? + raise 'Request timed out. Please check your network connection or increase the timeout.' + elsif response.success? + # Return nil for DELETE requests with no body + return nil if response.body.nil? || response.body.strip.empty? + + # Parse JSON for other successful responses + JSON.parse(response.body) + else + raise "HTTP request failed: #{response.code} - #{response.body}" + end + end + end +end diff --git a/lib/ohme/configuration.rb b/lib/ohme/configuration.rb new file mode 100644 index 0000000..6897ab9 --- /dev/null +++ b/lib/ohme/configuration.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +module Ohme + # Configuration of the Ohme API client gem. + class Configuration + attr_accessor :base_url, :client_name, :client_secret, :timeout, :version + + # Initializes the configuration with default values. + # + # @yield [config] Optional block to configure the client + # @return [Ohme::Configuration] A new instance of the configuration + def initialize + @base_url = 'https://api-ohme.oneheart.fr/api/' + @version = 'v1' + @timeout = 30 + yield self if block_given? + end + + # Configures the Ohme API client with a block. + # + # @yield [config] A block to configure the client + # @return [Ohme::Configuration] The current configuration instance + def configure + yield(self) if block_given? + end + + # Validates the configuration values. + # + # @raise [RuntimeError] if required values are missing + def validate! + error_on('client_name') unless @client_name + error_on('client_secret') unless @client_secret + end + + private + + # Private: Raises an error if a required configuration attribute is missing. + # + # @param attribute [String] The name of the missing attribute + # @raise [RuntimeError] if the attribute is missing + def error_on(attribute) + raise( + "#{attribute} is missing. " \ + "Please configure Ohme::Configuration.#{attribute}." + ) + end + end +end diff --git a/lib/ohme/version.rb b/lib/ohme/version.rb index b4734fe..1dbd82e 100644 --- a/lib/ohme/version.rb +++ b/lib/ohme/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Ohme - VERSION = "0.1.0" + VERSION = '0.2.0' end diff --git a/ohme.gemspec b/ohme.gemspec index 56a086f..9b3a922 100644 --- a/ohme.gemspec +++ b/ohme.gemspec @@ -1,38 +1,38 @@ # frozen_string_literal: true -require_relative "lib/ohme/version" +require_relative 'lib/ohme/version' Gem::Specification.new do |spec| - spec.name = "ohme" + spec.name = 'ohme' spec.version = Ohme::VERSION - spec.authors = ["Fabrice Carrega"] - spec.email = ["fabrice.carrega@treize37.com"] + spec.authors = ['Fabrice Carrega'] + spec.email = ['fabrice.carrega@treize37.com'] - spec.summary = "TODO: Write a short summary, because RubyGems requires one." - spec.description = "TODO: Write a longer description or delete this line." - spec.homepage = "TODO: Put your gem's website or public repo URL here." - spec.license = "MIT" - spec.required_ruby_version = ">= 2.6.0" + spec.summary = 'API client for the Ohme CRM.' + spec.description = 'API client for the Ohme CRM.' + spec.homepage = 'https://github.com/treize37/ohme' + spec.license = 'MIT' + spec.required_ruby_version = '>= 2.6.0' - spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'" + spec.metadata['allowed_push_host'] = 'https://rubygems.org' - spec.metadata["homepage_uri"] = spec.homepage - spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here." - spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here." + spec.metadata['homepage_uri'] = spec.homepage + spec.metadata['source_code_uri'] = spec.homepage + spec.metadata['changelog_uri'] = 'https://github.com/Treize37/ohme/blob/main/CHANGELOG.md' # Specify which files should be added to the gem when it is released. # The `git ls-files -z` loads the files in the RubyGem that have been added into git. spec.files = Dir.chdir(__dir__) do - `git ls-files -z`.split("\x0").reject do |f| + `git ls-files -z`.split('\x0').reject do |f| (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)}) end end - spec.bindir = "exe" + spec.bindir = 'exe' spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } - spec.require_paths = ["lib"] + spec.require_paths = ['lib'] # Uncomment to register a new dependency of your gem - # spec.add_dependency "example-gem", "~> 1.0" + spec.add_dependency 'typhoeus', '>= 1.4' # For more information and examples about making a new gem, check out our # guide at: https://bundler.io/guides/creating_gem.html diff --git a/sig/ohme.rbs b/sig/ohme.rbs index 503bae9..8a054ca 100644 --- a/sig/ohme.rbs +++ b/sig/ohme.rbs @@ -1,4 +1,37 @@ +# frozen_string_literal: true + module Ohme VERSION: String - # See the writing guide of rbs: https://github.com/ruby/rbs#guides + + module Configuration + def self.configure: () { (config: Configuration) -> void } -> void + def self.validate!: () -> void + + attr_accessor client_secret: String? + attr_accessor base_url: String? + attr_accessor timeout: Integer? + attr_accessor client_name: String? + attr_accessor version: String? + end + + class Client + def initialize: () -> void + + def get: (String, params: Hash[String, untyped]?) -> Hash[String, untyped]? + def post: (String, body: Hash[String, untyped]?) -> Hash[String, untyped]? + def put: (String, body: Hash[String, untyped]?) -> Hash[String, untyped]? + def delete: (String, params: Hash[String, untyped]?) -> nil + end + + module API + class Contact + def initialize: (Ohme::Client?) -> void + + def index: (params: Hash[String, untyped]?) -> Hash[String, untyped]? + def create: (body: Hash[String, untyped]) -> Hash[String, untyped]? + def update: (String, body: Hash[String, untyped]) -> Hash[String, untyped]? + def show: (String) -> Hash[String, untyped]? + def delete: (String) -> nil + end + end end diff --git a/spec/ohme/api/contact_spec.rb b/spec/ohme/api/contact_spec.rb new file mode 100644 index 0000000..fab86c4 --- /dev/null +++ b/spec/ohme/api/contact_spec.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_relative '../../../lib/ohme/api/contact' + +# rubocop:disable Metrics/BlockLength +RSpec.describe Ohme::API::Contact do + let(:client) { instance_double(Ohme::Client) } + let(:contact_api) { described_class.new(client) } + + describe '#index' do + it 'fetches the list of contacts' do + expect(client).to receive(:get).with('contacts', {}).and_return({ 'contacts' => [] }) + response = contact_api.index + expect(response).to eq({ 'contacts' => [] }) + end + end + + describe '#create' do + it 'creates a new contact' do + contact_data = { name: 'John Doe', email: 'john.doe@example.com' } + expect(client).to receive(:post).with('contacts', contact_data).and_return({ 'id' => '123' }) + response = contact_api.create(contact_data) + expect(response).to eq({ 'id' => '123' }) + end + end + + describe '#update' do + it 'updates a contact by ID' do + contact_data = { name: 'Jane Doe' } + expect(client).to receive(:put).with('contacts/123', contact_data) + .and_return({ 'id' => '123', 'name' => 'Jane Doe' }) + response = contact_api.update('123', contact_data) + expect(response).to eq({ 'id' => '123', 'name' => 'Jane Doe' }) + end + end + + describe '#show' do + it 'fetches a contact by ID' do + expect(client).to receive(:get).with('contacts/123').and_return({ 'id' => '123', 'name' => 'John Doe' }) + response = contact_api.show('123') + expect(response).to eq({ 'id' => '123', 'name' => 'John Doe' }) + end + end + + describe '#delete' do + it 'deletes a contact by ID' do + expect(client).to receive(:delete).with('contacts/123').and_return(nil) + response = contact_api.delete('123') + expect(response).to be_nil + end + end +end +# rubocop:enable Metrics/BlockLength diff --git a/spec/ohme/api/payment_spec.rb b/spec/ohme/api/payment_spec.rb new file mode 100644 index 0000000..5afdb83 --- /dev/null +++ b/spec/ohme/api/payment_spec.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_relative '../../../lib/ohme/api/payment' + +# rubocop:disable Metrics/BlockLength +RSpec.describe Ohme::API::Payment do + let(:client) { instance_double(Ohme::Client) } + let(:payment_api) { described_class.new(client) } + + describe '#index' do + it 'fetches the list of payments' do + expect(client).to receive(:get).with('payments', {}).and_return({ 'payments' => [] }) + response = payment_api.index + expect(response).to eq({ 'payments' => [] }) + end + end + + describe '#create' do + it 'creates a new payment' do + payment_data = { amount: 100, currency: 'USD' } + expect(client).to receive(:post).with('payments', payment_data).and_return({ 'id' => '123' }) + response = payment_api.create(payment_data) + expect(response).to eq({ 'id' => '123' }) + end + end + + describe '#update' do + it 'updates a payment by ID' do + payment_data = { amount: 150 } + expect(client).to receive(:put).with('payments/123', payment_data).and_return({ 'id' => '123', 'amount' => 150 }) + response = payment_api.update('123', payment_data) + expect(response).to eq({ 'id' => '123', 'amount' => 150 }) + end + end + + describe '#show' do + it 'fetches a payment by ID' do + expect(client).to receive(:get).with('payments/123').and_return({ 'id' => '123', 'amount' => 100 }) + response = payment_api.show('123') + expect(response).to eq({ 'id' => '123', 'amount' => 100 }) + end + end + + describe '#delete' do + it 'deletes a payment by ID' do + expect(client).to receive(:delete).with('payments/123').and_return(nil) + response = payment_api.delete('123') + expect(response).to be_nil + end + end +end +# rubocop:enable Metrics/BlockLength diff --git a/spec/ohme/client_spec.rb b/spec/ohme/client_spec.rb new file mode 100644 index 0000000..89d550b --- /dev/null +++ b/spec/ohme/client_spec.rb @@ -0,0 +1,82 @@ +# frozen_string_literal: true + +require 'json' +require 'spec_helper' +require 'typhoeus' +require_relative '../../lib/ohme/client' +require_relative '../../lib/ohme/configuration' + +# rubocop:disable Metrics/BlockLength +RSpec.describe Ohme::Client do + let(:configuration) do + Ohme::Configuration.new do |config| + config.client_secret = 'test_client_secret' + config.client_name = 'test_client_name' + end + end + + let(:client) { described_class.new(configuration) } + + describe '#get' do + it 'sends a GET request to the correct endpoint' do + Typhoeus.stub('https://api-ohme.oneheart.fr/api/v1/test_endpoint') + .and_return(Typhoeus::Response.new(code: 200, body: '{ "success": true }')) + + response = client.get('test_endpoint') + + expect(response).to eq({ 'success' => true }) + end + end + + describe '#post' do + it 'sends a POST request with the correct body' do + Typhoeus.stub('https://api-ohme.oneheart.fr/api/v1/test_endpoint') + .and_return(Typhoeus::Response.new(code: 201, body: '{ "created": true }')) + + response = client.post('test_endpoint', { key: 'value' }) + + expect(response).to eq({ 'created' => true }) + end + end + + describe '#put' do + it 'sends a PUT request with the correct body' do + Typhoeus.stub('https://api-ohme.oneheart.fr/api/v1/test_endpoint') + .and_return(Typhoeus::Response.new(code: 200, body: '{ "updated": true }')) + + response = client.put('test_endpoint', { key: 'updated_value' }) + + expect(response).to eq({ 'updated' => true }) + end + end + + describe '#delete' do + it 'sends a DELETE request to the correct endpoint' do + Typhoeus.stub('https://api-ohme.oneheart.fr/api/v1/test_endpoint') + .and_return(Typhoeus::Response.new(code: 204, body: '')) + + response = client.delete('test_endpoint') + + expect(response).to eq(nil) + end + end + + describe 'error handling' do + it 'raises an error for a timeout' do + error_message = 'Request timed out. Please check your network connection or increase the timeout.' + Typhoeus.stub('https://api-ohme.oneheart.fr/api/v1/test_endpoint') + .and_return(Typhoeus::Response.new(code: 0, return_code: :operation_timedout, return_message: 'Timeout')) + + expect { client.get('test_endpoint') }.to raise_error(error_message) + end + + it 'raises an error for a failed request' do + error_message = 'HTTP request failed: 500 - Internal Server Error' + Typhoeus.stub('https://api-ohme.oneheart.fr/api/v1/test_endpoint') + .and_return(Typhoeus::Response.new(code: 500, body: 'Internal Server Error')) + + expect { client.get('test_endpoint') }.to raise_error(error_message) + end + end +end +# rubocop:enable Metrics/BlockLength diff --git a/spec/ohme/configuration_spec.rb b/spec/ohme/configuration_spec.rb new file mode 100644 index 0000000..4b42cff --- /dev/null +++ b/spec/ohme/configuration_spec.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_relative '../../lib/ohme/configuration' + +# rubocop:disable Metrics/BlockLength +RSpec.describe Ohme::Configuration do + describe '.new' do + let(:conf) do + described_class.new do |config| + config.base_url = 'https://api.example.com' + config.client_name = 'test_client_name' + config.client_secret = 'test_client_secret' + config.timeout = 60 + config.version = 'v1' + end + end + + describe 'setting configuration attributes' do + it 'sets the client_secret attribute correctly' do + expect(conf.client_secret).to eq('test_client_secret') + end + + it 'sets the base_url attribute correctly' do + expect(conf.base_url).to eq('https://api.example.com') + end + + it 'sets the client_name attribute correctly' do + expect(conf.client_name).to eq('test_client_name') + end + + it 'sets the version attribute correctly' do + expect(conf.version).to eq('v1') + end + + it 'sets the timeout attribute correctly' do + expect(conf.timeout).to eq(60) + end + end + end + + describe '#validate!' do + let(:conf) { described_class.new } + + context 'when all required attributes are set' do + it 'does not raise an error' do + conf.client_name = 'test_client_name' + conf.client_secret = 'test_client_secret' + + expect { conf.validate! }.not_to raise_error + end + end + + context 'when client_name is missing' do + it 'raises an error' do + error_message = 'client_name is missing. ' \ + 'Please configure Ohme::Configuration.client_name.' + conf.client_secret = 'test_client_secret' + + expect { conf.validate! }.to raise_error(error_message) + end + end + + context 'when client_secret is missing' do + it 'raises an error' do + error_message = 'client_secret is missing. ' \ + 'Please configure Ohme::Configuration.client_secret.' + conf.client_name = 'test_client_name' + + expect { conf.validate! }.to raise_error(error_message) + end + end + end +end +# rubocop:enable Metrics/BlockLength diff --git a/spec/ohme_spec.rb b/spec/ohme_spec.rb index 3845426..46713ff 100644 --- a/spec/ohme_spec.rb +++ b/spec/ohme_spec.rb @@ -1,11 +1,7 @@ # frozen_string_literal: true RSpec.describe Ohme do - it "has a version number" do + it 'has a version number' do expect(Ohme::VERSION).not_to be nil end - - it "does something useful" do - expect(false).to eq(true) - end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 2e0998b..5c8f6a2 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -4,7 +4,7 @@ RSpec.configure do |config| # Enable flags like --only-failures and --next-failure - config.example_status_persistence_file_path = ".rspec_status" + config.example_status_persistence_file_path = '.rspec_status' # Disable RSpec exposing methods globally on `Module` and `main` config.disable_monkey_patching!