amplitude-api 0.1.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8b743d15865f804837f6f3abb9557fa35aa6a32ae360fae0edfeaab0e7905b81
4
- data.tar.gz: 8c58bd5c4a21a36394cca7ce58da56b1e4135fc4ac574001e31350bda5cf3d69
3
+ metadata.gz: 59e87e342af629c6e87369ef210a272186236ec4e4ef9f9a101a2a590da59204
4
+ data.tar.gz: 7e207b30db0550982c4280aa0da2d3c225b1598cfd2bcba1971e8a75238e142e
5
5
  SHA512:
6
- metadata.gz: 3bf4707b9fe9905e95fdeee4c66044dfce02a2f4bae7fe939cffc343957ff4b2eb3d0dcf41d9c9dc958048f14fc8039c5d4e5c375103b7aeec4260e5a5a5c2d5
7
- data.tar.gz: 6cb4d59c569e8ccb3d8fc1f52920baba4ae6fa1da605115e6ed393a05119d1b275e58d00d18349cb840dd84b11b58416f3639e31eb95e4fb6c88eac55a378084
6
+ metadata.gz: 42aa5d35506dcaebb8a9db1e973081f38d0259eacc1da1eeeae6d530fc92055dfc70f749e4b19a4e28e3b726e92abae52e575207f1fadfa483bd2b6d6abba771
7
+ data.tar.gz: 7e97e56ac203bee46e1740e937c0869cb310d8c4edbc88ce6c2603446c5ad0989e52ffbf327be61680813ff2e92808a9ae91e09d0de9e4de5f4cedae590c2415
data/.gitignore CHANGED
@@ -34,4 +34,5 @@ build/
34
34
  # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
35
35
  .rvmrc
36
36
 
37
- .idea
37
+ .idea
38
+ amplitude-api.iml
data/.rubocop.yml CHANGED
@@ -1,8 +1,26 @@
1
1
  require: rubocop-rspec
2
+
3
+ AllCops:
4
+ TargetRubyVersion: 2.4
5
+
2
6
  Metrics/LineLength:
3
7
  Max: 120
4
8
 
9
+ Style/StringLiterals:
10
+ EnforcedStyle: double_quotes
11
+ SupportedStyles:
12
+ - single_quotes
13
+ - double_quotes
14
+
15
+ Style/BlockDelimiters:
16
+ Enabled: true
17
+ Exclude:
18
+ - spec/**/*
19
+
5
20
  # Disable some failing rspec cops that fail from upgrading gems until we can clean things up a bit.
21
+ Naming/FileName:
22
+ Exclude:
23
+ - lib/amplitude-api.rb
6
24
  RSpec/ExampleLength:
7
25
  Enabled: false
8
26
  Metrics/BlockLength:
@@ -14,4 +32,4 @@ RSpec/NestedGroups:
14
32
  RSpec/MessageSpies:
15
33
  Enabled: false
16
34
  RSpec/ContextWording:
17
- Enabled: false
35
+ Enabled: false
data/.travis.yml CHANGED
@@ -1,6 +1,5 @@
1
1
  language: ruby
2
2
  cache: bundler
3
3
  rvm:
