loops_sdk 0.1.0

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: 2f72e2f62c89ee3d1ba4bf2803ce036d1bbaf0c5090cb59bc5dfed76310e0d64
4
+ data.tar.gz: 611b4184d555033ba4c4166426519a4bf9cea4fb47675b4b2b99ed0cafea9a58
5
+ SHA512:
6
+ metadata.gz: 128ae813b6a85b3420a30f6400c9ab11151d1cb95d73518bf776f31e54a64aa6b17d0e548abb54048bb4e4446395a1b7e71b6d2f145b81ab18adf834ded6ba0f
7
+ data.tar.gz: 10d6820a08203cbac614de06c54f482b9beea538a73d0d9fa31543a43150cb8183552d52a7ae58a9bd4a82299edb2f807e7f8deb400060e0675c2c37e71c9534
data/.rubocop.yml ADDED
@@ -0,0 +1,11 @@
1
+ AllCops:
2
+ TargetRubyVersion: 3.0
3
+
4
+ Style/StringLiterals:
5
+ EnforcedStyle: double_quotes
6
+
7
+ Style/StringLiteralsInInterpolation:
8
+ EnforcedStyle: double_quotes
9
+
10
+ Metrics/ParameterLists:
11
+ Max: 6
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ ## [0.1.0] - [TBD]
2
+
3
+ - Initial release
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 Loops
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,59 @@
1
+ # Loops Ruby SDK
2
+
3
+ ## Introduction
4
+
5
+ This is the official Ruby SDK for [Loops](https://loops.so), an email platform for modern software companies.
6
+
7
+ ## Installation
8
+
9
+ Install the gem and add to the application's Gemfile by executing:
10
+
11
+ $ bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
12
+
13
+ If bundler is not being used to manage dependencies, install the gem by executing:
14
+
15
+ $ gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
16
+
17
+ ## Usage
18
+
19
+ You will need a Loops API key to use the package.
20
+
21
+ In your Loops account, go to the [API Settings page](https://app.loops.so/settings?page=api) and click "Generate key".
22
+
23
+ Copy this key and save it in your application code (for example as `LOOPS_API_KEY` in an `.env` file).
24
+
25
+ See the API documentation to learn more about [rate limiting](https://loops.so/docs/api-reference#rate-limiting) and [error handling](https://loops.so/docs/api-reference#debugging).
26
+
27
+ In an initializer, import and configure the SDK:
28
+
29
+ ```ruby
30
+ # config/initializers/loops.rb
31
+
32
+ require "loops_sdk"
33
+
34
+ LoopsSdk.configure do |config|
35
+ config.api_key = 'your_api_key'
36
+ end
37
+ ```
38
+
39
+ ```ruby
40
+ begin
41
+
42
+ response = LoopsSdk::Transactional.send(
43
+ transactional_id: "closfz8ui02yq......",
44
+ email: "dan@loops.so",
45
+ data_variables: {
46
+ loginUrl: "https://app.domain.com/login?code=1234567890"
47
+ }
48
+ )
49
+
50
+ render json: response
51
+
52
+ rescue LoopsSdk::APIError => e
53
+ # Do something if there is an error from the API
54
+ end
55
+ ```
56
+
57
+ ## Contributing
58
+
59
+ Bug reports and pull requests are welcome on GitHub at https://github.com/Loops-so/loops-rb.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rubocop/rake_task"
5
+
6
+ RuboCop::RakeTask.new
7
+
8
+ task default: :rubocop
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LoopsSdk
4
+ class Base
5
+ class << self
6
+ private
7
+
8
+ def handle_response(response)
9
+ case response.status
10
+ when 200
11
+ JSON.parse(response.body)
12
+ when 400, 404, 405, 409, 500
13
+ raise APIError.new(response.status, response.body)
14
+ else
15
+ raise APIError.new(response.status, "Unexpected error occurred")
16
+ end
17
+ end
18
+
19
+ def make_request(method, path, params = {}, body = nil)
20
+ response = LoopsSdk.configuration.connection.send(method, path, params) do |req|
21
+ req.body = body.to_json if body
22
+ end
23
+ handle_response(response)
24
+ end
25
+ end
26
+ end
27
+
28
+ # The `APIError` class in Ruby represents an error that occurs during an API request with specific
29
+ # status and response body information.
30
+ class APIError < StandardError
31
+ attr_reader :status, :body
32
+
33
+ def initialize(status, body)
34
+ @status = status
35
+ @body = body
36
+ super("API request failed with status #{status}: #{body}")
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "faraday"
4
+
5
+ module LoopsSdk
6
+ class Configuration
7
+ attr_accessor :api_key
8
+
9
+ def connection
10
+ @connection ||= Faraday.new(url: "https://app.loops.so/api/") do |faraday|
11
+ faraday.adapter Faraday.default_adapter
12
+ faraday.headers["Authorization"] = "Bearer #{api_key}"
13
+ faraday.headers["Content-Type"] = "application/json"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LoopsSdk
4
+ class Contacts < Base
5
+ class << self
6
+ def create(email:, properties: {}, mailing_lists: {})
7
+ contact_data = {
8
+ email: email,
9
+ mailingLists: mailing_lists
10
+ }.merge(properties.compact).compact
11
+ make_request(:post, "v1/contacts/create", {}, contact_data)
12
+ end
13
+
14
+ def update(email:, properties: {}, mailing_lists: {})
15
+ contact_data = {
16
+ email: email,
17
+ mailingLists: mailing_lists
18
+ }.merge(properties.compact).compact
19
+ make_request(:put, "v1/contacts/update", {}, contact_data)
20
+ end
21
+
22
+ def find(email: nil, user_id: nil)
23
+ raise ArgumentError, "Only one parameter is permitted." if email && user_id
24
+ raise ArgumentError, "You must provide an email or user_id value." if email.nil? && user_id.nil?
25
+
26
+ params = email ? { email: email } : { userId: user_id }
27
+ make_request(:get, "v1/contacts/find", params)
28
+ end
29
+
30
+ def delete(email: nil, user_id: nil)
31
+ raise ArgumentError, "Only one parameter is permitted." if email && user_id
32
+ raise ArgumentError, "You must provide an email or user_id value." if email.nil? && user_id.nil?
33
+
34
+ body = email ? { email: email } : { userId: user_id }
35
+ make_request(:post, "v1/contacts/delete", {}, body)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LoopsSdk
4
+ class CustomFields < Base
5
+ class << self
6
+ def list
7
+ make_request(:get, "v1/customFields")
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LoopsSdk
4
+ class Events < Base
5
+ class << self
6
+ def send(event_name:, email: nil, user_id: nil, contact_properties: {}, event_properties: {}, mailing_lists: {})
7
+ raise ArgumentError, "You must provide an email or user_id value." if email.nil? && user_id.nil?
8
+
9
+ event_data = {
10
+ email: email,
11
+ userId: user_id,
12
+ eventName: event_name,
13
+ eventProperties: event_properties.compact,
14
+ mailingLists: mailing_lists.compact
15
+ }.merge(contact_properties.compact).compact
16
+ make_request(:post, "v1/events/send", {}, event_data)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LoopsSdk
4
+ class MailingLists < Base
5
+ class << self
6
+ def list
7
+ make_request(:get, "v1/lists")
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LoopsSdk
4
+ class Transactional < Base
5
+ class << self
6
+ def send(transactional_id:, email:, add_to_audience: false, data_variables: {}, attachments: [])
7
+ attachments = attachments.map do |attachment|
8
+ attachment.transform_keys { |key| key == :content_type ? :contentType : key }
9
+ end
10
+ email_data = {
11
+ transactionalId: transactional_id,
12
+ email: email,
13
+ addToAudience: add_to_audience,
14
+ dataVariables: data_variables,
15
+ attachments: attachments
16
+ }.compact
17
+ make_request(:post, "v1/transactional", {}, email_data)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LoopsSdk
4
+ VERSION = "0.1.0"
5
+ end
data/lib/loops_sdk.rb ADDED
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "faraday"
4
+ require "json"
5
+ require_relative "loops_sdk/version"
6
+ require_relative "loops_sdk/configuration"
7
+ require_relative "loops_sdk/base"
8
+ require_relative "loops_sdk/contacts"
9
+ require_relative "loops_sdk/events"
10
+ require_relative "loops_sdk/mailing_lists"
11
+ require_relative "loops_sdk/transactional"
12
+ require_relative "loops_sdk/custom_fields"
13
+
14
+ module LoopsSdk
15
+ class << self
16
+ attr_accessor :configuration
17
+ end
18
+
19
+ def self.configure
20
+ self.configuration ||= Configuration.new
21
+ yield(configuration)
22
+ end
23
+ end
data/sig/loops_sdk.rbs ADDED
@@ -0,0 +1,4 @@
1
+ module LoopsSdk
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: loops_sdk
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Dan Rowden
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-08-16 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: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: A Ruby wrapper for interacting with the Loops API.
28
+ email:
29
+ - dan@loops.so
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - ".rubocop.yml"
35
+ - CHANGELOG.md
36
+ - LICENSE.txt
37
+ - README.md
38
+ - Rakefile
39
+ - lib/loops_sdk.rb
40
+ - lib/loops_sdk/base.rb
41
+ - lib/loops_sdk/configuration.rb
42
+ - lib/loops_sdk/contacts.rb
43
+ - lib/loops_sdk/custom_fields.rb
44
+ - lib/loops_sdk/events.rb
45
+ - lib/loops_sdk/mailing_lists.rb
46
+ - lib/loops_sdk/transactional.rb
47
+ - lib/loops_sdk/version.rb
48
+ - sig/loops_sdk.rbs
49
+ homepage: https://loops.so/docs/api-reference
50
+ licenses:
51
+ - MIT
52
+ metadata:
53
+ allowed_push_host: https://rubygems.org
54
+ homepage_uri: https://loops.so/docs/api-reference
55
+ source_code_uri: https://github.com/Loops-so/loops-rb
56
+ post_install_message:
57
+ rdoc_options: []
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: 3.0.0
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ requirements: []
71
+ rubygems_version: 3.5.11
72
+ signing_key:
73
+ specification_version: 4
74
+ summary: The official Ruby SDK for Loops.
75
+ test_files: []