itly-plugin-segment 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: c9f20dfcfa5ed0fa7ef7d326b01393cbf9ec6569156574b860ecc476ac7a37e2
4
+ data.tar.gz: ce26f8c877644a4c61cdbb6f0229326f26779090bf44ef5e2798f791cf31e5f0
5
+ SHA512:
6
+ metadata.gz: 06df66a8cd5aaec7f3481b64e147668a87c5e9691b9e3337727c9081744092bdda7639982798f10e7f60e75050e79f90ae462bb8b773419b77bf3f43c3b5dc06
7
+ data.tar.gz: '0887e543ce1a1ce087ee64879924eb5c7e4861f5744da5049f0904c322582b7945bb59c8ae0c24ea037bd3e445a45bebeff8a2fe66282a6f6816479b4b809763'
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in itly-plugin-segment.gemspec
6
+ gemspec
7
+
8
+ gem 'rake', '~> 13.0'
9
+
10
+ if ENV['LOCAL_ITLY_GEM']
11
+ # TODO: before publication to RubyGems, switch to version 1
12
+ gem 'itly-sdk', '~> 0.1', path: '../sdk'
13
+ end
14
+
15
+ gem 'rbs', '~> 1.0'
16
+ gem 'rspec'
17
+ gem 'steep', '~> 0.41'
data/Steepfile ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ target :lib do
4
+ signature 'sig'
5
+
6
+ check 'lib'
7
+
8
+ library 'logger', 'set', 'itly-sdk'
9
+ end
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'itly/plugin-segment'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start(__FILE__)
data/bin/rspec ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Configure and load RBS
5
+ unless ENV['DISABLE_TYPE_CHECKING']
6
+ ENV['RBS_TEST_TARGET'] = 'Itly::*'
7
+ ENV['RBS_TEST_LOGLEVEL'] = 'warn'
8
+ ENV['RBS_TEST_DOUBLE_SUITE'] = 'rspec'
9
+ ENV['RBS_TEST_OPT'] = '-I./sig -I../sdk/sig'
10
+
11
+ require 'rbs/test/setup'
12
+ end
13
+
14
+ # Start RSpec
15
+ require 'rspec/core'
16
+
17
+ ENV['RSPEC_RUN_FROM_SCRIPT'] = 'true'
18
+ RSpec::Core::Runner.invoke
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,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/itly/plugin/segment/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'itly-plugin-segment'
7
+ spec.version = Itly::Plugin::Segment::VERSION
8
+ spec.authors = ['Iteratively', 'Benjamin Bouchet', 'Justin Fiedler', 'Andrey Sokolov']
9
+ spec.email = ['support@iterative.ly']
10
+
11
+ spec.summary = 'Segment plugin for Iteratively SDK for Ruby'
12
+ spec.description = 'Track and validate analytics with a unified, extensible interface ' \
13
+ 'that works with all your 3rd party analytics providers.'
14
+ spec.homepage = 'https://github.com/iterativelyhq/itly-sdk-ruby'
15
+ spec.license = 'MIT'
16
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.6.0')
17
+
18
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org/'
19
+
20
+ spec.metadata['homepage_uri'] = spec.homepage
21
+ spec.metadata['source_code_uri'] = 'https://github.com/iterativelyhq/itly-sdk-ruby/plugin-segment'
22
+
23
+ # Specify which files should be added to the gem when it is released.
24
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
25
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
26
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
27
+ end
28
+ spec.require_paths = ['lib']
29
+
30
+ spec.add_dependency 'itly-sdk', '~> 0.1'
31
+ spec.add_dependency 'simple_segment', '~> 1.2'
32
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ if ENV['LOCAL_ITLY_GEM']
4
+ lib = File.expand_path('../../../sdk/lib', File.dirname(__FILE__))
5
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
+ end
7
+
8
+ require_relative 'plugin/segment/segment'
9
+ require_relative 'plugin/segment/options'
10
+ require_relative 'plugin/segment/call_options'
11
+ require_relative 'plugin/segment/version'
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Itly
4
+ class Plugin
5
+ # Segment plugin class for Itly SDK
6
+ class Segment
7
+ ##
8
+ # Segment specific plugin options class
9
+ #
10
+ class CallOptions < Itly::PluginCallOptions
11
+ attr_reader :callback, :integrations, :context, :message_id, :timestamp, :anonymous_id
12
+
13
+ def initialize(
14
+ callback: nil, integrations: nil, context: nil, message_id: nil, timestamp: nil, anonymous_id: nil
15
+ )
16
+ super()
17
+ @integrations = integrations
18
+ @callback = callback
19
+ @context = context
20
+ @message_id = message_id
21
+ @timestamp = timestamp
22
+ @anonymous_id = anonymous_id
23
+ end
24
+
25
+ ##
26
+ # Return all properties to be passed to the client
27
+ # While excluding the `callback` property
28
+ #
29
+ # @return [Hash] properties
30
+ #
31
+ def to_hash
32
+ %w[integrations context message_id timestamp anonymous_id].each_with_object({}) do |prop, hash|
33
+ hash[prop.to_sym] = send(prop) unless send(prop).nil?
34
+ end
35
+ end
36
+
37
+ ##
38
+ # Get the plugin description, for logs
39
+ #
40
+ # @return [String] description
41
+ #
42
+ def to_s
43
+ class_name = self.class.name.split('::').last
44
+ props = %w[integrations context message_id timestamp anonymous_id].collect do |prop|
45
+ " #{prop}: #{send prop}" unless send(prop).nil?
46
+ end.compact
47
+ "#<Segment::#{class_name} callback: #{callback.nil? ? 'nil' : 'provided'}#{props.join}>"
48
+ end
49
+ end
50
+
51
+ ##
52
+ # Segment specific plugin options class for calls to plugin methods
53
+ #
54
+ %w[Identify Group Page Track Alias].each do |name|
55
+ class_eval(
56
+ <<-EVAL, __FILE__, __LINE__ + 1
57
+ class #{name}Options < CallOptions # class IdentifyOptions < CallOptions
58
+ end # end
59
+ EVAL
60
+ )
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'itly-sdk'
4
+
5
+ class Itly
6
+ class Plugin
7
+ class Segment
8
+ ##
9
+ # Options for the Segment plugin class
10
+ #
11
+ # rubocop:disable Lint/EmptyClass
12
+ class Options
13
+ end
14
+ # rubocop:enable Lint/EmptyClass
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,240 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'itly-sdk'
4
+ require 'simple_segment'
5
+
6
+ class Itly
7
+ class Plugin
8
+ ##
9
+ # Segment plugin class for Itly SDK
10
+ #
11
+ # Automatically loaded at runtime in any new +Itly+ object
12
+ #
13
+ class Segment < Plugin
14
+ attr_reader :client, :disabled
15
+
16
+ ##
17
+ # Instantiate a new Plugin::Segment
18
+ #
19
+ # @param [String] write_key: specify the Segment write key
20
+ # @param [TrueClass/FalseClass] disabled: set to true to disable the plugin. Default to false
21
+ #
22
+ def initialize(write_key:, disabled: false)
23
+ super()
24
+ @write_key = write_key
25
+ @disabled = disabled
26
+ end
27
+
28
+ ##
29
+ # Initialize Segment::Tracker client
30
+ #
31
+ # @param [Itly::PluginOptions] options: plugin options
32
+ #
33
+ def load(options:)
34
+ super
35
+ # Get options
36
+ @logger = options.logger
37
+
38
+ # Log
39
+ @logger&.info "#{id}: load()"
40
+
41
+ if @disabled
42
+ @logger&.info "#{id}: plugin is disabled!"
43
+ return
44
+ end
45
+
46
+ # Configure client
47
+ error_handler = proc do |error_code, error_body, exception, _|
48
+ message = 'The client returned an error.'
49
+ message += " Error code: #{error_code}. " if error_code
50
+ message += " Error body: #{error_body}. " if error_body
51
+ message += " Exception #{exception.class.name}: #{exception.message}." if exception
52
+
53
+ raise Itly::RemoteError, message
54
+ end
55
+
56
+ @client = ::SimpleSegment::Client.new \
57
+ write_key: @write_key, logger: @logger,
58
+ on_error: error_handler
59
+ end
60
+
61
+ ##
62
+ # Identify a user
63
+ #
64
+ # Raise an error if the client fails
65
+ #
66
+ # @param [String] user_id: the id of the user in your application
67
+ # @param [Hash] properties: the properties containing user's traits to pass to your application
68
+ # @param [Itly::Plugin::Segment::IdentifyOptions] options: the plugin specific options
69
+ #
70
+ def identify(user_id:, properties: nil, options: nil)
71
+ super
72
+ return unless enabled?
73
+
74
+ # Log
75
+ log = Itly::Loggers.vars_to_log user_id: user_id, properties: properties, options: options
76
+ @logger&.info "#{id}: identify(#{log})"
77
+
78
+ # Send through the client
79
+ payload = { user_id: user_id }
80
+ payload.merge! traits: properties.dup if properties
81
+ payload.merge! options.to_hash if options
82
+
83
+ call_end_point(options&.callback) do
84
+ @client.identify(**payload)
85
+ end
86
+ end
87
+
88
+ ##
89
+ # Associate a user with their group
90
+ #
91
+ # Raise an error if the client fails
92
+ #
93
+ # @param [String] user_id: the id of the user in your application
94
+ # @param [String] group_id: the id of the group in your application
95
+ # @param [Hash] properties: the properties to pass to your application
96
+ # @param [Itly::Plugin::Segment::GroupOptions] options: the plugin specific options
97
+ #
98
+ def group(user_id:, group_id:, properties: nil, options: nil)
99
+ super
100
+ return unless enabled?
101
+
102
+ # Log
103
+ log = Itly::Loggers.vars_to_log(
104
+ user_id: user_id, group_id: group_id, properties: properties, options: options
105
+ )
106
+ @logger&.info "#{id}: group(#{log})"
107
+
108
+ # Send through the client
109
+ payload = { user_id: user_id, group_id: group_id }
110
+ payload.merge! traits: properties.dup if properties
111
+ payload.merge! options.to_hash if options
112
+
113
+ call_end_point(options&.callback) do
114
+ @client.group(**payload)
115
+ end
116
+ end
117
+
118
+ ##
119
+ # Record page views
120
+ #
121
+ # Raise an error if the client fails
122
+ #
123
+ # @param [String] user_id: the id of the user in your application
124
+ # @param [String] category: the category of the page
125
+ # @param [String] name: the name of the page.
126
+ # @param [Hash] properties: the properties to pass to your application
127
+ # @param [Itly::Plugin::Segment::PageOptions] options: the plugin specific options
128
+ #
129
+ def page(user_id:, category: nil, name: nil, properties: nil, options: nil)
130
+ super
131
+ return unless enabled?
132
+
133
+ # Log
134
+ log = Itly::Loggers.vars_to_log(
135
+ user_id: user_id, category: category, name: name, properties: properties, options: options
136
+ )
137
+ @logger&.info "#{id}: page(#{log})"
138
+
139
+ # Send through the client
140
+ payload = { user_id: user_id }
141
+ payload.merge! name: name if name
142
+ payload.merge! options.to_hash if options
143
+ if properties && category
144
+ payload.merge! properties: properties.dup.merge(category: category)
145
+ elsif properties
146
+ payload.merge! properties: properties.dup
147
+ elsif category
148
+ payload.merge! properties: { category: category }
149
+ end
150
+
151
+ call_end_point(options&.callback) do
152
+ @client.page(**payload)
153
+ end
154
+ end
155
+
156
+ ##
157
+ # Track an event
158
+ #
159
+ # Raise an error if the client fails
160
+ #
161
+ # @param [String] user_id: the id of the user in your application
162
+ # @param [Event] event: the Event object to pass to your application
163
+ # @param [Itly::Plugin::Segment::TrackOptions] options: the plugin specific options
164
+ #
165
+ def track(user_id:, event:, options: nil)
166
+ super
167
+ return unless enabled?
168
+
169
+ # Log
170
+ log = Itly::Loggers.vars_to_log(
171
+ user_id: user_id, event: event&.name, properties: event&.properties, options: options
172
+ )
173
+ @logger&.info "#{id}: track(#{log})"
174
+
175
+ # Send through the client
176
+ payload = { user_id: user_id, event: event.name, properties: event.properties.dup }
177
+ payload.merge! options.to_hash if options
178
+
179
+ call_end_point(options&.callback) do
180
+ @client.track(**payload)
181
+ end
182
+ end
183
+
184
+ ##
185
+ # Associate one user ID with another (typically a known user ID with an anonymous one).
186
+ #
187
+ # Raise an error if the client fails
188
+ #
189
+ # @param [String] user_id: The ID that the user will be identified by going forward. This is
190
+ # typically the user's database ID (as opposed to an anonymous ID), or their updated ID
191
+ # (for example, if the ID is an email address which the user just updated).
192
+ # @param [String] previous_id: The ID the user has been identified by so far.
193
+ # @param [Itly::Plugin::Segment::AliasOptions] options: the plugin specific options
194
+ #
195
+ def alias(user_id:, previous_id:, options: nil)
196
+ super
197
+ return unless enabled?
198
+
199
+ # Log
200
+ log = Itly::Loggers.vars_to_log(
201
+ user_id: user_id, previous_id: previous_id, options: options
202
+ )
203
+ @logger&.info "#{id}: alias(#{log})"
204
+
205
+ # Send through the client
206
+ payload = { user_id: user_id, previous_id: previous_id }
207
+ payload.merge! options.to_hash if options
208
+
209
+ call_end_point(options&.callback) do
210
+ @client.alias(**payload)
211
+ end
212
+ end
213
+
214
+ ##
215
+ # Get the plugin ID
216
+ #
217
+ # @return [String] plugin id
218
+ #
219
+ def id
220
+ 'segment'
221
+ end
222
+
223
+ private
224
+
225
+ def enabled?
226
+ !@disabled
227
+ end
228
+
229
+ def call_end_point(callback)
230
+ raise 'You need to give a block' unless block_given?
231
+
232
+ # Call remote endpoint (Note: the Segment client returns a Net::HTTPResponse)
233
+ response = yield
234
+
235
+ # yield to the callback passed in to options
236
+ callback&.call(response.code.to_i, response.body)
237
+ end
238
+ end
239
+ end
240
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Itly
4
+ class Plugin
5
+ class Segment < Plugin
6
+ VERSION = '0.1.0'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,36 @@
1
+ class Itly
2
+ class Plugin
3
+ class Segment
4
+ class CallOptions < Itly::PluginCallOptions
5
+ attr_reader callback: (^(Integer?, String?) -> void)?
6
+ attr_reader integrations: Hash[String, bool]?
7
+ attr_reader context: Hash[String, bool]?
8
+ attr_reader message_id: String?
9
+ attr_reader timestamp: String?
10
+ attr_reader anonymous_id: String?
11
+
12
+ def to_hash: () -> untypedHash
13
+ def to_s: () -> String
14
+
15
+ private
16
+
17
+ def initialize: (?callback: (^(Integer?, String?) -> void)? callback, ?integrations: Hash[String, bool]? integrations, ?context: Hash[String, bool]? context, ?message_id: String? message_id, ?timestamp: String? timestamp, ?anonymous_id: String? anonymous_id) -> void
18
+ end
19
+
20
+ class IdentifyOptions < CallOptions
21
+ end
22
+
23
+ class GroupOptions < CallOptions
24
+ end
25
+
26
+ class PageOptions < CallOptions
27
+ end
28
+
29
+ class TrackOptions < CallOptions
30
+ end
31
+
32
+ class AliasOptions < CallOptions
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,3 @@
1
+ # Part of the gems
2
+ class MonitorMixin
3
+ end
@@ -0,0 +1,4 @@
1
+ class Net
2
+ class HTTPResponse
3
+ end
4
+ end
@@ -0,0 +1,12 @@
1
+ class SimpleSegment
2
+ class Client
3
+ def identify: (user_id: String user_id, traits: propertiesHash traits) -> void
4
+ def group: (user_id: String user_id, group_id: String group_id, traits: propertiesHash traits) -> void
5
+ def track: (user_id: String user_id, event: String event, properties: propertiesHash properties) -> void
6
+ def alias: (user_id: String user_id, previous_id: String previous_id) -> void
7
+
8
+ private
9
+
10
+ def initialize: (write_key: String write_key, logger: Logger? logger) -> void
11
+ end
12
+ end
data/sig/options.rbs ADDED
@@ -0,0 +1,8 @@
1
+ class Itly
2
+ class Plugin
3
+ class Segment
4
+ class Options
5
+ end
6
+ end
7
+ end
8
+ end
data/sig/segment.rbs ADDED
@@ -0,0 +1,24 @@
1
+ class Itly
2
+ class Plugin
3
+ class Segment < Plugin
4
+ VERSION: String
5
+
6
+ attr_reader client: SimpleSegment::Client?
7
+ attr_reader disabled: bool
8
+
9
+ def load: (options: Itly::PluginOptions options) -> void
10
+ def identify: (user_id: String user_id, ?properties: propertiesHash? properties, ?options: Itly::Plugin::Segment::IdentifyOptions? options) -> void
11
+ def group: (user_id: String user_id, group_id: String group_id, ?properties: propertiesHash? properties, ?options: Itly::Plugin::Segment::GroupOptions? options) -> void
12
+ def page: (user_id: String user_id, ?category: String? category, ?name: String? name, ?properties: propertiesHash? properties, ?options: Itly::Plugin::Segment::PageOptions? options) -> void
13
+ def track: (user_id: String user_id, event: Itly::Event event, ?options: Itly::Plugin::Segment::TrackOptions? options) -> void
14
+ def alias: (user_id: String user_id, previous_id: String previous_id, ?options: Itly::Plugin::Segment::AliasOptions? options) -> void
15
+ def id: () -> String
16
+
17
+ private
18
+
19
+ def initialize: (write_key: String write_key, ?disabled: bool disabled) -> void
20
+ def enabled?: () -> bool
21
+ def call_end_point: ((^(Integer?, String?) -> void)? callback) ?{ () -> Net::HTTPResponse } -> void
22
+ end
23
+ end
24
+ end
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: itly-plugin-segment
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Iteratively
8
+ - Benjamin Bouchet
9
+ - Justin Fiedler
10
+ - Andrey Sokolov
11
+ autorequire:
12
+ bindir: bin
13
+ cert_chain: []
14
+ date: 2021-06-15 00:00:00.000000000 Z
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: itly-sdk
18
+ requirement: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - "~>"
21
+ - !ruby/object:Gem::Version
22
+ version: '0.1'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '0.1'
30
+ - !ruby/object:Gem::Dependency
31
+ name: simple_segment
32
+ requirement: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - "~>"
35
+ - !ruby/object:Gem::Version
36
+ version: '1.2'
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "~>"
42
+ - !ruby/object:Gem::Version
43
+ version: '1.2'
44
+ description: Track and validate analytics with a unified, extensible interface that
45
+ works with all your 3rd party analytics providers.
46
+ email:
47
+ - support@iterative.ly
48
+ executables: []
49
+ extensions: []
50
+ extra_rdoc_files: []
51
+ files:
52
+ - ".rspec"
53
+ - Gemfile
54
+ - Steepfile
55
+ - bin/console
56
+ - bin/rspec
57
+ - bin/setup
58
+ - itly-plugin-segment.gemspec
59
+ - lib/itly/plugin-segment.rb
60
+ - lib/itly/plugin/segment/call_options.rb
61
+ - lib/itly/plugin/segment/options.rb
62
+ - lib/itly/plugin/segment/segment.rb
63
+ - lib/itly/plugin/segment/version.rb
64
+ - sig/call_options.rbs
65
+ - sig/lib/monitor_mixin.rbs
66
+ - sig/lib/net_http_response.rbs
67
+ - sig/lib/simple_segment_client.rbs
68
+ - sig/options.rbs
69
+ - sig/segment.rbs
70
+ homepage: https://github.com/iterativelyhq/itly-sdk-ruby
71
+ licenses:
72
+ - MIT
73
+ metadata:
74
+ allowed_push_host: https://rubygems.org/
75
+ homepage_uri: https://github.com/iterativelyhq/itly-sdk-ruby
76
+ source_code_uri: https://github.com/iterativelyhq/itly-sdk-ruby/plugin-segment
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: Segment plugin for Iteratively SDK for Ruby
96
+ test_files: []