4
- - 2.3.1
5
- - 2.2.2
6
- - 2.1.6
4
+ - 2.6
5
+ - 2.4
data/Changelog.md CHANGED
@@ -3,6 +3,28 @@
3
3
  We would like to think our many [contributors](https://github.com/toothrot/amplitude-api/graphs/contributors) for
4
4
  suggestions, ideas and improvements to Amplitude API.
5
5
 
6
+ ## 0.3.0 (2021-02-22)
7
+
8
+ * Changes Typhoeus to Faraday to launch requests
9
+ * Adds new API fields to Event
10
+ * Event can now include arbitrary properties, so it could be used if the API adds new ones.
11
+
12
+ ## 0.2.0 (2021-02-14)
13
+
14
+ * Updates gem to use HTTP API V2.
15
+
16
+ ## 0.1.1 (2019-01-01)
17
+
18
+ * Fix #41 - Delete API now correctly handles Arrays of IDs.
19
+
20
+ ## 0.1.0 (2019-01-01)
21
+
22
+ * Update Gem dependencies (thanks @kolorahl, @itamar, @krettan)
23
+ * Minimum ruby version is now 2.2
24
+ * Support Delete API (thanks @samjohn)
25
+ * Fix bundle Inline (thanks @jonduarte)
26
+ * Many fixes from @kolorahl
27
+
6
28
  ## 0.0.10 (2017-09-13)
7
29
 
8
30
  * Allow to use "Event Segmentation" via API ([#23](https://github.com/toothrot/amplitude-api/pull/23)).
data/Gemfile CHANGED
@@ -1,12 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Generated from /Users/alex/development/amplitude-api/amplitude-api.gemspec
2
- source 'https://rubygems.org'
4
+ source "https://rubygems.org"
3
5
 
4
- gem 'typhoeus', '~> 1.1'
6
+ gem "faraday", "~> 1.3"
5
7
 
6
8
  group :development, :test do
7
- gem 'pry', '~> 0.12.2'
8
- gem 'rake', '>= 12.0'
9
- gem 'rspec', '>= 2.99.0'
10
- gem 'rubocop', '~> 0.66.0', require: false
11
- gem 'rubocop-rspec'
9
+ gem "pry", "~> 0.12.2"
10
+ gem "rake", ">= 12.0"
11
+ gem "rspec", ">= 2.99.0"
12
+ gem "rubocop", "~> 0.66.0", require: false
13
+ gem "rubocop-rspec"
12
14
  end
data/Gemfile.lock CHANGED
@@ -4,11 +4,14 @@ GEM
4
4
  ast (2.4.0)
5
5
  coderay (1.1.2)
6
6
  diff-lcs (1.3)
7
- ethon (0.12.0)
8
- ffi (>= 1.3.0)
9
- ffi (1.10.0)
7
+ faraday (1.3.0)
8
+ faraday-net_http (~> 1.0)
9
+ multipart-post (>= 1.2, < 3)
10
+ ruby2_keywords
11
+ faraday-net_http (1.0.1)
10
12
  jaro_winkler (1.5.2)
11
13
  method_source (0.9.2)
14
+ multipart-post (2.1.1)
12
15
  parallel (1.17.0)
13
16
  parser (2.6.2.0)
14
17
  ast (~> 2.4.0)
@@ -17,7 +20,7 @@ GEM
17
20
  method_source (~> 0.9.0)
18
21
  psych (3.1.0)
19
22
  rainbow (3.0.0)
20
- rake (12.3.2)
23
+ rake (12.3.3)
21
24
  rspec (3.8.0)
22
25
  rspec-core (~> 3.8.0)
23
26
  rspec-expectations (~> 3.8.0)
@@ -42,20 +45,19 @@ GEM
42
45
  rubocop-rspec (1.32.0)
43
46
  rubocop (>= 0.60.0)
44
47
  ruby-progressbar (1.10.0)
45
- typhoeus (1.3.1)
46
- ethon (>= 0.9.0)
48
+ ruby2_keywords (0.0.4)
47
49
  unicode-display_width (1.5.0)
48
50
 
49
51
  PLATFORMS
50
52
  ruby
51
53
 
52
54
  DEPENDENCIES
55
+ faraday (~> 1.3)
53
56
  pry (~> 0.12.2)
54
57
  rake (>= 12.0)
55
58
  rspec (>= 2.99.0)
56
59
  rubocop (~> 0.66.0)
57
60
  rubocop-rspec
58
- typhoeus (~> 1.1)
59
61
 
60
62
  BUNDLED WITH
61
- 1.17.2
63
+ 1.17.3
data/Rakefile CHANGED
@@ -1,14 +1,16 @@
1
- require 'bundler/gem_tasks'
2
- require 'rubocop/rake_task'
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rubocop/rake_task"
3
5
 
4
6
  RuboCop::RakeTask.new
5
7
 
6
8
  begin
7
- require 'rspec/core/rake_task'
9
+ require "rspec/core/rake_task"
8
10
  RSpec::Core::RakeTask.new(:spec)
9
11
  rescue LoadError
10
- puts 'Unable to load rspec. Have you run `bundle install`?'
12
+ puts "Unable to load rspec. Have you run `bundle install`?"
11
13
  end
12
14
 
13
15
  task(:default).clear
14
- task default: ['rubocop:auto_correct', :spec]
16
+ task default: ["rubocop:auto_correct", :spec]
@@ -1,25 +1,27 @@
1
- lib = File.expand_path('lib', __dir__)
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path("lib", __dir__)
2
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
- require 'amplitude_api/version'
5
+ require "amplitude_api/version"
4
6
 
5
7
  Gem::Specification.new do |spec|
6
- spec.name = 'amplitude-api'
8
+ spec.name = "amplitude-api"
7
9
  spec.version = AmplitudeAPI::VERSION
8
- spec.authors = ['Alex Rakoczy']
9
- spec.email = ['arakoczy@gmail.com']
10
- spec.summary = 'Send events to the Amplitude API'
11
- spec.description = 'Provides an integration for sending events to Amplitude'
12
- spec.homepage = 'https://github.com/toothrot/amplitude-api'
13
- spec.license = 'MIT'
10
+ spec.authors = ["Alex Rakoczy"]
11
+ spec.email = ["arakoczy@gmail.com"]
12
+ spec.summary = "Send events to the Amplitude API"
13
+ spec.description = "Provides an integration for sending events to Amplitude"
14
+ spec.homepage = "https://github.com/toothrot/amplitude-api"
15
+ spec.license = "MIT"
14
16
 
15
17
  spec.files = `git ls-files -z`.split("\x0")
16
18
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
19
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
- spec.require_paths = ['lib']
20
+ spec.require_paths = ["lib"]
19
21
 
20
- spec.add_development_dependency 'pry', '~> 0.12.2'
21
- spec.add_development_dependency 'rake', '~> 12.0', '>= 12.0'
22
- spec.add_development_dependency 'rspec', '~> 2.99', '>= 2.99.0'
23
- spec.add_dependency 'typhoeus', '~> 1.0'
24
- spec.required_ruby_version = '~> 2.2'
22
+ spec.add_development_dependency "pry", "~> 0.12.2"
23
+ spec.add_development_dependency "rake", "~> 12.0", ">= 12.0"
24
+ spec.add_development_dependency "rspec", "~> 2.99", ">= 2.99.0"
25
+ spec.add_dependency "faraday", "~> 1.3"
26
+ spec.required_ruby_version = ">= 2.4"
25
27
  end
data/lib/amplitude-api.rb CHANGED
@@ -1,4 +1,3 @@
1
- # rubocop:disable Style/FileName
2
- require_relative 'amplitude_api'
3
- # rubocop:enable Style/FileName
4
- # Whoops.
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "amplitude_api"
@@ -1,4 +1,6 @@
1
- require 'singleton'
1
+ # frozen_string_literal: true
2
+
3
+ require "singleton"
2
4
 
3
5
  class AmplitudeAPI
4
6
  # AmplitudeAPI::Config
@@ -13,13 +15,32 @@ class AmplitudeAPI
13
15
  end
14
16
 
15
17
  class << self
18
+ def base_properties
19
+ %i[event_type event_properties user_properties user_id device_id]
20
+ end
21
+
22
+ def revenue_properties
23
+ %i[revenue_type product_id revenue price quantity]
24
+ end
25
+
26
+ def optional_properties
27
+ %i[
28
+ time
29
+ ip platform country insert_id
30
+ groups app_version os_name os_version
31
+ device_brand device_manufacturer device_model
32
+ carrier region city dma language
33
+ location_lat location_lng
34
+ idfa idfv adid android_id
35
+ event_id session_id
36
+ ]
37
+ end
38
+
16
39
  def defaults
17
40
  {
18
41
  api_key: nil,
19
42
  secret_key: nil,
20
- whitelist: %i[user_id device_id event_type time
21
- event_properties user_properties time ip platform country insert_id
22
- revenue_type price quantity product_id],
43
+ whitelist: base_properties + revenue_properties + optional_properties,
23
44
  time_formatter: ->(time) { time ? time.to_i * 1_000 : nil },
24
45
  event_properties_formatter: ->(props) { props || {} },
25
46
  user_properties_formatter: ->(props) { props || {} }
@@ -1,3 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This class is 115 lines long. It's on the limit, it should be refactored before
4
+ # including more code.
5
+ #
6
+ # rubocop:disable Metrics/ClassLength
1
7
  class AmplitudeAPI
2
8
  # AmplitudeAPI::Event
3
9
  class Event
@@ -7,13 +13,43 @@ class AmplitudeAPI
7
13
 
8
14
  # Create a new Event
9
15
  #
10
- # See (Amplitude HTTP API Documentation)[https://amplitude.zendesk.com/hc/en-us/articles/204771828-HTTP-API]
16
+ # See (Amplitude HTTP API Documentation)[https://developers.amplitude.com/docs/http-api-v2]
11
17
  # for a list of valid parameters and their types.
12
18
  def initialize(attributes = {})
13
19
  attributes.each do |k, v|
14
20
  send("#{k}=", v) if respond_to?("#{k}=")
15
21
  end
16
22
  validate_arguments
23
+ @extra_properties = []
24
+ end
25
+
26
+ def method_missing(method_name, *args)
27
+ super if block_given?
28
+
29
+ property_name = method_name.to_s.delete_suffix("=")
30
+
31
+ @extra_properties << property_name
32
+
33
+ create_setter property_name
34
+ create_getter property_name
35
+
36
+ send("#{property_name}=".to_sym, *args)
37
+ end
38
+
39
+ def create_setter(attribute_name)
40
+ self.class.send(:define_method, "#{attribute_name}=".to_sym) do |value|
41
+ instance_variable_set("@" + attribute_name.to_s, value)
42
+ end
43
+ end
44
+
45
+ def create_getter(attribute_name)
46
+ self.class.send(:define_method, attribute_name.to_sym) do
47
+ instance_variable_get("@" + attribute_name.to_s)
48
+ end
49
+ end
50
+
51
+ def respond_to_missing?(method_name, *args)
52
+ @extra_properties.include?(method_name) || @extra_properties.include?("#{method_name}=") || super
17
53
  end
18
54
 
19
55
  def user_id=(value)
@@ -36,28 +72,42 @@ class AmplitudeAPI
36
72
  }
37
73
  event[:user_id] = user_id if user_id
38
74
  event[:device_id] = device_id if device_id
39
- event.merge(optional_properties).merge(revenue_hash)
75
+ event.merge(optional_properties).merge(revenue_hash).merge(extra_properties)
40
76
  end
41
77
  alias to_h to_hash
42
78
 
43
79
  # @return [ Hash ] Optional properties
80
+ #
81
+ # Returns optional properties (belong to the API but are optional)
44
82
  def optional_properties
45
- %i[device_id time ip platform country insert_id].map do |prop|
83
+ AmplitudeAPI::Config.optional_properties.map do |prop|
46
84
  val = prop == :time ? formatted_time : send(prop)
47
85
  val ? [prop, val] : nil
48
86
  end.compact.to_h
49
87
  end
50
88
 
89
+ # @return [ Hash ] Extra properties
90
+ #
91
+ # Returns optional properties (not belong to the API, are assigned by the user)
92
+ # This way, if the API is updated with new properties, the gem will be able
93
+ # to work with the new specification until the code is modified
94
+ def extra_properties
95
+ @extra_properties.map do |prop|
96
+ val = send(prop)
97
+ val ? [prop.to_sym, val] : nil
98
+ end.compact.to_h
99
+ end
100
+
51
101
  # @return [ true, false ]
52
102
  #
53
103
  # Returns true if the event type matches one reserved by Amplitude API.
54
104
  def reserved_event?(type)
55
- ['[Amplitude] Start Session',
56
- '[Amplitude] End Session',
57
- '[Amplitude] Revenue',
58
- '[Amplitude] Revenue (Verified)',
59
- '[Amplitude] Revenue (Unverified)',
60
- '[Amplitude] Merged User'].include?(type)
105
+ ["[Amplitude] Start Session",
106
+ "[Amplitude] End Session",
107
+ "[Amplitude] Revenue",
108
+ "[Amplitude] Revenue (Verified)",
109
+ "[Amplitude] Revenue (Unverified)",
110
+ "[Amplitude] Merged User"].include?(type)
61
111
  end
62
112
 
63
113
  # @return [ true, false ]
@@ -89,15 +139,23 @@ class AmplitudeAPI
89
139
  end
90
140
 
91
141
  def validate_required_arguments
92
- raise ArgumentError, 'You must provide user_id or device_id (or both)' unless user_id || device_id
93
- raise ArgumentError, 'You must provide event_type' unless event_type
94
- raise ArgumentError, 'Invalid event_type - cannot match a reserved event name' if reserved_event?(event_type)
142
+ raise ArgumentError, "You must provide user_id or device_id (or both)" unless user_id || device_id
143
+ raise ArgumentError, "You must provide event_type" unless event_type
144
+ raise ArgumentError, "Invalid event_type - cannot match a reserved event name" if reserved_event?(event_type)
95
145
  end
96
146
 
97
147
  def validate_revenue_arguments
98
- return self.quantity ||= 1 if price
99
- raise ArgumentError, 'You must provide a price in order to use the product_id' if product_id
100
- raise ArgumentError, 'You must provide a price in order to use the revenue_type' if revenue_type
148
+ return true if !revenue_type && !product_id
149
+ return true if revenue || price
150
+
151
+ raise ArgumentError, revenue_error_message
152
+ end
153
+
154
+ def revenue_error_message
155
+ error_field = "product_id" if product_id
156
+ error_field = "revenue_type" if revenue_type
157
+
158
+ "You must provide a price or a revenue in order to use the field #{error_field}"
101
159
  end
102
160
 
103
161
  def revenue_hash
@@ -106,6 +164,7 @@ class AmplitudeAPI
106
164
  revenue_hash[:revenueType] = revenue_type if revenue_type
107
165
  revenue_hash[:quantity] = quantity if quantity
108
166
  revenue_hash[:price] = price if price
167
+ revenue_hash[:revenue] = revenue if revenue
109
168
  revenue_hash
110
169
  end
111
170
 
@@ -114,3 +173,4 @@ class AmplitudeAPI
114
173
  end
115
174
  end
116
175
  end
176
+ # rubocop:enable Metrics/ClassLength
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class AmplitudeAPI
2
4
  # AmplitudeAPI::Identification
3
5
  class Identification
@@ -16,7 +18,7 @@ class AmplitudeAPI
16
18
  # @param [ String ] user_id a user_id to associate with the identification
17
19
  # @param [ String ] device_id a device_id to associate with the identification
18
20
  # @param [ Hash ] user_properties various properties to attach to the user identification
19
- def initialize(user_id: '', device_id: nil, user_properties: {})
21
+ def initialize(user_id: "", device_id: nil, user_properties: {})
20
22
  self.user_id = user_id
21
23
  self.device_id = device_id if device_id
22
24
  self.user_properties = user_properties