laneful-ruby 1.0.1 → 1.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 +4 -4
- data/lib/laneful/models.rb +3 -2
- data/lib/laneful/version.rb +1 -1
- data/lib/laneful/webhooks.rb +134 -5
- data/lib/laneful.rb +1 -1
- metadata +2 -12
- data/.rubocop.yml +0 -31
- data/LICENSE +0 -21
- data/Makefile +0 -49
- data/README.md +0 -456
- data/Rakefile +0 -8
- data/examples/Gemfile +0 -5
- data/examples/README.md +0 -53
- data/examples/simple_example.rb +0 -121
- data/laneful-ruby.gemspec +0 -38
- data/scripts/publish.sh +0 -169
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4cebf80375fe3b41ce712f115c4e291c6f7ff0a9ceb4cf90de829422966b970b
|
4
|
+
data.tar.gz: 7fee98bf4a843ffe95123f1c544545760fd4f943651199619b93450e37c7727e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 11e4cea266db6d53a73958d9bf4b6a4106c31fe1cb7bcba62f52959444fc9c70d2b2432906bb4c540365b0edbe76af09d4f55a80f84a1f16445595d0f8242cce
|
7
|
+
data.tar.gz: 0f94b21d5267eb709cbada7cca3225f2eb4a6cebdfa694a2d63caec3d2fc7a7bf3f375e564cbedec8632fd08c91b0546a883175a9d591661c759bf562de82270
|
data/lib/laneful/models.rb
CHANGED
@@ -124,12 +124,13 @@ module Laneful
|
|
124
124
|
|
125
125
|
# Creates an attachment from a hash representation
|
126
126
|
def self.from_hash(data)
|
127
|
-
|
127
|
+
filename = data['file_name'] || data['filename'] # Support both field names
|
128
|
+
new(filename, data['content_type'], data['content'])
|
128
129
|
end
|
129
130
|
|
130
131
|
def to_hash
|
131
132
|
{
|
132
|
-
'
|
133
|
+
'file_name' => filename,
|
133
134
|
'content_type' => content_type,
|
134
135
|
'content' => content
|
135
136
|
}
|
data/lib/laneful/version.rb
CHANGED
data/lib/laneful/webhooks.rb
CHANGED
@@ -1,31 +1,116 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'json'
|
4
|
+
require 'openssl'
|
5
|
+
|
3
6
|
module Laneful
|
4
|
-
# Utility class for verifying webhook signatures
|
7
|
+
# Utility class for verifying webhook signatures and processing webhook payloads
|
5
8
|
class WebhookVerifier
|
6
9
|
ALGORITHM = 'sha256'
|
10
|
+
SIGNATURE_PREFIX = 'sha256='
|
11
|
+
SIGNATURE_HEADER_NAME = 'x-webhook-signature'
|
12
|
+
|
13
|
+
# Valid event types as documented
|
14
|
+
VALID_EVENT_TYPES = %w[
|
15
|
+
delivery open click drop spam_complaint unsubscribe bounce
|
16
|
+
].freeze
|
7
17
|
|
8
|
-
#
|
18
|
+
# UUID pattern for lane_id validation
|
19
|
+
UUID_PATTERN = /\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/i
|
20
|
+
|
21
|
+
# Verifies a webhook signature with support for sha256= prefix
|
22
|
+
# @param secret [String] The webhook secret
|
23
|
+
# @param payload [String] The webhook payload
|
24
|
+
# @param signature [String] The signature to verify (may include 'sha256=' prefix)
|
25
|
+
# @return [Boolean] true if the signature is valid, false otherwise
|
9
26
|
def self.verify_signature(secret, payload, signature)
|
10
27
|
return false if secret.nil? || secret.strip.empty?
|
11
28
|
return false if payload.nil?
|
12
29
|
return false if signature.nil? || signature.strip.empty?
|
13
30
|
|
31
|
+
# Handle sha256= prefix as documented
|
32
|
+
clean_signature = if signature.start_with?(SIGNATURE_PREFIX)
|
33
|
+
signature[SIGNATURE_PREFIX.length..]
|
34
|
+
else
|
35
|
+
signature
|
36
|
+
end
|
37
|
+
|
14
38
|
expected_signature = generate_signature(secret, payload)
|
15
|
-
secure_compare?(expected_signature,
|
39
|
+
secure_compare?(expected_signature, clean_signature)
|
16
40
|
rescue StandardError
|
17
41
|
false
|
18
42
|
end
|
19
43
|
|
20
44
|
# Generates a signature for the given payload
|
21
|
-
|
45
|
+
# @param secret [String] The webhook secret
|
46
|
+
# @param payload [String] The payload to sign
|
47
|
+
# @param include_prefix [Boolean] Whether to include the 'sha256=' prefix
|
48
|
+
# @return [String] The generated signature
|
49
|
+
def self.generate_signature(secret, payload, include_prefix: false)
|
22
50
|
digest = OpenSSL::Digest.new(ALGORITHM)
|
23
51
|
hmac = OpenSSL::HMAC.new(secret, digest)
|
24
52
|
hmac.update(payload)
|
25
|
-
hmac.hexdigest
|
53
|
+
signature = hmac.hexdigest
|
54
|
+
include_prefix ? "#{SIGNATURE_PREFIX}#{signature}" : signature
|
55
|
+
end
|
56
|
+
|
57
|
+
# Parse and validate webhook payload structure
|
58
|
+
# @param payload [String] The raw webhook payload JSON
|
59
|
+
# @return [Hash] Hash containing :is_batch boolean and :events array
|
60
|
+
# @raise [ArgumentError] If payload is invalid JSON or structure
|
61
|
+
def self.parse_webhook_payload(payload)
|
62
|
+
raise ArgumentError, 'Payload cannot be empty' if payload.nil? || payload.strip.empty?
|
63
|
+
|
64
|
+
data = JSON.parse(payload)
|
65
|
+
|
66
|
+
if data.is_a?(Array)
|
67
|
+
# Batch mode: array of events
|
68
|
+
events = data.map { |event| validate_and_parse_event(event) }
|
69
|
+
{ is_batch: true, events: events }
|
70
|
+
elsif data.is_a?(Hash) && data.key?('event')
|
71
|
+
# Single event mode
|
72
|
+
event = validate_and_parse_event(data)
|
73
|
+
{ is_batch: false, events: [event] }
|
74
|
+
else
|
75
|
+
raise ArgumentError, 'Invalid webhook payload structure'
|
76
|
+
end
|
77
|
+
rescue JSON::ParserError => e
|
78
|
+
raise ArgumentError, "Invalid JSON payload: #{e.message}"
|
79
|
+
end
|
80
|
+
|
81
|
+
# Get the webhook header name as documented
|
82
|
+
# @return [String] The correct header name for webhook signatures
|
83
|
+
def self.signature_header_name
|
84
|
+
SIGNATURE_HEADER_NAME
|
85
|
+
end
|
86
|
+
|
87
|
+
# Extract webhook signature from HTTP headers (supports multiple formats)
|
88
|
+
# @param headers [Hash] HTTP headers hash
|
89
|
+
# @return [String, nil] The webhook signature or nil if not found
|
90
|
+
def self.extract_signature_from_headers(headers)
|
91
|
+
return nil if headers.nil?
|
92
|
+
|
93
|
+
# Try documented header name first
|
94
|
+
signature = headers[SIGNATURE_HEADER_NAME]
|
95
|
+
return signature if signature
|
96
|
+
|
97
|
+
# Try uppercase version
|
98
|
+
upper_header = SIGNATURE_HEADER_NAME.upcase.tr('-', '_')
|
99
|
+
signature = headers[upper_header]
|
100
|
+
return signature if signature
|
101
|
+
|
102
|
+
# Try with HTTP_ prefix (common in Rack environments)
|
103
|
+
server_header = "HTTP_#{upper_header}"
|
104
|
+
signature = headers[server_header]
|
105
|
+
return signature if signature
|
106
|
+
|
107
|
+
nil
|
26
108
|
end
|
27
109
|
|
28
110
|
# Compares two strings in constant time to prevent timing attacks
|
111
|
+
# @param str_a [String] First string
|
112
|
+
# @param str_b [String] Second string
|
113
|
+
# @return [Boolean] true if strings are equal, false otherwise
|
29
114
|
def self.secure_compare?(str_a, str_b)
|
30
115
|
return false unless str_a.bytesize == str_b.bytesize
|
31
116
|
|
@@ -34,5 +119,49 @@ module Laneful
|
|
34
119
|
str_b.each_byte { |byte| res |= byte ^ l.shift }
|
35
120
|
res.zero?
|
36
121
|
end
|
122
|
+
|
123
|
+
# Validate individual event structure according to documentation
|
124
|
+
# @param event [Hash] The event data
|
125
|
+
# @return [Hash] Parsed event hash
|
126
|
+
# @raise [ArgumentError] If event structure is invalid
|
127
|
+
def self.validate_and_parse_event(event)
|
128
|
+
raise ArgumentError, 'Event must be a hash' unless event.is_a?(Hash)
|
129
|
+
|
130
|
+
# Required fields
|
131
|
+
required_fields = %w[event email lane_id message_id timestamp]
|
132
|
+
required_fields.each do |field|
|
133
|
+
raise ArgumentError, "Missing required field: #{field}" unless event.key?(field)
|
134
|
+
end
|
135
|
+
|
136
|
+
# Validate event type
|
137
|
+
event_type = event['event']
|
138
|
+
raise ArgumentError, "Invalid event type: #{event_type}" unless VALID_EVENT_TYPES.include?(event_type)
|
139
|
+
|
140
|
+
# Validate email format
|
141
|
+
email = event['email']
|
142
|
+
raise ArgumentError, "Invalid email format: #{email}" unless valid_email?(email)
|
143
|
+
|
144
|
+
# Validate timestamp is numeric
|
145
|
+
timestamp = event['timestamp']
|
146
|
+
begin
|
147
|
+
Integer(timestamp)
|
148
|
+
rescue ArgumentError, TypeError
|
149
|
+
raise ArgumentError, 'Invalid timestamp format'
|
150
|
+
end
|
151
|
+
|
152
|
+
# Validate lane_id is a valid UUID format
|
153
|
+
lane_id = event['lane_id']
|
154
|
+
raise ArgumentError, "Invalid lane_id format: #{lane_id}" unless UUID_PATTERN.match?(lane_id)
|
155
|
+
|
156
|
+
# Return event with all fields (required + optional)
|
157
|
+
event
|
158
|
+
end
|
159
|
+
|
160
|
+
# Simple email validation
|
161
|
+
# @param email [String] The email to validate
|
162
|
+
# @return [Boolean] true if email format is valid
|
163
|
+
def self.valid_email?(email)
|
164
|
+
email.is_a?(String) && email.include?('@') && email.include?('.')
|
165
|
+
end
|
37
166
|
end
|
38
167
|
end
|
data/lib/laneful.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: laneful-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Laneful Team
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-09-
|
11
|
+
date: 2025-09-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: httparty
|
@@ -46,22 +46,12 @@ executables: []
|
|
46
46
|
extensions: []
|
47
47
|
extra_rdoc_files: []
|
48
48
|
files:
|
49
|
-
- ".rubocop.yml"
|
50
|
-
- LICENSE
|
51
|
-
- Makefile
|
52
|
-
- README.md
|
53
|
-
- Rakefile
|
54
|
-
- examples/Gemfile
|
55
|
-
- examples/README.md
|
56
|
-
- examples/simple_example.rb
|
57
|
-
- laneful-ruby.gemspec
|
58
49
|
- lib/laneful.rb
|
59
50
|
- lib/laneful/client.rb
|
60
51
|
- lib/laneful/exceptions.rb
|
61
52
|
- lib/laneful/models.rb
|
62
53
|
- lib/laneful/version.rb
|
63
54
|
- lib/laneful/webhooks.rb
|
64
|
-
- scripts/publish.sh
|
65
55
|
homepage: https://github.com/laneful/laneful-ruby
|
66
56
|
licenses:
|
67
57
|
- MIT
|
data/.rubocop.yml
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
AllCops:
|
2
|
-
NewCops: enable
|
3
|
-
TargetRubyVersion: 3.0
|
4
|
-
SuggestExtensions: false
|
5
|
-
|
6
|
-
# Disable some strict rules for test files and gemspec
|
7
|
-
Metrics/BlockLength:
|
8
|
-
Exclude:
|
9
|
-
- 'spec/**/*'
|
10
|
-
- '*.gemspec'
|
11
|
-
|
12
|
-
Metrics/MethodLength:
|
13
|
-
Max: 30
|
14
|
-
|
15
|
-
Metrics/ClassLength:
|
16
|
-
Max: 150
|
17
|
-
|
18
|
-
Metrics/AbcSize:
|
19
|
-
Max: 80
|
20
|
-
|
21
|
-
Metrics/CyclomaticComplexity:
|
22
|
-
Max: 40
|
23
|
-
|
24
|
-
Metrics/PerceivedComplexity:
|
25
|
-
Max: 40
|
26
|
-
|
27
|
-
Metrics/ParameterLists:
|
28
|
-
Max: 5
|
29
|
-
|
30
|
-
Layout/LineLength:
|
31
|
-
Max: 120
|
data/LICENSE
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
MIT License
|
2
|
-
|
3
|
-
Copyright (c) 2024 Laneful
|
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 all
|
13
|
-
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 THE
|
21
|
-
SOFTWARE.
|
data/Makefile
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
# Laneful Ruby SDK Makefile
|
2
|
-
|
3
|
-
.PHONY: help test lint build publish clean install setup
|
4
|
-
|
5
|
-
# Default target
|
6
|
-
help:
|
7
|
-
@echo "Available commands:"
|
8
|
-
@echo " setup - Install dependencies"
|
9
|
-
@echo " test - Run tests"
|
10
|
-
@echo " lint - Run code linting"
|
11
|
-
@echo " build - Build the gem"
|
12
|
-
@echo " publish - Publish to RubyGems (requires RUBYGEMS_API_KEY)"
|
13
|
-
@echo " install - Install gem locally"
|
14
|
-
@echo " clean - Clean up built gems"
|
15
|
-
|
16
|
-
# Install dependencies
|
17
|
-
setup:
|
18
|
-
bundle install
|
19
|
-
|
20
|
-
# Run tests
|
21
|
-
test:
|
22
|
-
bundle exec rspec
|
23
|
-
|
24
|
-
# Run linting
|
25
|
-
lint:
|
26
|
-
bundle exec rubocop
|
27
|
-
|
28
|
-
# Build gem
|
29
|
-
build:
|
30
|
-
gem build laneful-ruby.gemspec
|
31
|
-
|
32
|
-
# Publish to RubyGems
|
33
|
-
publish:
|
34
|
-
@if [ -z "$$GEM_HOST_API_KEY" ]; then \
|
35
|
-
echo "Error: GEM_HOST_API_KEY environment variable is not set"; \
|
36
|
-
echo "Please set your RubyGems API key: export GEM_HOST_API_KEY=your_api_key_here"; \
|
37
|
-
exit 1; \
|
38
|
-
fi
|
39
|
-
./scripts/publish.sh
|
40
|
-
|
41
|
-
# Install gem locally
|
42
|
-
install:
|
43
|
-
gem build laneful-ruby.gemspec
|
44
|
-
gem install laneful-ruby-*.gem
|
45
|
-
|
46
|
-
# Clean up
|
47
|
-
clean:
|
48
|
-
rm -f laneful-ruby-*.gem
|
49
|
-
|
data/README.md
DELETED
@@ -1,456 +0,0 @@
|
|
1
|
-
# Laneful Ruby SDK
|
2
|
-
|
3
|
-
A modern Ruby client library for the Laneful email API with support for sending emails, templates, tracking, and webhooks.
|
4
|
-
|
5
|
-
## Requirements
|
6
|
-
|
7
|
-
- Ruby 3.0 or higher
|
8
|
-
- Bundler (for dependency management)
|
9
|
-
|
10
|
-
## Installation
|
11
|
-
|
12
|
-
### Using Bundler
|
13
|
-
|
14
|
-
Add the following to your `Gemfile`:
|
15
|
-
|
16
|
-
```ruby
|
17
|
-
gem 'laneful-ruby'
|
18
|
-
```
|
19
|
-
|
20
|
-
Then run:
|
21
|
-
|
22
|
-
```bash
|
23
|
-
bundle install
|
24
|
-
```
|
25
|
-
|
26
|
-
### Manual Installation
|
27
|
-
|
28
|
-
```bash
|
29
|
-
git clone https://github.com/lanefulhq/laneful-ruby.git
|
30
|
-
cd laneful-ruby
|
31
|
-
bundle install
|
32
|
-
bundle exec rake install
|
33
|
-
```
|
34
|
-
|
35
|
-
## Quick Start
|
36
|
-
|
37
|
-
```ruby
|
38
|
-
require 'laneful'
|
39
|
-
|
40
|
-
# Create client
|
41
|
-
client = Laneful::Client.new(
|
42
|
-
'https://your-endpoint.send.laneful.net',
|
43
|
-
'your-auth-token'
|
44
|
-
)
|
45
|
-
|
46
|
-
# Create email
|
47
|
-
email = Laneful::Email::Builder.new
|
48
|
-
.from(Laneful::Address.new('sender@example.com', 'Your Name'))
|
49
|
-
.to(Laneful::Address.new('recipient@example.com', 'Recipient Name'))
|
50
|
-
.subject('Hello from Laneful Ruby SDK!')
|
51
|
-
.text_content('This is a simple test email.')
|
52
|
-
.build
|
53
|
-
|
54
|
-
# Send email
|
55
|
-
response = client.send_email(email)
|
56
|
-
puts "Email sent successfully!"
|
57
|
-
```
|
58
|
-
|
59
|
-
## Features
|
60
|
-
|
61
|
-
- Send single or multiple emails
|
62
|
-
- Plain text and HTML content
|
63
|
-
- Email templates with dynamic data
|
64
|
-
- File attachments
|
65
|
-
- Email tracking (opens, clicks, unsubscribes)
|
66
|
-
- Custom headers and reply-to addresses
|
67
|
-
- Scheduled sending
|
68
|
-
- Webhook signature verification
|
69
|
-
- Comprehensive error handling
|
70
|
-
- Modern Ruby 3.0+ features
|
71
|
-
|
72
|
-
## Examples
|
73
|
-
|
74
|
-
### Simple Text Email
|
75
|
-
|
76
|
-
```ruby
|
77
|
-
email = Laneful::Email::Builder.new
|
78
|
-
.from(Laneful::Address.new('sender@example.com'))
|
79
|
-
.to(Laneful::Address.new('user@example.com'))
|
80
|
-
.subject('Simple Email')
|
81
|
-
.text_content('This is a simple text email.')
|
82
|
-
.build
|
83
|
-
|
84
|
-
response = client.send_email(email)
|
85
|
-
```
|
86
|
-
|
87
|
-
### HTML Email with Tracking
|
88
|
-
|
89
|
-
```ruby
|
90
|
-
tracking = Laneful::TrackingSettings.new(opens: true, clicks: true, unsubscribes: false)
|
91
|
-
|
92
|
-
email = Laneful::Email::Builder.new
|
93
|
-
.from(Laneful::Address.new('sender@example.com'))
|
94
|
-
.to(Laneful::Address.new('user@example.com'))
|
95
|
-
.subject('HTML Email with Tracking')
|
96
|
-
.html_content('<h1>Welcome!</h1><p>This is an <strong>HTML email</strong> with tracking enabled.</p>')
|
97
|
-
.text_content('Welcome! This is an HTML email with tracking enabled.')
|
98
|
-
.tracking(tracking)
|
99
|
-
.build
|
100
|
-
|
101
|
-
response = client.send_email(email)
|
102
|
-
```
|
103
|
-
|
104
|
-
### Template Email
|
105
|
-
|
106
|
-
```ruby
|
107
|
-
email = Laneful::Email::Builder.new
|
108
|
-
.from(Laneful::Address.new('sender@example.com'))
|
109
|
-
.to(Laneful::Address.new('user@example.com'))
|
110
|
-
.template_id('welcome-template')
|
111
|
-
.template_data({
|
112
|
-
'name' => 'John Doe',
|
113
|
-
'company' => 'Acme Corp'
|
114
|
-
})
|
115
|
-
.build
|
116
|
-
|
117
|
-
response = client.send_email(email)
|
118
|
-
```
|
119
|
-
|
120
|
-
### Email with Attachments
|
121
|
-
|
122
|
-
```ruby
|
123
|
-
# Create attachment from file
|
124
|
-
attachment = Laneful::Attachment.from_file('/path/to/document.pdf')
|
125
|
-
|
126
|
-
email = Laneful::Email::Builder.new
|
127
|
-
.from(Laneful::Address.new('sender@example.com'))
|
128
|
-
.to(Laneful::Address.new('user@example.com'))
|
129
|
-
.subject('Document Attached')
|
130
|
-
.text_content('Please find the document attached.')
|
131
|
-
.attachment(attachment)
|
132
|
-
.build
|
133
|
-
|
134
|
-
response = client.send_email(email)
|
135
|
-
```
|
136
|
-
|
137
|
-
### Multiple Recipients
|
138
|
-
|
139
|
-
```ruby
|
140
|
-
email = Laneful::Email::Builder.new
|
141
|
-
.from(Laneful::Address.new('sender@example.com'))
|
142
|
-
.to(Laneful::Address.new('user1@example.com'))
|
143
|
-
.to(Laneful::Address.new('user2@example.com', 'User Two'))
|
144
|
-
.cc(Laneful::Address.new('cc@example.com'))
|
145
|
-
.bcc(Laneful::Address.new('bcc@example.com'))
|
146
|
-
.subject('Multiple Recipients')
|
147
|
-
.text_content('This email has multiple recipients.')
|
148
|
-
.build
|
149
|
-
|
150
|
-
response = client.send_email(email)
|
151
|
-
```
|
152
|
-
|
153
|
-
### Scheduled Email
|
154
|
-
|
155
|
-
```ruby
|
156
|
-
# Schedule for 24 hours from now
|
157
|
-
send_time = Time.now.to_i + (24 * 60 * 60)
|
158
|
-
|
159
|
-
email = Laneful::Email::Builder.new
|
160
|
-
.from(Laneful::Address.new('sender@example.com'))
|
161
|
-
.to(Laneful::Address.new('user@example.com'))
|
162
|
-
.subject('Scheduled Email')
|
163
|
-
.text_content('This email was scheduled.')
|
164
|
-
.send_time(send_time)
|
165
|
-
.build
|
166
|
-
|
167
|
-
response = client.send_email(email)
|
168
|
-
```
|
169
|
-
|
170
|
-
### Multiple Emails
|
171
|
-
|
172
|
-
```ruby
|
173
|
-
emails = [
|
174
|
-
Laneful::Email::Builder.new
|
175
|
-
.from(Laneful::Address.new('sender@example.com'))
|
176
|
-
.to(Laneful::Address.new('user1@example.com'))
|
177
|
-
.subject('Email 1')
|
178
|
-
.text_content('First email content.')
|
179
|
-
.build,
|
180
|
-
Laneful::Email::Builder.new
|
181
|
-
.from(Laneful::Address.new('sender@example.com'))
|
182
|
-
.to(Laneful::Address.new('user2@example.com'))
|
183
|
-
.subject('Email 2')
|
184
|
-
.text_content('Second email content.')
|
185
|
-
.build
|
186
|
-
]
|
187
|
-
|
188
|
-
response = client.send_emails(emails)
|
189
|
-
```
|
190
|
-
|
191
|
-
### Custom Timeout
|
192
|
-
|
193
|
-
```ruby
|
194
|
-
client = Laneful::Client.new(
|
195
|
-
'https://your-endpoint.send.laneful.net',
|
196
|
-
'your-auth-token',
|
197
|
-
timeout: 60 # 60 second timeout
|
198
|
-
)
|
199
|
-
```
|
200
|
-
|
201
|
-
## Webhook Verification
|
202
|
-
|
203
|
-
```ruby
|
204
|
-
# In your webhook handler
|
205
|
-
payload = request.body.read
|
206
|
-
signature = request.headers['X-Laneful-Signature']
|
207
|
-
secret = 'your-webhook-secret'
|
208
|
-
|
209
|
-
if Laneful::WebhookVerifier.verify_signature(secret, payload, signature)
|
210
|
-
# Process webhook data
|
211
|
-
data = JSON.parse(payload)
|
212
|
-
# Handle webhook event
|
213
|
-
else
|
214
|
-
# Invalid signature
|
215
|
-
head :unauthorized
|
216
|
-
end
|
217
|
-
```
|
218
|
-
|
219
|
-
## Error Handling
|
220
|
-
|
221
|
-
```ruby
|
222
|
-
begin
|
223
|
-
response = client.send_email(email)
|
224
|
-
puts "Email sent successfully"
|
225
|
-
rescue Laneful::ValidationException => e
|
226
|
-
puts "Validation error: #{e.message}"
|
227
|
-
rescue Laneful::ApiException => e
|
228
|
-
puts "API error: #{e.message}"
|
229
|
-
puts "Status code: #{e.status_code}"
|
230
|
-
puts "Error message: #{e.error_message}"
|
231
|
-
rescue Laneful::HttpException => e
|
232
|
-
puts "HTTP error: #{e.message}"
|
233
|
-
puts "Status code: #{e.status_code}"
|
234
|
-
rescue StandardError => e
|
235
|
-
puts "Unexpected error: #{e.message}"
|
236
|
-
end
|
237
|
-
```
|
238
|
-
|
239
|
-
## API Reference
|
240
|
-
|
241
|
-
### Laneful::Client
|
242
|
-
|
243
|
-
#### Constructor
|
244
|
-
|
245
|
-
```ruby
|
246
|
-
Laneful::Client.new(base_url, auth_token, timeout: 30)
|
247
|
-
```
|
248
|
-
|
249
|
-
- `base_url` - The base URL of the Laneful API
|
250
|
-
- `auth_token` - The authentication token
|
251
|
-
- `timeout` - Request timeout in seconds (optional, default: 30)
|
252
|
-
|
253
|
-
#### Methods
|
254
|
-
|
255
|
-
- `send_email(email)` - Sends a single email
|
256
|
-
- `send_emails(emails)` - Sends multiple emails
|
257
|
-
|
258
|
-
### Laneful::Email::Builder
|
259
|
-
|
260
|
-
#### Required Fields
|
261
|
-
|
262
|
-
- `from(address)` - Sender address
|
263
|
-
|
264
|
-
#### Optional Fields
|
265
|
-
|
266
|
-
- `to(address)` - Recipient addresses
|
267
|
-
- `cc(address)` - CC addresses
|
268
|
-
- `bcc(address)` - BCC addresses
|
269
|
-
- `subject(subject)` - Email subject
|
270
|
-
- `text_content(content)` - Plain text content
|
271
|
-
- `html_content(content)` - HTML content
|
272
|
-
- `template_id(id)` - Template ID
|
273
|
-
- `template_data(data)` - Template data
|
274
|
-
- `attachment(attachment)` - File attachments
|
275
|
-
- `headers(headers)` - Custom headers
|
276
|
-
- `reply_to(address)` - Reply-to address
|
277
|
-
- `send_time(time)` - Scheduled send time (Unix timestamp)
|
278
|
-
- `webhook_data(data)` - Webhook data
|
279
|
-
- `tag(tag)` - Email tag
|
280
|
-
- `tracking(tracking)` - Tracking settings
|
281
|
-
|
282
|
-
### Laneful::Address
|
283
|
-
|
284
|
-
```ruby
|
285
|
-
Laneful::Address.new(email, name = nil)
|
286
|
-
```
|
287
|
-
|
288
|
-
- `email` - The email address (required)
|
289
|
-
- `name` - The display name (optional)
|
290
|
-
|
291
|
-
### Laneful::Attachment
|
292
|
-
|
293
|
-
```ruby
|
294
|
-
# From file
|
295
|
-
Laneful::Attachment.from_file(file_path)
|
296
|
-
|
297
|
-
# From raw data
|
298
|
-
Laneful::Attachment.new(filename, content_type, content)
|
299
|
-
```
|
300
|
-
|
301
|
-
### Laneful::TrackingSettings
|
302
|
-
|
303
|
-
```ruby
|
304
|
-
Laneful::TrackingSettings.new(opens: false, clicks: false, unsubscribes: false)
|
305
|
-
```
|
306
|
-
|
307
|
-
### Laneful::WebhookVerifier
|
308
|
-
|
309
|
-
```ruby
|
310
|
-
Laneful::WebhookVerifier.verify_signature(secret, payload, signature)
|
311
|
-
```
|
312
|
-
|
313
|
-
## Exception Types
|
314
|
-
|
315
|
-
- `Laneful::ValidationException` - Thrown when input validation fails
|
316
|
-
- `Laneful::ApiException` - Thrown when the API returns an error response
|
317
|
-
- `Laneful::HttpException` - Thrown when HTTP communication fails
|
318
|
-
- `Laneful::LanefulException` - Base exception class for all SDK exceptions
|
319
|
-
|
320
|
-
## Development
|
321
|
-
|
322
|
-
### Running Tests
|
323
|
-
|
324
|
-
```bash
|
325
|
-
bundle exec rspec
|
326
|
-
```
|
327
|
-
|
328
|
-
### Code Quality
|
329
|
-
|
330
|
-
```bash
|
331
|
-
bundle exec rubocop
|
332
|
-
```
|
333
|
-
|
334
|
-
### Documentation
|
335
|
-
|
336
|
-
```bash
|
337
|
-
bundle exec yard doc
|
338
|
-
```
|
339
|
-
|
340
|
-
## Publishing to RubyGems
|
341
|
-
|
342
|
-
This SDK can be published to RubyGems using a simple, automated workflow.
|
343
|
-
|
344
|
-
### Prerequisites
|
345
|
-
|
346
|
-
1. **Ruby 3.0+**: Ensure you have Ruby 3.0 or higher installed
|
347
|
-
2. **Bundler**: Install bundler if not already installed (`gem install bundler`)
|
348
|
-
3. **RubyGems API Key**: Get your API key from [RubyGems.org](https://rubygems.org/settings/edit)
|
349
|
-
|
350
|
-
### Setting up your API Key
|
351
|
-
|
352
|
-
```bash
|
353
|
-
export GEM_HOST_API_KEY=your_api_key_here
|
354
|
-
```
|
355
|
-
|
356
|
-
### Publishing Methods
|
357
|
-
|
358
|
-
#### Method 1: Using the Automated Script (Recommended)
|
359
|
-
|
360
|
-
```bash
|
361
|
-
./scripts/publish.sh
|
362
|
-
```
|
363
|
-
|
364
|
-
This script will:
|
365
|
-
|
366
|
-
- Check Ruby version compatibility
|
367
|
-
- Install dependencies
|
368
|
-
- Run all tests
|
369
|
-
- Perform code linting
|
370
|
-
- Build the gem
|
371
|
-
- Publish to RubyGems
|
372
|
-
- Clean up built gem files
|
373
|
-
|
374
|
-
#### Method 2: Using Make Commands
|
375
|
-
|
376
|
-
**Install dependencies:**
|
377
|
-
|
378
|
-
```bash
|
379
|
-
make setup
|
380
|
-
```
|
381
|
-
|
382
|
-
**Run tests:**
|
383
|
-
|
384
|
-
```bash
|
385
|
-
make test
|
386
|
-
```
|
387
|
-
|
388
|
-
**Run linting:**
|
389
|
-
|
390
|
-
```bash
|
391
|
-
make lint
|
392
|
-
```
|
393
|
-
|
394
|
-
**Build the gem:**
|
395
|
-
|
396
|
-
```bash
|
397
|
-
make build
|
398
|
-
```
|
399
|
-
|
400
|
-
**Publish to RubyGems:**
|
401
|
-
|
402
|
-
```bash
|
403
|
-
make publish
|
404
|
-
```
|
405
|
-
|
406
|
-
#### Method 3: Manual Publishing
|
407
|
-
|
408
|
-
**Install dependencies:**
|
409
|
-
|
410
|
-
```bash
|
411
|
-
bundle install
|
412
|
-
```
|
413
|
-
|
414
|
-
**Run tests:**
|
415
|
-
|
416
|
-
```bash
|
417
|
-
bundle exec rspec
|
418
|
-
```
|
419
|
-
|
420
|
-
**Run linting:**
|
421
|
-
|
422
|
-
```bash
|
423
|
-
bundle exec rubocop
|
424
|
-
```
|
425
|
-
|
426
|
-
**Build the gem:**
|
427
|
-
|
428
|
-
```bash
|
429
|
-
gem build laneful-ruby.gemspec
|
430
|
-
```
|
431
|
-
|
432
|
-
**Publish to RubyGems:**
|
433
|
-
|
434
|
-
```bash
|
435
|
-
gem push laneful-ruby-*.gem
|
436
|
-
```
|
437
|
-
|
438
|
-
### Version Management
|
439
|
-
|
440
|
-
Before publishing, make sure to update the version in `lib/laneful/version.rb`:
|
441
|
-
|
442
|
-
```ruby
|
443
|
-
module Laneful
|
444
|
-
VERSION = "1.0.1".freeze # Update this version
|
445
|
-
end
|
446
|
-
```
|
447
|
-
|
448
|
-
Follow [Semantic Versioning](https://semver.org/) guidelines:
|
449
|
-
|
450
|
-
- **MAJOR** version for incompatible API changes
|
451
|
-
- **MINOR** version for backwards-compatible functionality additions
|
452
|
-
- **PATCH** version for backwards-compatible bug fixes
|
453
|
-
|
454
|
-
## License
|
455
|
-
|
456
|
-
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
data/Rakefile
DELETED
data/examples/Gemfile
DELETED
data/examples/README.md
DELETED
@@ -1,53 +0,0 @@
|
|
1
|
-
# Laneful Ruby SDK Examples
|
2
|
-
|
3
|
-
This directory contains example code demonstrating how to use the Laneful Ruby SDK.
|
4
|
-
|
5
|
-
## Quick Start
|
6
|
-
|
7
|
-
1. **Install the gem:**
|
8
|
-
```bash
|
9
|
-
gem install laneful-ruby
|
10
|
-
```
|
11
|
-
|
12
|
-
2. **Or use Bundler:**
|
13
|
-
```bash
|
14
|
-
cd examples
|
15
|
-
bundle install
|
16
|
-
```
|
17
|
-
|
18
|
-
3. **Configure the example:**
|
19
|
-
Edit `simple_example.rb` and replace the placeholder values:
|
20
|
-
- `base_url`: Your Laneful endpoint URL
|
21
|
-
- `auth_token`: Your authentication token
|
22
|
-
- Email addresses: Replace with your actual email addresses
|
23
|
-
|
24
|
-
4. **Run the example:**
|
25
|
-
```bash
|
26
|
-
ruby simple_example.rb
|
27
|
-
```
|
28
|
-
|
29
|
-
## Example Files
|
30
|
-
|
31
|
-
- **`simple_example.rb`**: Demonstrates basic email sending functionality including:
|
32
|
-
- Simple text email
|
33
|
-
- HTML email with tracking
|
34
|
-
- Email with CC recipients
|
35
|
-
- Error handling
|
36
|
-
|
37
|
-
## Configuration
|
38
|
-
|
39
|
-
Before running the examples, make sure to:
|
40
|
-
|
41
|
-
1. **Get your credentials** from your Laneful dashboard
|
42
|
-
2. **Update the configuration** in the example files:
|
43
|
-
```ruby
|
44
|
-
base_url = 'https://your-endpoint.send.laneful.net'
|
45
|
-
auth_token = 'your-auth-token'
|
46
|
-
```
|
47
|
-
3. **Use valid email addresses** for testing
|
48
|
-
|
49
|
-
## More Examples
|
50
|
-
|
51
|
-
For more comprehensive examples and API documentation, visit:
|
52
|
-
- [Laneful Ruby SDK Documentation](https://docs.laneful.com/ruby)
|
53
|
-
- [GitHub Repository](https://github.com/laneful/laneful-ruby)
|
data/examples/simple_example.rb
DELETED
@@ -1,121 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require 'laneful'
|
5
|
-
|
6
|
-
# Simple example demonstrating basic usage of the Laneful Ruby SDK
|
7
|
-
puts '📧 Laneful Ruby SDK - Simple Example'
|
8
|
-
puts "====================================\n"
|
9
|
-
|
10
|
-
# Configuration - Replace with your actual credentials
|
11
|
-
base_url = 'https://your-endpoint.send.laneful.net'
|
12
|
-
auth_token = 'your-auth-token'
|
13
|
-
|
14
|
-
# Email addresses - Replace with your actual addresses
|
15
|
-
sender_email = 'sender@yourdomain.com'
|
16
|
-
sender_name = 'Your Name'
|
17
|
-
recipient_email = 'recipient@example.com'
|
18
|
-
recipient_name = 'Recipient Name'
|
19
|
-
cc_email = 'cc@example.com'
|
20
|
-
cc_name = 'CC Recipient'
|
21
|
-
|
22
|
-
# Create client
|
23
|
-
begin
|
24
|
-
client = Laneful::Client.new(base_url, auth_token)
|
25
|
-
puts '✅ Client created successfully'
|
26
|
-
rescue Laneful::ValidationException => e
|
27
|
-
puts "❌ Failed to create client: #{e.message}"
|
28
|
-
puts 'Please check your base_url and auth_token configuration.'
|
29
|
-
exit 1
|
30
|
-
end
|
31
|
-
|
32
|
-
# Test 1: Send a simple text email
|
33
|
-
puts "\n📝 Test 1: Sending Simple Text Email"
|
34
|
-
puts '------------------------------------'
|
35
|
-
|
36
|
-
begin
|
37
|
-
email = Laneful::Email::Builder.new
|
38
|
-
.from(Laneful::Address.new(sender_email, sender_name))
|
39
|
-
.to(Laneful::Address.new(recipient_email, recipient_name))
|
40
|
-
.subject('Hello from Laneful Ruby SDK! 🚀')
|
41
|
-
.text_content('Hi! This is a test email sent using the Laneful Ruby SDK. ' \
|
42
|
-
'The SDK is working perfectly!')
|
43
|
-
.tag('ruby-sdk-test')
|
44
|
-
.build
|
45
|
-
|
46
|
-
response = client.send_email(email)
|
47
|
-
puts '✅ Simple email sent successfully!'
|
48
|
-
puts "Response: #{response}"
|
49
|
-
rescue Laneful::ValidationException => e
|
50
|
-
puts "❌ Validation error: #{e.message}"
|
51
|
-
rescue Laneful::ApiException => e
|
52
|
-
puts "❌ API error: #{e.message} (Status: #{e.status_code})"
|
53
|
-
rescue Laneful::HttpException => e
|
54
|
-
puts "❌ HTTP error: #{e.message} (Status: #{e.status_code})"
|
55
|
-
end
|
56
|
-
|
57
|
-
# Test 2: Send an HTML email with CC
|
58
|
-
puts "\n🎨 Test 2: Sending HTML Email with CC"
|
59
|
-
puts '-------------------------------------'
|
60
|
-
|
61
|
-
begin
|
62
|
-
tracking = Laneful::TrackingSettings.new(opens: true, clicks: true, unsubscribes: false)
|
63
|
-
|
64
|
-
email = Laneful::Email::Builder.new
|
65
|
-
.from(Laneful::Address.new(sender_email, sender_name))
|
66
|
-
.to(Laneful::Address.new(recipient_email, recipient_name))
|
67
|
-
.cc(Laneful::Address.new(cc_email, cc_name))
|
68
|
-
.subject('Ruby SDK Test - HTML Email with Tracking 📧')
|
69
|
-
.html_content(<<~HTML)
|
70
|
-
<!DOCTYPE html>
|
71
|
-
<html>
|
72
|
-
<head>
|
73
|
-
<title>Ruby SDK Test</title>
|
74
|
-
</head>
|
75
|
-
<body style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px;">
|
76
|
-
<h1 style="color: #2c3e50;">🎉 Ruby SDK Test Successful!</h1>
|
77
|
-
<p>Hello! This email was sent using the <strong>Laneful Ruby SDK</strong> with modern Ruby features:</p>
|
78
|
-
<ul style="background-color: #f8f9fa; padding: 15px; border-radius: 5px;">
|
79
|
-
<li>✅ Frozen string literals for immutability</li>
|
80
|
-
<li>✅ Keyword arguments for clean APIs</li>
|
81
|
-
<li>✅ Safe navigation operator (&.)</li>
|
82
|
-
<li>✅ Enhanced exception handling</li>
|
83
|
-
<li>✅ Modern Ruby syntax throughout</li>
|
84
|
-
</ul>
|
85
|
-
<p style="color: #7f8c8d;">This email has tracking enabled for opens and clicks.</p>
|
86
|
-
<hr style="border: none; border-top: 1px solid #eee; margin: 20px 0;">
|
87
|
-
<p style="font-size: 12px; color: #95a5a6;">
|
88
|
-
Sent from: #{sender_email}<br>
|
89
|
-
To: #{recipient_email}<br>
|
90
|
-
CC: #{cc_email}
|
91
|
-
</p>
|
92
|
-
</body>
|
93
|
-
</html>
|
94
|
-
HTML
|
95
|
-
.text_content('Ruby SDK Test Successful! Hello! This email was sent using ' \
|
96
|
-
'the Laneful Ruby SDK with modern Ruby features including ' \
|
97
|
-
'frozen string literals, keyword arguments, safe navigation ' \
|
98
|
-
'operator, and enhanced exception handling. This email has ' \
|
99
|
-
'tracking enabled for opens and clicks.')
|
100
|
-
.tracking(tracking)
|
101
|
-
.tag('html-cc-test')
|
102
|
-
.build
|
103
|
-
|
104
|
-
response = client.send_email(email)
|
105
|
-
puts '✅ HTML email with CC sent successfully!'
|
106
|
-
puts "Response: #{response}"
|
107
|
-
rescue Laneful::ValidationException => e
|
108
|
-
puts "❌ Validation error: #{e.message}"
|
109
|
-
rescue Laneful::ApiException => e
|
110
|
-
puts "❌ API error: #{e.message} (Status: #{e.status_code})"
|
111
|
-
rescue Laneful::HttpException => e
|
112
|
-
puts "❌ HTTP error: #{e.message} (Status: #{e.status_code})"
|
113
|
-
end
|
114
|
-
|
115
|
-
puts "\n🎉 Tests completed!"
|
116
|
-
puts "\n📋 Summary:"
|
117
|
-
puts ' • Ruby SDK is working correctly'
|
118
|
-
puts ' • Real API endpoint is accessible'
|
119
|
-
puts ' • Email building and sending functionality is operational'
|
120
|
-
puts ' • Error handling is working properly'
|
121
|
-
puts "\n💡 Check your email inboxes for the test emails!"
|
data/laneful-ruby.gemspec
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'lib/laneful/version'
|
4
|
-
|
5
|
-
Gem::Specification.new do |spec|
|
6
|
-
spec.name = 'laneful-ruby'
|
7
|
-
spec.version = Laneful::VERSION
|
8
|
-
spec.authors = ['Laneful Team']
|
9
|
-
spec.email = ['support@laneful.com']
|
10
|
-
|
11
|
-
spec.summary = 'Ruby SDK for the Laneful email API'
|
12
|
-
spec.description = 'A modern Ruby client library for the Laneful email API, ' \
|
13
|
-
'providing easy integration for email sending, webhooks, and analytics.'
|
14
|
-
spec.homepage = 'https://github.com/laneful/laneful-ruby'
|
15
|
-
spec.license = 'MIT'
|
16
|
-
spec.required_ruby_version = '>= 3.0.0'
|
17
|
-
|
18
|
-
spec.metadata['homepage_uri'] = spec.homepage
|
19
|
-
spec.metadata['source_code_uri'] = 'https://github.com/laneful/laneful-ruby'
|
20
|
-
spec.metadata['changelog_uri'] = 'https://github.com/laneful/laneful-ruby/blob/main/CHANGELOG.md'
|
21
|
-
spec.metadata['documentation_uri'] = 'https://docs.laneful.com/ruby'
|
22
|
-
spec.metadata['rubygems_mfa_required'] = 'true'
|
23
|
-
|
24
|
-
# Specify which files should be added to the gem when it is released.
|
25
|
-
spec.files = Dir.chdir(__dir__) do
|
26
|
-
`git ls-files -z`.split("\x0").reject do |f|
|
27
|
-
(File.expand_path(f) == __FILE__) ||
|
28
|
-
f.start_with?(*%w[bin/ test/ spec/ features/ .git appveyor Gemfile])
|
29
|
-
end
|
30
|
-
end
|
31
|
-
spec.bindir = 'exe'
|
32
|
-
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
33
|
-
spec.require_paths = ['lib']
|
34
|
-
|
35
|
-
# Dependencies
|
36
|
-
spec.add_dependency 'httparty', '~> 0.21'
|
37
|
-
spec.add_dependency 'json', '~> 2.6'
|
38
|
-
end
|
data/scripts/publish.sh
DELETED
@@ -1,169 +0,0 @@
|
|
1
|
-
#!/bin/bash
|
2
|
-
|
3
|
-
# Laneful Ruby SDK Publishing Script
|
4
|
-
# This script handles the complete publishing workflow to RubyGems
|
5
|
-
|
6
|
-
set -e
|
7
|
-
|
8
|
-
# Colors for output
|
9
|
-
RED='\033[0;31m'
|
10
|
-
GREEN='\033[0;32m'
|
11
|
-
YELLOW='\033[1;33m'
|
12
|
-
BLUE='\033[0;34m'
|
13
|
-
NC='\033[0m' # No Color
|
14
|
-
|
15
|
-
# Function to print colored output
|
16
|
-
print_status() {
|
17
|
-
echo -e "${BLUE}[INFO]${NC} $1"
|
18
|
-
}
|
19
|
-
|
20
|
-
print_success() {
|
21
|
-
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
22
|
-
}
|
23
|
-
|
24
|
-
print_warning() {
|
25
|
-
echo -e "${YELLOW}[WARNING]${NC} $1"
|
26
|
-
}
|
27
|
-
|
28
|
-
print_error() {
|
29
|
-
echo -e "${RED}[ERROR]${NC} $1"
|
30
|
-
}
|
31
|
-
|
32
|
-
# Check if required environment variables are set
|
33
|
-
check_environment() {
|
34
|
-
print_status "Checking environment variables..."
|
35
|
-
|
36
|
-
if [ -z "$GEM_HOST_API_KEY" ]; then
|
37
|
-
print_error "GEM_HOST_API_KEY environment variable is not set"
|
38
|
-
print_status "Please set your RubyGems API key:"
|
39
|
-
print_status "export GEM_HOST_API_KEY=your_api_key_here"
|
40
|
-
exit 1
|
41
|
-
fi
|
42
|
-
|
43
|
-
print_success "Environment variables are set"
|
44
|
-
}
|
45
|
-
|
46
|
-
# Check if we're in the right directory
|
47
|
-
check_directory() {
|
48
|
-
if [ ! -f "laneful-ruby.gemspec" ]; then
|
49
|
-
print_error "laneful-ruby.gemspec not found. Please run this script from the project root."
|
50
|
-
exit 1
|
51
|
-
fi
|
52
|
-
print_success "Found gemspec file"
|
53
|
-
}
|
54
|
-
|
55
|
-
# Check Ruby version
|
56
|
-
check_ruby_version() {
|
57
|
-
print_status "Checking Ruby version..."
|
58
|
-
ruby_version=$(ruby -v | cut -d' ' -f2)
|
59
|
-
required_version="3.0.0"
|
60
|
-
|
61
|
-
if [ "$(printf '%s\n' "$required_version" "$ruby_version" | sort -V | head -n1)" = "$required_version" ]; then
|
62
|
-
print_success "Ruby version $ruby_version is compatible"
|
63
|
-
else
|
64
|
-
print_error "Ruby version $ruby_version is not compatible. Required: $required_version or higher"
|
65
|
-
exit 1
|
66
|
-
fi
|
67
|
-
}
|
68
|
-
|
69
|
-
# Install dependencies
|
70
|
-
install_dependencies() {
|
71
|
-
print_status "Installing dependencies..."
|
72
|
-
bundle install
|
73
|
-
if [ $? -eq 0 ]; then
|
74
|
-
print_success "Dependencies installed successfully"
|
75
|
-
else
|
76
|
-
print_error "Failed to install dependencies. Aborting publish."
|
77
|
-
exit 1
|
78
|
-
fi
|
79
|
-
}
|
80
|
-
|
81
|
-
# Run tests
|
82
|
-
run_tests() {
|
83
|
-
print_status "Running tests..."
|
84
|
-
bundle exec rspec
|
85
|
-
if [ $? -eq 0 ]; then
|
86
|
-
print_success "All tests passed"
|
87
|
-
else
|
88
|
-
print_error "Tests failed. Aborting publish."
|
89
|
-
exit 1
|
90
|
-
fi
|
91
|
-
}
|
92
|
-
|
93
|
-
# Run linting
|
94
|
-
run_lint() {
|
95
|
-
print_status "Running linter..."
|
96
|
-
bundle exec rubocop
|
97
|
-
if [ $? -eq 0 ]; then
|
98
|
-
print_success "Linting passed"
|
99
|
-
else
|
100
|
-
print_error "Linting failed. Aborting publish."
|
101
|
-
exit 1
|
102
|
-
fi
|
103
|
-
}
|
104
|
-
|
105
|
-
# Build the gem
|
106
|
-
build_gem() {
|
107
|
-
print_status "Building gem..."
|
108
|
-
gem build laneful-ruby.gemspec
|
109
|
-
if [ $? -eq 0 ]; then
|
110
|
-
print_success "Gem built successfully"
|
111
|
-
else
|
112
|
-
print_error "Gem build failed. Aborting publish."
|
113
|
-
exit 1
|
114
|
-
fi
|
115
|
-
}
|
116
|
-
|
117
|
-
# Publish to RubyGems
|
118
|
-
publish_gem() {
|
119
|
-
print_status "Publishing to RubyGems..."
|
120
|
-
gem push laneful-ruby-*.gem
|
121
|
-
if [ $? -eq 0 ]; then
|
122
|
-
print_success "Gem published successfully to RubyGems!"
|
123
|
-
else
|
124
|
-
print_error "Failed to publish gem to RubyGems."
|
125
|
-
exit 1
|
126
|
-
fi
|
127
|
-
}
|
128
|
-
|
129
|
-
# Clean up
|
130
|
-
cleanup() {
|
131
|
-
print_status "Cleaning up..."
|
132
|
-
rm -f laneful-ruby-*.gem
|
133
|
-
print_success "Cleanup completed"
|
134
|
-
}
|
135
|
-
|
136
|
-
# Main execution
|
137
|
-
main() {
|
138
|
-
print_status "Starting Laneful Ruby SDK publishing process..."
|
139
|
-
|
140
|
-
check_environment
|
141
|
-
check_directory
|
142
|
-
check_ruby_version
|
143
|
-
install_dependencies
|
144
|
-
|
145
|
-
# Ask for confirmation
|
146
|
-
echo
|
147
|
-
print_warning "This will publish the gem to RubyGems. Are you sure? (y/N)"
|
148
|
-
read -r response
|
149
|
-
if [[ ! "$response" =~ ^[Yy]$ ]]; then
|
150
|
-
print_status "Publishing cancelled."
|
151
|
-
exit 0
|
152
|
-
fi
|
153
|
-
|
154
|
-
run_tests
|
155
|
-
run_lint
|
156
|
-
build_gem
|
157
|
-
publish_gem
|
158
|
-
cleanup
|
159
|
-
|
160
|
-
print_success "Publishing process completed successfully!"
|
161
|
-
print_status "Your gem is now available on RubyGems: https://rubygems.org/gems/laneful-ruby"
|
162
|
-
}
|
163
|
-
|
164
|
-
# Handle script interruption
|
165
|
-
trap cleanup EXIT
|
166
|
-
|
167
|
-
# Run main function
|
168
|
-
main "$@"
|
169
|
-
|