itly-plugin-segment 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 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: []