rudder_analytics_sync 1.0.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
+ SHA1:
3
+ metadata.gz: 5726304487704b78e0e4af5710528e3b065b590a
4
+ data.tar.gz: 33ff76d7d2fcec35e640908472061a683061afcd
5
+ SHA512:
6
+ metadata.gz: 53e11d8490d9184c53d791e8f38dbeb8c262137d4732ccc405a6e999bb2b52c6bf9396b881d2dc476380a364f3f9d36b286eee1687208ccb73feaf2ca56f681a
7
+ data.tar.gz: 31790054a46185fcbdb96b721cdd58af13f687cf71d839ef36d6f6bb4fbe0215d6baf7d833e25a3db9bdd4e698c77cd593134e39e4dd4e5a79e33f103b2ace76
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.gem
11
+ .rbenv-gemsets
data/.hound.yml ADDED
@@ -0,0 +1,3 @@
1
+ rubocop:
2
+ config_file: .rubocop.yml
3
+ version: 0.75.0
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,12 @@
1
+ Metrics/BlockLength:
2
+ Exclude:
3
+ - '**/*_spec.rb'
4
+
5
+ Metrics/LineLength:
6
+ Max: 100
7
+ IgnoreCopDirectives: true
8
+ Exclude:
9
+ - 'simple_segment.gemspec'
10
+
11
+ Style/Documentation:
12
+ Enabled: false
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.4
4
+ - 2.5
5
+ - 2.6
6
+ - 2.7
data/CHANGELOG.md ADDED
@@ -0,0 +1,35 @@
1
+ # Changelog
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5
+ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [1.1.0] - 2020-04-11
10
+
11
+ ### Added
12
+ - Added supprt for http_proxy and https_proxy environment variables https://github.com/whatthewhat/simple_segment/pull/26 by @saks
13
+ - Added Ruby 2.7 to travis.yml
14
+
15
+ ## [1.0.0] - 2019-12-12
16
+
17
+ ### Added
18
+ - Allow passing custom Net::HTTP options (e.g. timeout) https://github.com/whatthewhat/simple_segment/pull/23 by @barodeur
19
+
20
+ ### Changed
21
+ - The gem is no longer tested with Ruby versions below 2.4
22
+
23
+ ## [0.3.0] - 2018-03-15
24
+
25
+ ### Changed
26
+ - Date properties are now automatically converted to ISO 8601 to be consistent with the official client https://github.com/whatthewhat/simple_segment/pull/19 by @juanramoncg
27
+
28
+ [Unreleased]: https://github.com/whatthewhat/simple_segment/compare/v1.1.0...HEAD
29
+ [1.1.0]: https://github.com/whatthewhat/simple_segment/compare/v1.0.0...v1.1.0
30
+ [1.0.0]: https://github.com/whatthewhat/simple_segment/compare/v0.3.0...v1.0.0
31
+ [0.3.0]: https://github.com/whatthewhat/simple_segment/compare/v0.2.1...v0.3.0
32
+ [0.2.1]: https://github.com/whatthewhat/simple_segment/compare/v0.2.0...v0.2.1
33
+ [0.2.0]: https://github.com/whatthewhat/simple_segment/compare/v0.1.1...v0.2.0
34
+ [0.1.1]: https://github.com/whatthewhat/simple_segment/compare/v0.1.0...v0.1.1
35
+ [0.1.0]: https://github.com/whatthewhat/simple_segment/compare/2d62f07a1df8388000b0b5a20331409132d05ad3...v0.1.0
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in simple_segment.gemspec
6
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 RudderStack
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,125 @@
1
+ # RudderAnalyticsSync
2
+
3
+ [![Build Status](https://travis-ci.org/whatthewhat/simple_segment.svg?branch=master)](https://travis-ci.org/whatthewhat/simple_segment)
4
+
5
+ A simple synchronous Ruby API client for [segment.io](segment.io).
6
+
7
+ RudderAnalyticsSync allows for manual control of when and how the events are sent to Segment. This can be useful if you want to leverage an existing queueing system like Sidekiq or Resque for sending events or need to send events synchronously. If this is not the case you will be better off using the [official segment gem](https://github.com/segmentio/analytics-ruby) that handles queuing for you.
8
+
9
+ ## Status
10
+
11
+ The gem supports all existing functionality of analytics-ruby:
12
+
13
+ - `analytics.track(...)`
14
+ - `analytics.identify(...)`
15
+ - `analytics.group(...)`
16
+ - `analytics.page(...)`
17
+ - `analytics.alias(...)`
18
+ - `analytics.flush` (no op for backwards compatibility with the official gem)
19
+
20
+ In addition it offers the ability to manually batch events with [analytics.batch](#batching).
21
+
22
+ The plan is to be an drop in replacement for the official gem, so if you find inconsistencies with `analytics-ruby` feel free to file an issue.
23
+
24
+ ## Installation
25
+
26
+ Add this line to your application's Gemfile:
27
+
28
+ ```ruby
29
+ gem 'simple_segment'
30
+ ```
31
+
32
+ Or install it yourself as:
33
+
34
+ ```sh
35
+ $ gem install simple_segment
36
+ ```
37
+
38
+ ## Usage
39
+
40
+ Create a client instance:
41
+
42
+ ```ruby
43
+ analytics = RudderAnalyticsSync::Client.new(
44
+ write_key: 'YOUR_WRITE_KEY', # required
45
+ on_error: proc { |error_code, error_body, exception, response|
46
+ # defaults to an empty proc
47
+ }
48
+ )
49
+ ```
50
+
51
+ Use it as you would use `analytics-ruby`:
52
+
53
+ ```ruby
54
+ analytics.track(
55
+ user_id: user.id,
56
+ event: 'Created Account'
57
+ )
58
+ ```
59
+
60
+ ### Batching
61
+
62
+ You can manually batch events with `analytics.batch`:
63
+
64
+ ```ruby
65
+ analytics.batch do |batch|
66
+ batch.context = {...} # shared context for all events
67
+ batch.integrations = {...} # shared integrations hash for all events
68
+ batch.identify(...)
69
+ batch.track(...)
70
+ batch.track(...)
71
+ ...
72
+ end
73
+ ```
74
+
75
+ ### Stub API calls
76
+
77
+ You can stub your API calls avoiding unecessary requests in development and automated test environments (backwards compatible with the official gem):
78
+
79
+ ```ruby
80
+ analytics = RudderAnalyticsSync::Client.new(
81
+ write_key: 'YOUR_WRITE_KEY',
82
+ stub: true
83
+ )
84
+ ```
85
+
86
+ ### Configurable Logger
87
+
88
+ When used in stubbed mode all calls are logged to STDOUT, this can be changed by providing a custom logger object:
89
+
90
+ ```ruby
91
+ analytics = RudderAnalyticsSync::Client.new(
92
+ write_key: 'YOUR_WRITE_KEY',
93
+ logger: Rails.logger
94
+ )
95
+ ```
96
+
97
+ ### Set HTTP Options
98
+
99
+ You can set [options](https://docs.ruby-lang.org/en/2.0.0/Net/HTTP.html#method-c-start) that are passed to `Net::HTTP.start`.
100
+
101
+ ```ruby
102
+ analytics = RudderAnalyticsSync::Client.new(
103
+ write_key: 'YOUR_WRITE_KEY',
104
+ http_options: {
105
+ open_timeout: 42,
106
+ read_timeout: 42,
107
+ close_on_empty_response: true,
108
+ # ...
109
+ }
110
+ )
111
+ ```
112
+
113
+ ## Development
114
+
115
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
116
+
117
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
118
+
119
+ ## Contributing
120
+
121
+ Bug reports and pull requests are welcome on GitHub at https://github.com/whatthewhat/simple_segment.
122
+
123
+ ## License
124
+
125
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
data/bin/console ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'simple_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
+ require 'pry'
11
+ Pry.start
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,29 @@
1
+ $LOAD_PATH << './lib/rudder_analytics_sync'
2
+
3
+ require 'rudder_analytics_sync'
4
+
5
+ include RudderAnalyticsSync
6
+
7
+ analytics = RudderAnalyticsSync::Client.new(
8
+ write_key: 'YOUR_WRITE_KEY', # required
9
+ data_plane_url: 'https://a14c63e1.ngrok.io',
10
+ on_error: proc { |error_code, error_body, exception, response|
11
+ # defaults to an empty proc
12
+ }
13
+ )
14
+
15
+ analytics.track(
16
+ user_id: 'test_user_id',
17
+ event: 'Created Account'
18
+ )
19
+
20
+ analytics.batch do |batch|
21
+ batch.track(
22
+ user_id: 'test_user_id',
23
+ event: 'Created Account'
24
+ )
25
+ batch.track(
26
+ user_id: 'test_user_id',
27
+ event: 'Closed Account'
28
+ )
29
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/http'
4
+ require 'json'
5
+ require 'time'
6
+ require 'rudder_analytics_sync/version'
7
+ require 'rudder_analytics_sync/client'
8
+
9
+ module RudderAnalyticsSync
10
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RudderAnalyticsSync
4
+ class Batch
5
+ include RudderAnalyticsSync::Utils
6
+
7
+ attr_reader :client, :payload
8
+
9
+ def self.deserialize(client, payload)
10
+ new(client, symbolize_keys(payload))
11
+ end
12
+
13
+ def initialize(client, payload = { batch: [] })
14
+ @client = client
15
+ @payload = payload
16
+ end
17
+
18
+ def identify(options)
19
+ add(Operations::Identify, options, __method__)
20
+ end
21
+
22
+ def track(options)
23
+ add(Operations::Track, options, __method__)
24
+ end
25
+
26
+ def page(options)
27
+ add(Operations::Page, options, __method__)
28
+ end
29
+
30
+ def group(options)
31
+ add(Operations::Group, options, __method__)
32
+ end
33
+
34
+ def context=(context)
35
+ payload[:context] = context
36
+ end
37
+
38
+ def integrations=(integrations)
39
+ payload[:integrations] = integrations
40
+ end
41
+
42
+ def serialize
43
+ payload
44
+ end
45
+
46
+ def commit
47
+ if payload[:batch].length.zero?
48
+ raise ArgumentError, 'A batch must contain at least one action'
49
+ end
50
+
51
+ Request.new(client).post('/v1/batch', payload)
52
+ end
53
+
54
+ private
55
+
56
+ def add(operation_class, options, action)
57
+ operation = operation_class.new(client, symbolize_keys(options))
58
+ operation_payload = operation.build_payload
59
+ operation_payload[:action] = action
60
+ payload[:batch] << operation_payload
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rudder_analytics_sync/utils'
4
+ require 'rudder_analytics_sync/configuration'
5
+ require 'rudder_analytics_sync/operations'
6
+ require 'rudder_analytics_sync/batch'
7
+
8
+ module RudderAnalyticsSync
9
+ class Client
10
+ include RudderAnalyticsSync::Utils
11
+
12
+ attr_reader :config
13
+
14
+ def initialize(options = {})
15
+ @config = Configuration.new(options)
16
+ end
17
+
18
+ # @param [Hash] options
19
+ # @option :user_id
20
+ # @option :anonymous_id
21
+ # @option :traits [Hash]
22
+ # @option :context [Hash]
23
+ # @option :integrations [Hash]
24
+ # @option :timestamp [#iso8601] (Time.now)
25
+ def identify(options)
26
+ Operations::Identify.new(self, symbolize_keys(options)).call
27
+ end
28
+
29
+ # @param [Hash] options
30
+ # @option :event [String] required
31
+ # @option :user_id
32
+ # @option :anonymous_id
33
+ # @option :properties [Hash]
34
+ # @option :context [Hash]
35
+ # @option :integrations [Hash]
36
+ # @option :timestamp [#iso8601] (Time.now)
37
+ def track(options)
38
+ Operations::Track.new(self, symbolize_keys(options)).call
39
+ end
40
+
41
+ # @param [Hash] options
42
+ # @option :user_id
43
+ # @option :anonymous_id
44
+ # @option :name [String]
45
+ # @option :properties [Hash]
46
+ # @option :context [Hash]
47
+ # @option :integrations [Hash]
48
+ # @option :timestamp [#iso8601] (Time.now)
49
+ def page(options)
50
+ Operations::Page.new(self, symbolize_keys(options)).call
51
+ end
52
+
53
+ # @param [Hash] options
54
+ # @option :user_id
55
+ # @option :anonymous_id
56
+ # @option :group_id required
57
+ # @option :traits [Hash]
58
+ # @option :context [Hash]
59
+ # @option :integrations [Hash]
60
+ # @option :timestamp [#iso8601] (Time.now)
61
+ def group(options)
62
+ Operations::Group.new(self, symbolize_keys(options)).call
63
+ end
64
+
65
+ # @param [Hash] options
66
+ # @option :user_id
67
+ # @option :anonymous_id
68
+ # @option :previous_id required
69
+ # @option :traits [Hash]
70
+ # @option :context [Hash]
71
+ # @option :integrations [Hash]
72
+ # @option :timestamp [#iso8601] (Time.now)
73
+ def alias(options)
74
+ Operations::Alias.new(self, symbolize_keys(options)).call
75
+ end
76
+
77
+ # @yield [batch] Yields a special batch object that can be used to group
78
+ # `identify`, `track`, `page` and `group` calls into a
79
+ # single API request.
80
+ # @example
81
+ # client.batch do |analytics|
82
+ # analytics.context = { 'foo' => 'bar' }
83
+ # analytics.identify(user_id: 'id')
84
+ # analytics.track(event: 'Delivered Package', user_id: 'id')
85
+ # end
86
+ def batch
87
+ batch = Batch.new(self)
88
+ yield(batch)
89
+ batch.commit
90
+ end
91
+
92
+ # A no op, added for backwards compatibility with `analytics-ruby`
93
+ def flush; end
94
+ end
95
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rudder_analytics_sync/logging'
4
+
5
+ module RudderAnalyticsSync
6
+ class Configuration
7
+ include RudderAnalyticsSync::Utils
8
+ include RudderAnalyticsSync::Logging
9
+
10
+ attr_reader :write_key, :data_plane_url, :on_error, :stub, :logger, :http_options
11
+
12
+ def initialize(settings = {})
13
+ symbolized_settings = symbolize_keys(settings)
14
+ @write_key = symbolized_settings[:write_key]
15
+ @data_plane_url = symbolized_settings[:data_plane_url]
16
+ @on_error = symbolized_settings[:on_error] || proc {}
17
+ @stub = symbolized_settings[:stub]
18
+ @logger = default_logger(symbolized_settings[:logger])
19
+ @http_options = { use_ssl: true }
20
+ .merge(symbolized_settings[:http_options] || {})
21
+ raise ArgumentError, 'Missing required option :write_key' \
22
+ unless @write_key
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logger'
4
+ module RudderAnalyticsSync
5
+ module Logging
6
+ def self.included(klass)
7
+ klass.extend(self)
8
+ end
9
+
10
+ def default_logger(logger_option)
11
+ logger_option || Logger.new(STDOUT)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rudder_analytics_sync/request'
4
+ require 'rudder_analytics_sync/operations/operation'
5
+ require 'rudder_analytics_sync/operations/identify'
6
+ require 'rudder_analytics_sync/operations/track'
7
+ require 'rudder_analytics_sync/operations/page'
8
+ require 'rudder_analytics_sync/operations/group'
9
+ require 'rudder_analytics_sync/operations/alias'
10
+
11
+ module RudderAnalyticsSync
12
+ module Operations
13
+ end
14
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RudderAnalyticsSync
4
+ module Operations
5
+ class Alias < Operation
6
+ def call
7
+ request.post('/v1/alias', build_payload)
8
+ end
9
+
10
+ def build_payload
11
+ raise ArgumentError, 'previous_id must be present' \
12
+ unless options[:previous_id]
13
+
14
+ base_payload.merge(
15
+ previousId: options[:previous_id]
16
+ )
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RudderAnalyticsSync
4
+ module Operations
5
+ class Group < Operation
6
+ def call
7
+ request.post('/v1/group', build_payload)
8
+ end
9
+
10
+ def build_payload
11
+ raise ArgumentError, 'group_id must be present' \
12
+ unless options[:group_id]
13
+
14
+ base_payload.merge(
15
+ traits: options[:traits] && isoify_dates!(options[:traits]),
16
+ groupId: options[:group_id]
17
+ )
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RudderAnalyticsSync
4
+ module Operations
5
+ class Identify < Operation
6
+ def call
7
+ request.post('/v1/identify', build_payload)
8
+ end
9
+
10
+ def build_payload
11
+ base_payload.merge(
12
+ traits: options[:traits] && isoify_dates!(options[:traits])
13
+ )
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RudderAnalyticsSync
4
+ module Operations
5
+ class Operation
6
+ include RudderAnalyticsSync::Utils
7
+
8
+ DEFAULT_CONTEXT = {
9
+ library: {
10
+ name: 'rudder-sdk-ruby-sync',
11
+ version: RudderAnalyticsSync::VERSION
12
+ }
13
+ }.freeze
14
+
15
+ def initialize(client, options = {})
16
+ @options = options
17
+ @context = DEFAULT_CONTEXT.merge(options[:context].to_h)
18
+ @request = Request.new(client)
19
+ end
20
+
21
+ def call
22
+ raise 'Must be implemented in a subclass'
23
+ end
24
+
25
+ private
26
+
27
+ attr_reader :options, :request, :context
28
+
29
+ def base_payload
30
+ check_identity!
31
+ current_time = Time.now
32
+
33
+ {
34
+ userId: options[:user_id],
35
+ anonymousId: options[:anonymous_id],
36
+ context: context,
37
+ integrations: options[:integrations],
38
+ timestamp: timestamp(options.fetch(:timestamp, current_time)),
39
+ sentAt: current_time.iso8601
40
+ }
41
+ end
42
+
43
+ def check_identity!
44
+ raise ArgumentError, 'user_id or anonymous_id must be present' \
45
+ unless options[:user_id] || options[:anonymous_id]
46
+ end
47
+
48
+ def timestamp(timestamp)
49
+ if timestamp.respond_to?(:iso8601)
50
+ timestamp.iso8601
51
+ else
52
+ Time.iso8601(timestamp).iso8601
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RudderAnalyticsSync
4
+ module Operations
5
+ class Page < Operation
6
+ def call
7
+ request.post('/v1/page', build_payload)
8
+ end
9
+
10
+ def build_payload
11
+ properties = options[:properties] && isoify_dates!(options[:properties])
12
+
13
+ base_payload.merge(
14
+ name: options[:name],
15
+ properties: properties
16
+ )
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RudderAnalyticsSync
4
+ module Operations
5
+ class Track < Operation
6
+ def call
7
+ request.post('/v1/track', build_payload)
8
+ end
9
+
10
+ def build_payload
11
+ raise ArgumentError, 'event name must be present' \
12
+ unless options[:event]
13
+
14
+ properties = options[:properties] && isoify_dates!(options[:properties])
15
+
16
+ base_payload.merge(
17
+ event: options[:event],
18
+ properties: properties
19
+ )
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RudderAnalyticsSync
4
+ class Request
5
+ BASE_URL = 'https://hosted.rudderlabs.com'
6
+ DEFAULT_HEADERS = {
7
+ 'Content-Type' => 'application/json',
8
+ 'accept' => 'application/json'
9
+ }.freeze
10
+
11
+ attr_reader :write_key, :data_plane_url, :error_handler, :stub, :logger, :http_options
12
+
13
+ def initialize(client)
14
+ @write_key = client.config.write_key
15
+ @data_plane_url = client.config.data_plane_url || BASE_URL
16
+ @error_handler = client.config.on_error
17
+ @stub = client.config.stub
18
+ @logger = client.config.logger
19
+ @http_options = client.config.http_options
20
+ end
21
+
22
+ def post(path, payload, headers: DEFAULT_HEADERS) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
23
+ response = nil
24
+ status_code = nil
25
+ response_body = nil
26
+
27
+ uri = URI(data_plane_url)
28
+ payload = JSON.generate(payload)
29
+ if stub
30
+ logger.debug "stubbed request to \
31
+ #{path}: write key = #{write_key}, \
32
+ payload = #{payload}"
33
+
34
+ { status: 200, error: nil }
35
+ else
36
+ Net::HTTP.start(uri.host, uri.port, :ENV, http_options) do |http|
37
+ request = Net::HTTP::Post.new(path, headers)
38
+ request.basic_auth write_key, nil
39
+ http.request(request, payload).tap do |res|
40
+ status_code = res.code
41
+ response_body = res.body
42
+ response = res
43
+ response.value
44
+ end
45
+ end
46
+ end
47
+ rescue StandardError => e
48
+ error_handler.call(status_code, response_body, e, response)
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RudderAnalyticsSync
4
+ module Utils
5
+ def self.included(klass)
6
+ klass.extend(self)
7
+ end
8
+
9
+ def symbolize_keys(hash)
10
+ hash.each_with_object({}) do |(key, value), result|
11
+ result[key.to_sym] = value
12
+ end
13
+ end
14
+
15
+ # public: Converts all the date values in the into iso8601 strings in place
16
+ #
17
+ def isoify_dates!(hash)
18
+ hash.replace isoify_dates hash
19
+ end
20
+
21
+ # public: Returns a new hash with all the date values in the into iso8601
22
+ # strings
23
+ #
24
+ def isoify_dates(hash)
25
+ hash.each_with_object({}) do |(k, v), memo|
26
+ memo[k] = maybe_datetime_in_iso8601(v)
27
+ end
28
+ end
29
+
30
+ def maybe_datetime_in_iso8601(prop)
31
+ case prop
32
+ when Time
33
+ prop.iso8601(3)
34
+ when DateTime
35
+ prop.to_time.iso8601(3)
36
+ when Date
37
+ prop.strftime('%F')
38
+ else
39
+ prop
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RudderAnalyticsSync
4
+ VERSION = '1.0.0'
5
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'rudder_analytics_sync/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'rudder_analytics_sync'
9
+ spec.version = RudderAnalyticsSync::VERSION
10
+ spec.authors = ['RudderStack']
11
+ spec.email = ['arnab@rudderlabs.com']
12
+
13
+ spec.summary = 'Privacy and Security focused Segment-alternative. Ruby SDK (sync)'
14
+ spec.description = 'Rudder is a platform for collecting, storing and routing customer event data to dozens of tools. Rudder is open-source, can run in your cloud environment (AWS, GCP, Azure or even your data-centre) and provides a powerful transformation framework to process your event data on the fly.'
15
+ spec.homepage = 'https://github.com/rudderlabs/rudder-sdk-ruby-sync'
16
+ spec.license = 'MIT'
17
+
18
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
19
+ spec.bindir = 'exe'
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ['lib']
22
+
23
+ spec.add_development_dependency 'bundler', '>= 1.11'
24
+ spec.add_development_dependency 'pry'
25
+ spec.add_development_dependency 'rake', '>= 10.0'
26
+ spec.add_development_dependency 'rspec', '~> 3.0'
27
+ spec.add_development_dependency 'rubocop', '0.75.0'
28
+ spec.add_development_dependency 'timecop', '~> 0.8.0'
29
+ spec.add_development_dependency 'webmock', '~> 3.7'
30
+ end
metadata ADDED
@@ -0,0 +1,174 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rudder_analytics_sync
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - RudderStack
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-04-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '1.11'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '1.11'
27
+ - !ruby/object:Gem::Dependency
28
+ name: pry
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '='
74
+ - !ruby/object:Gem::Version
75
+ version: 0.75.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '='
81
+ - !ruby/object:Gem::Version
82
+ version: 0.75.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: timecop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.8.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.8.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: webmock
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '3.7'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '3.7'
111
+ description: Rudder is a platform for collecting, storing and routing customer event
112
+ data to dozens of tools. Rudder is open-source, can run in your cloud environment
113
+ (AWS, GCP, Azure or even your data-centre) and provides a powerful transformation
114
+ framework to process your event data on the fly.
115
+ email:
116
+ - arnab@rudderlabs.com
117
+ executables: []
118
+ extensions: []
119
+ extra_rdoc_files: []
120
+ files:
121
+ - ".gitignore"
122
+ - ".hound.yml"
123
+ - ".rspec"
124
+ - ".rubocop.yml"
125
+ - ".travis.yml"
126
+ - CHANGELOG.md
127
+ - Gemfile
128
+ - LICENSE.txt
129
+ - README.md
130
+ - Rakefile
131
+ - bin/console
132
+ - bin/setup
133
+ - example/example.rb
134
+ - lib/rudder_analytics_sync.rb
135
+ - lib/rudder_analytics_sync/batch.rb
136
+ - lib/rudder_analytics_sync/client.rb
137
+ - lib/rudder_analytics_sync/configuration.rb
138
+ - lib/rudder_analytics_sync/logging.rb
139
+ - lib/rudder_analytics_sync/operations.rb
140
+ - lib/rudder_analytics_sync/operations/alias.rb
141
+ - lib/rudder_analytics_sync/operations/group.rb
142
+ - lib/rudder_analytics_sync/operations/identify.rb
143
+ - lib/rudder_analytics_sync/operations/operation.rb
144
+ - lib/rudder_analytics_sync/operations/page.rb
145
+ - lib/rudder_analytics_sync/operations/track.rb
146
+ - lib/rudder_analytics_sync/request.rb
147
+ - lib/rudder_analytics_sync/utils.rb
148
+ - lib/rudder_analytics_sync/version.rb
149
+ - rudder_analytics_sync.gemspec
150
+ homepage: https://github.com/rudderlabs/rudder-sdk-ruby-sync
151
+ licenses:
152
+ - MIT
153
+ metadata: {}
154
+ post_install_message:
155
+ rdoc_options: []
156
+ require_paths:
157
+ - lib
158
+ required_ruby_version: !ruby/object:Gem::Requirement
159
+ requirements:
160
+ - - ">="
161
+ - !ruby/object:Gem::Version
162
+ version: '0'
163
+ required_rubygems_version: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
168
+ requirements: []
169
+ rubyforge_project:
170
+ rubygems_version: 2.5.2.3
171
+ signing_key:
172
+ specification_version: 4
173
+ summary: Privacy and Security focused Segment-alternative. Ruby SDK (sync)
174
+ test_files: []