enginn 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 69df7684cee8d69dc1323a4619fa36da07ca99c4971c2efd5e028b01d896587e
4
+ data.tar.gz: 27e16a94a761a330c3e0c0b036804de6518d190606a5a7889df5f2845c9f9832
5
+ SHA512:
6
+ metadata.gz: 2a18523033fd9b7d102dde8cc5206b0d1e7709e7ca690db333282d940351b6a10c23f3ff95b8b064a88447a738539d579246036296e9af323256dc4c34bd0f26
7
+ data.tar.gz: f1a040d449fd07ce2dd70dab88b6458a7404fff498fcf77daf74b5afdbcfe50b05fa5f07d8f8a014a0179697902474af26f008b751a209ba25692e56e65aac43
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,44 @@
1
+ # See list of defaults here: https://docs.rubocop.org/rubocop/index.html
2
+
3
+ require:
4
+ - rubocop-performance
5
+ - rubocop-rspec
6
+ - rubocop-rake
7
+
8
+ AllCops:
9
+ TargetRubyVersion: 2.6
10
+ NewCops: enable
11
+ Exclude:
12
+ - bin/**/*
13
+ - vendor/**/* # Fix missing gem in CI when using `bundler-cache: true`
14
+
15
+ Gemspec/RequireMFA:
16
+ Enabled: false
17
+
18
+ # ------------------------------------------------------------------------------
19
+ # DEPARTMENT LAYOUT
20
+ # ------------------------------------------------------------------------------
21
+
22
+ Layout/FirstArrayElementIndentation:
23
+ EnforcedStyle: consistent # default: special_inside_parentheses
24
+
25
+ Layout/FirstHashElementIndentation:
26
+ EnforcedStyle: consistent # default: special_inside_parentheses
27
+
28
+ Layout/LineLength:
29
+ Max: 100 # default: 120
30
+
31
+ # ------------------------------------------------------------------------------
32
+ # DEPARTMENT METRICS
33
+ # ------------------------------------------------------------------------------
34
+
35
+ Metrics/BlockLength:
36
+ Exclude:
37
+ - spec/**/*
38
+
39
+ # ------------------------------------------------------------------------------
40
+ # DEPARTMENT STYLE
41
+ # ------------------------------------------------------------------------------
42
+
43
+ Style/Documentation:
44
+ Enabled: false # default: true
data/CHANGELOG.md ADDED
@@ -0,0 +1,16 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ # Unreleased
9
+ (nothing yet!)
10
+
11
+ ## [0.1.1] - 2022-09-13
12
+ ### Added
13
+ - Initial working set of functionalities.
14
+
15
+ [Unreleased]: https://github.com/EnginnTechnologies/enginn-rb/compare/v0.1.1...HEAD
16
+ [0.1.1]: https://github.com/EnginnTechnologies/enginn-rb/releases/tag/v0.1.1
data/Gemfile ADDED
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in enginn.gemspec
6
+ gemspec
7
+
8
+ group :development do
9
+ gem 'rake', '~> 13.0'
10
+ gem 'rubocop', '~> 1.21', require: false
11
+ gem 'rubocop-performance', '~> 1.13', require: false
12
+ gem 'rubocop-rake', '~> 0.6.0', require: false
13
+ gem 'rubocop-rspec', '~> 2.7', require: false
14
+ gem 'yard', '~> 0.9.27', require: false
15
+ end
16
+
17
+ group :test do
18
+ gem 'rspec', '~> 3.0'
19
+ gem 'simplecov', require: false
20
+ end
21
+
22
+ group :development, :test do
23
+ gem 'debug', '~> 1.4'
24
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,94 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ enginn (0.1.1)
5
+ faraday (~> 2.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ ast (2.4.2)
11
+ debug (1.6.2)
12
+ irb (>= 1.3.6)
13
+ reline (>= 0.3.1)
14
+ diff-lcs (1.5.0)
15
+ docile (1.4.0)
16
+ faraday (2.5.2)
17
+ faraday-net_http (>= 2.0, < 3.1)
18
+ ruby2_keywords (>= 0.0.4)
19
+ faraday-net_http (3.0.0)
20
+ io-console (0.5.11)
21
+ irb (1.4.1)
22
+ reline (>= 0.3.0)
23
+ json (2.6.2)
24
+ parallel (1.22.1)
25
+ parser (3.1.2.1)
26
+ ast (~> 2.4.1)
27
+ rainbow (3.1.1)
28
+ rake (13.0.6)
29
+ regexp_parser (2.5.0)
30
+ reline (0.3.1)
31
+ io-console (~> 0.5)
32
+ rexml (3.2.5)
33
+ rspec (3.11.0)
34
+ rspec-core (~> 3.11.0)
35
+ rspec-expectations (~> 3.11.0)
36
+ rspec-mocks (~> 3.11.0)
37
+ rspec-core (3.11.0)
38
+ rspec-support (~> 3.11.0)
39
+ rspec-expectations (3.11.1)
40
+ diff-lcs (>= 1.2.0, < 2.0)
41
+ rspec-support (~> 3.11.0)
42
+ rspec-mocks (3.11.1)
43
+ diff-lcs (>= 1.2.0, < 2.0)
44
+ rspec-support (~> 3.11.0)
45
+ rspec-support (3.11.1)
46
+ rubocop (1.36.0)
47
+ json (~> 2.3)
48
+ parallel (~> 1.10)
49
+ parser (>= 3.1.2.1)
50
+ rainbow (>= 2.2.2, < 4.0)
51
+ regexp_parser (>= 1.8, < 3.0)
52
+ rexml (>= 3.2.5, < 4.0)
53
+ rubocop-ast (>= 1.20.1, < 2.0)
54
+ ruby-progressbar (~> 1.7)
55
+ unicode-display_width (>= 1.4.0, < 3.0)
56
+ rubocop-ast (1.21.0)
57
+ parser (>= 3.1.1.0)
58
+ rubocop-performance (1.15.0)
59
+ rubocop (>= 1.7.0, < 2.0)
60
+ rubocop-ast (>= 0.4.0)
61
+ rubocop-rake (0.6.0)
62
+ rubocop (~> 1.0)
63
+ rubocop-rspec (2.13.1)
64
+ rubocop (~> 1.33)
65
+ ruby-progressbar (1.11.0)
66
+ ruby2_keywords (0.0.5)
67
+ simplecov (0.21.2)
68
+ docile (~> 1.1)
69
+ simplecov-html (~> 0.11)
70
+ simplecov_json_formatter (~> 0.1)
71
+ simplecov-html (0.12.3)
72
+ simplecov_json_formatter (0.1.4)
73
+ unicode-display_width (2.2.0)
74
+ webrick (1.7.0)
75
+ yard (0.9.28)
76
+ webrick (~> 1.7.0)
77
+
78
+ PLATFORMS
79
+ x86_64-linux
80
+
81
+ DEPENDENCIES
82
+ debug (~> 1.4)
83
+ enginn!
84
+ rake (~> 13.0)
85
+ rspec (~> 3.0)
86
+ rubocop (~> 1.21)
87
+ rubocop-performance (~> 1.13)
88
+ rubocop-rake (~> 0.6.0)
89
+ rubocop-rspec (~> 2.7)
90
+ simplecov
91
+ yard (~> 0.9.27)
92
+
93
+ BUNDLED WITH
94
+ 2.3.18
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022 Enginn Technologies
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,72 @@
1
+ [![CI](https://github.com/EnginnTechnologies/enginn-rb/actions/workflows/ci.yml/badge.svg)](https://github.com/EnginnTechnologies/enginn-rb/actions/workflows/ci.yml)
2
+ [![Release](https://github.com/EnginnTechnologies/enginn-rb/actions/workflows/release.yml/badge.svg)](https://github.com/EnginnTechnologies/enginn-rb/actions/workflows/release.yml)
3
+ [![Gem Version](https://badge.fury.io/rb/enginn.svg)](https://badge.fury.io/rb/enginn)
4
+
5
+ # Enginn
6
+
7
+ The official gem to interact with the [Enginn API](https://app.enginn.tech/api/docs/index.html).
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'enginn'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ $ bundle install
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install enginn
24
+
25
+ ## Usage
26
+
27
+ Visit the [API documentation](https://www.rubydoc.info/github/EnginnTechnologies/enginn-rb/)
28
+ for more details.
29
+
30
+ ```rb
31
+ # Create a client
32
+ client = Enginn::Client.new(api_token: 'xxxxx')
33
+
34
+ # Retrieve a project
35
+ project = client.projects.where(id: 'xxxxx').first
36
+
37
+ # Manipulate collections
38
+ characters = project.characters.where(gender_eq: 'male')
39
+ characters.each do |character|
40
+ # ...
41
+ end
42
+
43
+ # Update a character
44
+ character = project.characters.first
45
+ character.name = 'Pilou'
46
+ character.save!
47
+
48
+ # Create a new character
49
+ character = Enginn::Character.new(project, name: 'Raph', gender: 'male', ...)
50
+ character.save!
51
+
52
+ # Destroy a character
53
+ character.destroy!
54
+ ```
55
+
56
+ ## Development
57
+
58
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
59
+
60
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
61
+
62
+ ## Contributing
63
+
64
+ Bug reports and pull requests are welcome on GitHub at https://github.com/EnginnTechnologies/enginn-rb.
65
+
66
+ ## Changelog
67
+
68
+ See [CHANGELOG.md](https://github.com/EnginnTechnologies/enginn-rb/blob/main/CHANGELOG.md).
69
+
70
+ ## License
71
+
72
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require 'rubocop/rake_task'
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[spec rubocop]
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ Bundler.require(:development)
6
+ require 'enginn'
7
+ require 'irb'
8
+
9
+ @client = Enginn::Client.new(api_token: ENV['ENGINN_API_TOKEN'])
10
+ @client.connection do |conn|
11
+ conn.url_prefix = ENV['ENGINN_BASE_URL'] || Enginn::Client::BASE_URL
12
+ conn.response :logger
13
+ end
14
+
15
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Enginn
4
+ class Character < Resource
5
+ def self.path
6
+ 'characters'
7
+ end
8
+
9
+ # Retrieve the takes of this character.
10
+ # @return [Enginn::TakesIndex]
11
+ def takes
12
+ TakesIndex.new(@project).where(character_id_eq: @attributes[:id])
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Enginn
4
+ class CharactersIndex < ResourceIndex
5
+ def self.resource
6
+ Character
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
4
+
5
+ module Enginn
6
+ class Client
7
+ BASE_URL = 'https://app.enginn.tech/api/v1'
8
+
9
+ attr_reader :api_token, :adapter
10
+
11
+ # @param api_token [String] The API token to use
12
+ # @param adapter [Symbol] The Faraday adapter to use
13
+ def initialize(api_token:, adapter: Faraday.default_adapter)
14
+ @api_token = api_token
15
+ @adapter = adapter
16
+ end
17
+
18
+ # Get a connection to the API.
19
+ #
20
+ # @yieldparam connection [Faraday::Connection] if a block is given
21
+ # @return [Faraday::Connection]
22
+ def connection
23
+ @connection ||= Faraday.new(BASE_URL) do |conn|
24
+ conn.adapter @adapter
25
+ conn.request :authorization, 'Bearer', -> { @api_token }
26
+ conn.request :json
27
+ conn.response :json
28
+ conn.response :enginn_raise_error
29
+ end
30
+ yield(@connection) if block_given?
31
+ @connection
32
+ end
33
+
34
+ # Retrieve the projects the account have access to.
35
+ #
36
+ # @return [Enginn::ProjectsIndex]
37
+ def projects
38
+ ProjectsIndex.new(self)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Enginn
4
+ class DictionaryEntriesIndex < ResourceIndex
5
+ def self.resource
6
+ DictionaryEntry
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Enginn
4
+ class DictionaryEntry < Resource
5
+ def self.path
6
+ 'dictionary_entries'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Enginn
4
+ class Error < StandardError; end
5
+
6
+ # Map Enginn errors to Faraday's while keeping Enginn::Error inheriting from
7
+ # StandardError.
8
+ class HTTPError < Faraday::Error; end
9
+ class ClientError < HTTPError; end
10
+ class ServerError < HTTPError; end
11
+ class BadRequestError < ClientError; end
12
+ class UnauthorizedError < ClientError; end
13
+ class ForbiddenError < ClientError; end
14
+ class ResourceNotFound < ClientError; end
15
+ class ProxyAuthError < ClientError; end
16
+ class ConflictError < ClientError; end
17
+ class UnprocessableEntityError < ClientError; end
18
+ class NilStatusError < ServerError; end
19
+
20
+ # Override the Faraday::Response::RaiseError middleware to raise Enginn
21
+ # errors instead of Faraday's
22
+ # (see https://github.com/lostisland/faraday -> lib/faraday/error.rb)
23
+ #
24
+ # rubocop:disable Metrics/AbcSize
25
+ # rubocop:disable Metrics/CyclomaticComplexity
26
+ # rubocop:disable Metrics/MethodLength
27
+ class RaiseError < Faraday::Response::RaiseError
28
+ def on_complete(env)
29
+ case env[:status]
30
+ when 400
31
+ raise Enginn::BadRequestError, response_values(env)
32
+ when 401
33
+ raise Enginn::UnauthorizedError, response_values(env)
34
+ when 403
35
+ raise Enginn::ForbiddenError, response_values(env)
36
+ when 404
37
+ raise Enginn::ResourceNotFound, response_values(env)
38
+ when 407
39
+ # mimic the behavior that we get with proxy requests with HTTPS
40
+ msg = %(407 "Proxy Authentication Required")
41
+ raise Enginn::ProxyAuthError.new(msg, response_values(env))
42
+ when 409
43
+ raise Enginn::ConflictError, response_values(env)
44
+ when 422
45
+ raise Enginn::UnprocessableEntityError, response_values(env)
46
+ when ClientErrorStatuses
47
+ raise Enginn::ClientError, response_values(env)
48
+ when ServerErrorStatuses
49
+ raise Enginn::ServerError, response_values(env)
50
+ when nil
51
+ raise Enginn::NilStatusError, response_values(env)
52
+ end
53
+ end
54
+ end
55
+ # rubocop:enable Metrics/AbcSize
56
+ # rubocop:enable Metrics/CyclomaticComplexity
57
+ # rubocop:enable Metrics/MethodLength
58
+
59
+ Faraday::Response.register_middleware(enginn_raise_error: Enginn::RaiseError)
60
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Enginn
4
+ class Line < Resource
5
+ def self.path
6
+ 'lines'
7
+ end
8
+
9
+ # Retrieve the takes of this line.
10
+ # @return [Enginn::TakesIndex]
11
+ def takes
12
+ TakesIndex.new(@project).where(line_id_eq: @attributes[:id])
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Enginn
4
+ class LineTag < Resource
5
+ def self.path
6
+ 'line_tags'
7
+ end
8
+
9
+ # Retrieve the lines of this line tag.
10
+ # @return [Enginn::LinesIndex]
11
+ def lines
12
+ LinesIndex.new(@project).where(line_tag_id_eq: @attributes[:id])
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Enginn
4
+ class LineTagsIndex < ResourceIndex
5
+ def self.resource
6
+ LineTag
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Enginn
4
+ class LinesIndex < ResourceIndex
5
+ def self.resource
6
+ Line
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Enginn
4
+ class Project < Resource
5
+ def self.path
6
+ 'projects'
7
+ end
8
+
9
+ attr_reader :client
10
+
11
+ # @param client [Enginn::Client] The client to use with this project and its sub-resources
12
+ def initialize(client, attributes = {})
13
+ @client = client
14
+ super(self, attributes)
15
+ end
16
+
17
+ # Retrieve the characters present in this project.
18
+ # @return [Enginn::CharactersIndex]
19
+ def characters
20
+ CharactersIndex.new(self)
21
+ end
22
+
23
+ # Retrieve the dictionary entries present in this project.
24
+ # @return [Enginn::DictionaryEntriesIndex]
25
+ def dictionary_entries
26
+ DictionaryEntriesIndex.new(self)
27
+ end
28
+
29
+ alias dictionary dictionary_entries
30
+
31
+ # Retrieve the synthesis exports present in this project.
32
+ # @return [Enginn::SynthesisExportsIndex]
33
+ def synthesis_exports
34
+ SynthesisExportsIndex.new(self)
35
+ end
36
+
37
+ # Retrieve the scenes present in this project.
38
+ # @return [Enginn::ScenesIndex]
39
+ def scenes
40
+ ScenesIndex.new(self)
41
+ end
42
+
43
+ # Retrieve the lines present in this project.
44
+ # @return [Enginn::LinesIndex]
45
+ def lines
46
+ LinesIndex.new(self)
47
+ end
48
+
49
+ # Retrieve the line_tags present in this project.
50
+ # @return [Enginn::LineTagsIndex]
51
+ def line_tags
52
+ LineTagsIndex.new(self)
53
+ end
54
+
55
+ # Retrieve the takes present in this project.
56
+ # @return [Enginn::TakesIndex]
57
+ def takes
58
+ TakesIndex.new(self)
59
+ end
60
+
61
+ # Retrieve the take_batches present in this project.
62
+ # @return [Enginn::TakeBatchesIndex]
63
+ def take_batches
64
+ TakeBatchesIndex.new(self)
65
+ end
66
+
67
+ # @api private
68
+ def route
69
+ "#{self.class.path}/#{@attributes[:id]}"
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Enginn
4
+ class ProjectsIndex < ResourceIndex
5
+ # @see ResourceIndex.resource
6
+ def self.resource
7
+ Project
8
+ end
9
+
10
+ attr_reader :client
11
+
12
+ # @param client [Enginn::Client] The client to use with this project and resources
13
+ def initialize(client)
14
+ @client = client
15
+ super(self)
16
+ end
17
+
18
+ # @see ResourceIndex#fetch!
19
+ def fetch!
20
+ response = request
21
+ @pagination = response[:pagination]
22
+ @collection = response[:result].map do |attributes|
23
+ self.class.resource.new(@client, attributes)
24
+ end
25
+ self
26
+ end
27
+
28
+ # @api private
29
+ def route
30
+ 'projects'
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'string_utils'
4
+
5
+ module Enginn
6
+ # A Resource can be a Character, a Take, or anything described in the
7
+ # Enginn API doc (https://app.enginn.tech/api/docs).
8
+ #
9
+ # A Resource depends on a Client that will be used for actual HTTP operations
10
+ # and is relative to a parent Project (see {#initialize} parameters). When a
11
+ # Resource is fetched through {#fetch} or {#save}, any received attributes
12
+ # from the API is synced with the object such as it is available as an
13
+ # instance method.
14
+ #
15
+ # @example
16
+ # character = Enginn::Character(project, { id: "00000000-0000-0000-0000-000000000000" })
17
+ # character.name # NoMethodError
18
+ # character.fetch!
19
+ # character.name # => 'Rocky'
20
+ #
21
+ # A Resource whose attributes include an ID will be considered as already
22
+ # existing and as such, subsequent calls to {#save} will issue a PATCH
23
+ # request. Otherwise, a POST request will be issued instead, allowing the
24
+ # creation of a new Resource.
25
+ #
26
+ # @example
27
+ # scene = Enginn::Scene.new(project, { name: 'Grand Finale' })
28
+ # scene.save # POST request (i.e. a new scene created)
29
+ # scene.id # => "00000000-0000-0000-0000-000000000000"
30
+ # scene.name = 'The End'
31
+ # scene.save # PATCH request (i.e. the scene is updated)
32
+ #
33
+ # @abstract Override the {.path} method to implement.
34
+ class Resource
35
+ # Get the path to use for this kind of {Enginn::Resource}
36
+ #
37
+ # @api private
38
+ # @return [String]
39
+ def self.path
40
+ raise "path is not overriden for #{self}"
41
+ end
42
+
43
+ attr_reader :project, :errors
44
+ attr_accessor :attributes
45
+
46
+ # @param project [Enginn::Project] The parent project of this resource
47
+ # @param attributes [Hash] The attributes to initialize the resource with
48
+ def initialize(project, attributes = {})
49
+ @project = project
50
+ @attributes = {}
51
+ @errors = []
52
+ sync_attributes_with(attributes || {})
53
+ end
54
+
55
+ # @raise [Faraday::Error] if something goes wrong during the request
56
+ # @return [true] if the requested has succeeded
57
+ def fetch!
58
+ result = request(:get)[:result]
59
+ sync_attributes_with(result)
60
+ true
61
+ end
62
+
63
+ # Same as {#fetch!} but return false instead of raising an exception.
64
+ # Also fill in {#errors} with the server response.
65
+ # @see fetch!
66
+ # @return [Boolean]
67
+ def fetch
68
+ fetch!
69
+ true
70
+ rescue Faraday::Error => e
71
+ @errors << e.response
72
+ false
73
+ end
74
+
75
+ # @raise [Faraday::Error] if something goes wrong during the request
76
+ # @return [true] if the requested has succeeded
77
+ def save!
78
+ response = request(@attributes[:id].nil? ? :post : :patch)
79
+ sync_attributes_with(response[:result])
80
+ true
81
+ end
82
+
83
+ # Same as {#save!} but return false instead of raising an exception.
84
+ # Also fill in {#errors} with the server response.
85
+ # @see save!
86
+ # @return [Boolean]
87
+ def save
88
+ save!
89
+ true
90
+ rescue Faraday::Error => e
91
+ @errors << e.response
92
+ false
93
+ end
94
+
95
+ # @raise [Faraday::Error] if something goes wrong during the request
96
+ # @return [true] if the requested has succeeded
97
+ def destroy!
98
+ request(:delete)
99
+ true
100
+ end
101
+
102
+ # Same as {#destroy!} but return false instead of raising an exception.
103
+ # Also fill in {#errors} with the server response.
104
+ # @see destroy!
105
+ # @return [Boolean]
106
+ def destroy
107
+ destroy!
108
+ true
109
+ rescue Faraday::Error => e
110
+ @errors << e.response
111
+ false
112
+ end
113
+
114
+ # @return [String]
115
+ def inspect
116
+ "#<#{self.class} #{@attributes.map { |name, value| "@#{name}=#{value.inspect}" }.join(', ')}>"
117
+ end
118
+
119
+ # @api private
120
+ # @return [String]
121
+ def route
122
+ "#{@project.route}/#{self.class.path}/#{@attributes[:id]}"
123
+ end
124
+
125
+ private
126
+
127
+ def sync_attributes_with(hash)
128
+ @attributes.merge!(hash)
129
+ @attributes.each do |attribute, value|
130
+ instance_variable_set("@#{attribute}", value)
131
+ self.class.define_method(attribute) { @attributes[attribute] }
132
+ self.class.define_method("#{attribute}=") { |arg| @attributes[attribute] = arg }
133
+ end
134
+ end
135
+
136
+ def request(method)
137
+ resource_name = StringUtils.underscore(self.class.name.split('::').last)
138
+ params = %i[post patch].include?(method) ? { resource_name => @attributes } : {}
139
+ response = @project.client.connection.public_send(method, route, params)
140
+ JSON.parse(JSON[response.body], symbolize_names: true)
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Enginn
4
+ # A {ResourceIndex} is a collection of fetchable {Resource}.
5
+ #
6
+ # It can be filtered and paginated through the chainable methods {#per},
7
+ # {#page}, and {#where}. It also includes the Enumerable module so methods
8
+ # such as {#each}, #map or #to_a are available.
9
+ #
10
+ # Actual API requests are only issued when the {#each} method (or any method
11
+ # from Enumerable) is called. While {#each}-ing, new API request will be
12
+ # issued when the end of a page is reached. Note that when using {#page}, only
13
+ # the given page is reached for.
14
+ # One can also force fetching manually using {#fetch}.
15
+ #
16
+ # @example
17
+ # takes = project.takes.where(synthesis_text_cont: 'hello')
18
+ # takes.map(&:character_name)
19
+ #
20
+ # @abstract Override the {.resource} method to implement.
21
+ class ResourceIndex
22
+ # Define the type of {Enginn::Resource} to use with this kind of {Enginn::ResourceIndex}.
23
+ #
24
+ # @api private
25
+ # @return [Enginn::Resource]
26
+ def self.resource
27
+ raise "resource is not overriden for #{self}"
28
+ end
29
+
30
+ # @api private
31
+ # @return [String]
32
+ def self.path
33
+ resource.path
34
+ end
35
+
36
+ include Enumerable
37
+
38
+ attr_reader :project, :errors
39
+ attr_accessor :filters, :pagination
40
+
41
+ # @param project [Enginn::Project] The parent project of the indexed resource
42
+ def initialize(project)
43
+ @project = project
44
+ @filters = {}
45
+ @pagination = { current: 1 }
46
+ @errors = []
47
+ end
48
+
49
+ # @yieldparam item [Enginn::Resource]
50
+ # @return [self]
51
+ def each(&block)
52
+ fetch!
53
+ @collection.each(&block)
54
+ return self if @pagination[:locked]
55
+
56
+ while @pagination[:current] < @pagination[:last]
57
+ pagination[:current] += 1
58
+ fetch!
59
+ @collection.each(&block)
60
+ end
61
+
62
+ @pagination = { current: 1 }
63
+ self
64
+ end
65
+
66
+ # @param page [Integer] The page number
67
+ # @return [Enginn::ResourceIndex] A new index with updated pagination
68
+ def page(page)
69
+ new_index = clone
70
+ new_index.pagination = @pagination.merge(current: page, locked: true)
71
+ new_index
72
+ end
73
+
74
+ # @param per [Integer] The number of items per page
75
+ # @return [Enginn::ResourceIndex] A new index with updated pagination
76
+ def per(per)
77
+ new_index = clone
78
+ new_index.pagination = @pagination.merge(per: per)
79
+ new_index
80
+ end
81
+
82
+ # @param filters [Hash] Filters as you would use them in the `q` object with the API.
83
+ # @return [Enginn::ResourceIndex] A new filtered index
84
+ def where(filters)
85
+ new_index = clone
86
+ new_index.filters = @filters.merge(filters || {})
87
+ new_index
88
+ end
89
+
90
+ # Fetch the current page from the API. Resulting items of the collection are
91
+ # wrapped in the corresponding {Enginn::Resource} subclass.
92
+ #
93
+ # @return [true] if the request has been successfull
94
+ def fetch!
95
+ response = request
96
+ @pagination = response[:pagination]
97
+ @collection = response[:result].map do |attributes|
98
+ self.class.resource.new(@project, attributes)
99
+ end
100
+ true
101
+ end
102
+
103
+ # Same as {#fetch!} but return false instead of raising an exception.
104
+ # Also fill in {#errors} with the server response.
105
+ # @see fetch!
106
+ # @return [Boolean]
107
+ def fetch
108
+ fetch!
109
+ true
110
+ rescue Faraday::Error => e
111
+ @errors << e.response
112
+ false
113
+ end
114
+
115
+ # @return [String]
116
+ def inspect
117
+ attributes = instance_variables.map do |var|
118
+ "#{var}=#{instance_variable_get(var)}"
119
+ end
120
+ "#<#{self.class} #{attributes.join(', ')}>"
121
+ end
122
+
123
+ # @api private
124
+ # @return [String]
125
+ def route
126
+ "#{@project.route}/#{self.class.path}"
127
+ end
128
+
129
+ private
130
+
131
+ def request
132
+ response = @project.client.connection.get(route, {
133
+ per: @pagination[:per],
134
+ page: @pagination[:current],
135
+ q: @filters
136
+ }.reject { |_, value| value.nil? || (value.respond_to?(:empty?) && value.empty?) })
137
+ JSON.parse(JSON[response.body], symbolize_names: true)
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Enginn
4
+ class Scene < Resource
5
+ def self.path
6
+ 'scenes'
7
+ end
8
+
9
+ # Retrieve the lines of this scene.
10
+ # @return [Enginn::TakesIndex]
11
+ def lines
12
+ LinesIndex.new(@project).where(scene_id_eq: @attributes[:id])
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Enginn
4
+ class ScenesIndex < ResourceIndex
5
+ def self.resource
6
+ Scene
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Enginn
4
+ module StringUtils
5
+ module_function
6
+
7
+ def underscore(str)
8
+ str.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
9
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
10
+ .tr('-', '_')
11
+ .downcase
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Enginn
4
+ class SynthesisExport < Resource
5
+ def self.path
6
+ 'synthesis_exports'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Enginn
4
+ class SynthesisExportsIndex < ResourceIndex
5
+ def self.resource
6
+ SynthesisExport
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Enginn
4
+ class Take < Resource
5
+ def self.path
6
+ 'takes'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Enginn
4
+ class TakeBatch < Resource
5
+ def self.path
6
+ 'take_batches'
7
+ end
8
+
9
+ # Retrieve the takes of this take_batch.
10
+ # @return [Enginn::TakesIndex]
11
+ def takes
12
+ TakesIndex.new(@project).where(take_batch_id_eq: @attributes[:id])
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Enginn
4
+ class TakeBatchesIndex < ResourceIndex
5
+ def self.resource
6
+ TakeBatch
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Enginn
4
+ class TakesIndex < ResourceIndex
5
+ def self.resource
6
+ Take
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Enginn
4
+ class TestSynthesis < Resource
5
+ def self.path
6
+ 'test_syntheses'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Enginn
4
+ VERSION = '0.1.1'
5
+ end
data/lib/enginn.rb ADDED
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'enginn/version'
4
+ require_relative 'enginn/client'
5
+ require_relative 'enginn/error'
6
+
7
+ require_relative 'enginn/resource'
8
+ require_relative 'enginn/character'
9
+ require_relative 'enginn/dictionary_entry'
10
+ require_relative 'enginn/test_synthesis'
11
+ require_relative 'enginn/take'
12
+ require_relative 'enginn/take_batch'
13
+ require_relative 'enginn/line'
14
+ require_relative 'enginn/line_tag'
15
+ require_relative 'enginn/synthesis_export'
16
+ require_relative 'enginn/scene'
17
+ require_relative 'enginn/project'
18
+
19
+ require_relative 'enginn/resource_index'
20
+ require_relative 'enginn/characters_index'
21
+ require_relative 'enginn/dictionary_entries_index'
22
+ require_relative 'enginn/takes_index'
23
+ require_relative 'enginn/take_batches_index'
24
+ require_relative 'enginn/lines_index'
25
+ require_relative 'enginn/line_tags_index'
26
+ require_relative 'enginn/synthesis_exports_index'
27
+ require_relative 'enginn/scenes_index'
28
+ require_relative 'enginn/projects_index'
29
+
30
+ module Enginn
31
+ end
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: enginn
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Enginn Technologies
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2022-09-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ description:
28
+ email:
29
+ - mail@enginn.tech
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - ".rspec"
35
+ - ".rubocop.yml"
36
+ - CHANGELOG.md
37
+ - Gemfile
38
+ - Gemfile.lock
39
+ - LICENSE.txt
40
+ - README.md
41
+ - Rakefile
42
+ - bin/console
43
+ - bin/setup
44
+ - lib/enginn.rb
45
+ - lib/enginn/character.rb
46
+ - lib/enginn/characters_index.rb
47
+ - lib/enginn/client.rb
48
+ - lib/enginn/dictionary_entries_index.rb
49
+ - lib/enginn/dictionary_entry.rb
50
+ - lib/enginn/error.rb
51
+ - lib/enginn/line.rb
52
+ - lib/enginn/line_tag.rb
53
+ - lib/enginn/line_tags_index.rb
54
+ - lib/enginn/lines_index.rb
55
+ - lib/enginn/project.rb
56
+ - lib/enginn/projects_index.rb
57
+ - lib/enginn/resource.rb
58
+ - lib/enginn/resource_index.rb
59
+ - lib/enginn/scene.rb
60
+ - lib/enginn/scenes_index.rb
61
+ - lib/enginn/string_utils.rb
62
+ - lib/enginn/synthesis_export.rb
63
+ - lib/enginn/synthesis_exports_index.rb
64
+ - lib/enginn/take.rb
65
+ - lib/enginn/take_batch.rb
66
+ - lib/enginn/take_batches_index.rb
67
+ - lib/enginn/takes_index.rb
68
+ - lib/enginn/test_synthesis.rb
69
+ - lib/enginn/version.rb
70
+ homepage: https://github.com/EnginnTechnologies/enginn-rb
71
+ licenses:
72
+ - MIT
73
+ metadata:
74
+ homepage_uri: https://github.com/EnginnTechnologies/enginn-rb
75
+ source_code_uri: https://github.com/EnginnTechnologies/enginn-rb
76
+ changelog_uri: https://github.com/EnginnTechnologies/enginn-rb/blob/v0.1.1/CHANGELOG.md
77
+ post_install_message:
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: 2.6.0
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubygems_version: 3.0.3.1
93
+ signing_key:
94
+ specification_version: 4
95
+ summary: Official Enginn API wrapper for Ruby.
96
+ test_files: []