enginn 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []