firebase-stats 0.1.0 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1f9de921405769947da53d014425be7283f4417086404cf286aec2878ef76626
4
- data.tar.gz: 1a3e5974d548846245ac4cf82514d6cd5032b539031b23bca24d48ea9cc4276d
3
+ metadata.gz: 4c0052a1fd763bfd20e4561f5381098bc8436252f25ca478a51f152d9c9edc1f
4
+ data.tar.gz: 5057c8cf57c562d489d60ecf7d35fa4172ad025937da9b7fd3ddd72b09e8b86c
5
5
  SHA512:
6
- metadata.gz: ddc6212d166cc9adde36d87cd1e683dd9595461d30832b7baddde6bbd5fa5cfbd3379f2cf4129c59196db6d7cf6df15a95907d5bd18364b56de9777c29b36653
7
- data.tar.gz: 4a9557ea13c60f54c1c4015c8fd1b817b4b17fd1dbbcb652a74f02be52c7046a8187f818b1bf0cb7740b5aab29b0878a4c281bbe397edcaa8791228c07cdb6eb
6
+ metadata.gz: 2e36f05b2e942c81ebd86db0ddaff06aecca5e8167bf233591a32df06489b31b52985d6636d00dfcedd2c82ff914430c03d220297f3d93456b658c012b8240be
7
+ data.tar.gz: f74f39bd93fcfc0fc0c93ed6f11d9485d1635cbcbb64c0ca046cd91eb5f0828f8acaa9c3e3c2640cec4c62f00ef4cadf4f92dbe5e9b1dbe5d9c7ea07b5bba498
data/bin/firebase-stats CHANGED
@@ -6,11 +6,11 @@ require 'commander/import'
6
6
  require 'firebase-stats'
7
7
  require 'table_print'
8
8
 
9
- program :name, 'firebase_stats_cli'
10
- program :version, '0.1.0'
11
- program :description, 'CLI to view stuff from the Firebase Analytics CSV'
9
+ program :name, 'firebase-stats'
10
+ program :version, FirebaseStats::VERSION
11
+ program :description, 'A CLI tool to get different stats out of the huge Firebase Analytics CSV'
12
+ program :help_formatter, Commander::HelpFormatter::TerminalCompact
12
13
 
13
- global_option('--platform STRING', String, 'Show only stats for this OS. Either ios, android or all (default)')
14
14
 
15
15
  def map_platform(options)
16
16
  raw_platform = options.platform ||= 'all'
@@ -21,10 +21,12 @@ def map_platform(options)
21
21
  end
22
22
 
23
23
  command :devices do |c|
24
- c.syntax = 'firebase_stats_cli devices [options]'
24
+ c.syntax = 'devices <path to csv> [options]'
25
25
  c.summary = 'Prints out device stats'
26
- c.description = ''
27
- c.option '--friendly', 'Maps Android model numbers to friendly names'
26
+ c.description = 'Prints out a table with all of the devices, optionally filtered by OS'
27
+ c.option '--friendly', 'Prints out Android device models with their human readable name (this is slow)'
28
+ c.option '--limit NUMBER', Integer, 'Limits number of devices output'
29
+ c.option '--platform STRING', String, 'Show only stats for this OS. Either ios, android or all (default)'
28
30
 
29
31
  c.action do |args, options|
30
32
  stats = FirebaseStats::Reader.new
@@ -32,16 +34,18 @@ command :devices do |c|
32
34
 
33
35
  platform = map_platform(options)
34
36
 
35
- wrapper = FirebaseStats::Wrapper.new(stats, platform)
36
- tp wrapper.devices(friendly: options.friendly)
37
+ wrapper = FirebaseStats::Wrapper.new(stats)
38
+ tp wrapper.devices(friendly: options.friendly, limit: options.limit, platform: platform)
37
39
  end
38
40
  end
39
41
 
40
42
  command :os do |c|
41
- c.syntax = 'firebase_stats_cli os [options]'
42
- c.summary = 'Prints out all of the data'
43
- c.description = ''
44
- c.option '--grouped', 'Groups OS versions together'
43
+ c.syntax = 'os <path to csv> [options]'
44
+ c.summary = 'Prints out OS stats'
45
+ c.description = 'Prints out the number of devices per OS version, optionally filtered by OS and grouped by major version'
46
+ c.option '--grouped', 'Groups minor OS versions together'
47
+ c.option '--version-sorted', 'Sorts by OS version instead of percentage'
48
+ c.option '--platform STRING', String, 'Show only stats for this OS. Either ios, android or all (default)'
45
49
 
46
50
  c.action do |args, options|
47
51
  stats = FirebaseStats::Reader.new
@@ -49,8 +53,45 @@ command :os do |c|
49
53
 
50
54
  platform = map_platform(options)
51
55
 
52
- wrapper = FirebaseStats::Wrapper.new(stats, platform)
56
+ wrapper = FirebaseStats::Wrapper.new(stats)
53
57
 
54
- options.grouped.nil? ? tp(wrapper.os_version) : tp(wrapper.os_grouped)
58
+ grouped = options.grouped || false
59
+ major_order = options.version_sorted || false
60
+
61
+ data = wrapper.os(platform: platform, grouped: grouped, major_order: major_order)
62
+
63
+ tp data
64
+ end
65
+ end
66
+
67
+ command :gender do |c|
68
+ c.syntax = 'gender'
69
+ c.summary = 'Prints out gender stats (if available)'
70
+ c.description = 'Prints out a table with number of users of each gender'
71
+
72
+ c.action do |args, options|
73
+ stats = FirebaseStats::Reader.new
74
+ stats.parse_file(args[0])
75
+
76
+ platform = map_platform(options)
77
+
78
+ wrapper = FirebaseStats::Wrapper.new(stats)
79
+ tp wrapper.gender
80
+ end
81
+ end
82
+
83
+ command :gender_age do |c|
84
+ c.syntax = 'gender_age'
85
+ c.summary = 'Prints out age group stats (if available)'
86
+ c.description = 'Prints out a table with percentage of users of each gender grouped by age'
87
+
88
+ c.action do |args, options|
89
+ stats = FirebaseStats::Reader.new
90
+ stats.parse_file(args[0])
91
+
92
+ platform = map_platform(options)
93
+
94
+ wrapper = FirebaseStats::Wrapper.new(stats)
95
+ tp wrapper.gender_age
55
96
  end
56
97
  end
@@ -0,0 +1,24 @@
1
+ module FirebaseStats
2
+ # Parses the Firebase CSV file into sections
3
+ class DeviceUtils
4
+ # Is this device name an iOS device?
5
+ # @param [CSV::Row] device_name
6
+ def self.ios_device?(device_name)
7
+ device_name.downcase.include?('iphone') or device_name.downcase.include?('ipad') or device_name.downcase.include?('ipod')
8
+ end
9
+
10
+ # Filters a device list to only the requested platform
11
+ # @param [CSV::Table] device_data
12
+ # @param [Symbol] platform One of :all, :ios, :android
13
+ def self.filter_device(device_data, platform)
14
+ case platform
15
+ when :android
16
+ device_data.reject { |row| ios_device? row['Device model'] }
17
+ when :ios
18
+ device_data.select { |row| ios_device? row['Device model'] }
19
+ else
20
+ device_data
21
+ end
22
+ end
23
+ end
24
+ end
@@ -2,3 +2,5 @@
2
2
 
3
3
  require 'reader'
4
4
  require 'wrapper'
5
+ require 'version'
6
+ require 'device_utils'
data/lib/reader.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class FirebaseStats
3
+ module FirebaseStats
4
4
  require 'csv'
5
5
 
6
6
  # Parses the Firebase CSV file into sections
@@ -22,7 +22,7 @@ class FirebaseStats
22
22
  def parse(input)
23
23
  curr_lines = []
24
24
  input.each_with_index do |line, idx|
25
- curr_lines.append(line) unless comment?(line) || line.strip.empty?
25
+ curr_lines.push(line) unless comment?(line) || line.strip.empty?
26
26
 
27
27
  if (idx == input.length - 1) || line.strip.empty?
28
28
  process_lines curr_lines unless curr_lines.empty?
data/lib/version.rb ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FirebaseStats
4
+ VERSION = '1.0.5'
5
+ end
data/lib/wrapper.rb CHANGED
@@ -1,76 +1,85 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class FirebaseStats
3
+ module FirebaseStats
4
4
  require 'csv'
5
- # require 'android/devices'
5
+ require 'android/devices'
6
+ require 'open-uri'
6
7
 
7
8
  # Transforms the parsed Firebase file into something more user friendly
8
9
  class Wrapper
9
10
  # @param [FirebaseStats::Reader] stats
10
- # @param [Symbol] platform One of :all, :ios, :android
11
- def initialize(stats, platform = :all)
11
+ def initialize(stats)
12
12
  super()
13
13
  @stats = stats
14
- @platform = platform
15
14
  end
16
15
 
17
- def os_version
18
- filtered = filter_os(@stats.data[:os_version], @platform)
16
+ # Get all OS versions, grouped by Major version
17
+ # @param [Symbol] platform One of :all, :ios, :android
18
+ # @param [Boolean] grouped Group by Major OS version
19
+ # @param [Boolean] major_order Order by Major OS version (instead of percentage)
20
+ def os(platform: :all, grouped: true, major_order: true)
21
+ os_data = all_os
22
+ filtered = filter_os(os_data, platform)
23
+
24
+ data = if grouped
25
+ make_group_stats(filtered, platform)
26
+ else
27
+ filtered
28
+ end
19
29
 
30
+ major_order ? major_version_sort(data) : data
31
+ end
32
+
33
+ # Gets all devices
34
+ # @param [Boolean] friendly Transform the Android model numbers into their human numaes
35
+ # @param [Integer] limit Number of devices to turn
36
+ # @param [Symbol] platform One of :all, :ios, :android
37
+ def devices(friendly: false, limit: 10, platform: :all)
38
+ filtered = DeviceUtils.filter_device(@stats.data[:devices], platform)
39
+ filtered = filtered.take(limit || 10)
20
40
  cleaned = []
21
41
  filtered.each do |row|
22
- cleaned << {
23
- 'version' => row['OS with version'],
24
- 'count' => row['Users'].to_i,
25
- 'percentage' => as_percentage(os_total, row['Users'].to_f)
42
+ device = {
43
+ 'model' => row['Device model']
26
44
  }
27
- end
28
- cleaned
29
- end
45
+ if friendly && ((platform == :all) || (platform == :android))
46
+ mapped = Android::Devices.search_by_model(row['Device model'])
47
+ device['friendly'] = if mapped.nil?
48
+ row['Device model']
49
+ else
50
+ mapped.name
51
+ end
52
+ end
53
+ device['count'] = row['Users'].to_i
30
54
 
31
- def os_grouped
32
- raw_os = @stats.data[:os_version]
33
-
34
- grouped = case @platform
35
- when :ios
36
- ios_os_group(raw_os)
37
- when :android
38
- android_os_group(raw_os)
39
- else
40
- android_os_group(raw_os).merge ios_os_group(raw_os)
41
- end
42
- computed = []
43
- grouped.each do |k, v|
44
- version_name = k
45
- total = v.map { |version| version['Users'].to_i }.reduce(0, :+)
46
- computed << { 'version' => version_name, 'total' => total, 'percentage' => as_percentage(os_total, total.to_f) }
55
+ cleaned << device
47
56
  end
48
- computed
57
+ cleaned
49
58
  end
50
59
 
51
- def os_total
52
- filtered = filter_os(@stats.data[:os_version], @platform)
53
- total = 0
54
- filtered.each do |row|
55
- total += row['Users'].to_i
60
+ def gender
61
+ raw = @stats.data[:gender]
62
+ data = []
63
+ raw.each do |row|
64
+ data << {
65
+ 'gender' => row['Gender'],
66
+ 'count' => row['Users']
67
+ }
56
68
  end
57
- total
69
+ data
58
70
  end
59
71
 
60
- def devices(friendly: false)
61
- filtered = filter_device(@stats.data[:devices], @platform)
62
- cleaned = []
63
- filtered.each do |row|
64
- device = {
65
- 'model' => row['Device model'],
66
- 'count' => row['Users'].to_i
72
+ def gender_age
73
+ raw = @stats.data[:gender_age]
74
+ data = []
75
+ raw.each do |row|
76
+ data << {
77
+ 'age' => row['Category'],
78
+ 'male' => (row['Male'].to_f * 100).round(2),
79
+ 'female' => (row['Female'].to_f * 100).round(2)
67
80
  }
68
- # if friendly && ((@platform == :all) || (@platform == :android))
69
- # device['friendly'] = Android::Devices.search_by_model(row['Device Model']).name
70
- # end
71
- cleaned << device
72
81
  end
73
- cleaned
82
+ data
74
83
  end
75
84
 
76
85
  private
@@ -80,32 +89,14 @@ class FirebaseStats
80
89
  def filter_os(os_data, platform)
81
90
  case platform
82
91
  when :android
83
- os_data.select { |row| row['OS with version'].downcase.include?('android') }
92
+ os_data.select { |row| row['version'].downcase.include?('android') }
84
93
  when :ios
85
- os_data.select { |row| row['OS with version'].downcase.include?('ios') }
94
+ os_data.select { |row| row['version'].downcase.include?('ios') }
86
95
  else
87
96
  os_data
88
97
  end
89
98
  end
90
99
 
91
- # @param [CSV::Table] device_data
92
- # @param [Symbol] platform One of :all, :ios, :android
93
- def filter_device(device_data, platform)
94
- case platform
95
- when :android
96
- device_data.reject { |row| ios_device? row['Device model'] }
97
- when :ios
98
- device_data.select { |row| ios_device? row['Device model'] }
99
- else
100
- device_data
101
- end
102
- end
103
-
104
- # @param [CSV::Row] device_name
105
- def ios_device?(device_name)
106
- device_name.downcase.include?('iphone') or device_name.downcase.include?('ipad')
107
- end
108
-
109
100
  def as_percentage(total, value)
110
101
  percentage = (value / total) * 100
111
102
  if percentage < 0.01
@@ -116,11 +107,59 @@ class FirebaseStats
116
107
  end
117
108
 
118
109
  def ios_os_group(os_details)
119
- filter_os(os_details, :ios).group_by { |row| row['OS with version'].match('(iOS [0-9]{1,2})').captures[0] }
110
+ filter_os(os_details, :ios).group_by { |row| row['version'].match('(iOS [0-9]{1,2})').captures[0] }
120
111
  end
121
112
 
122
113
  def android_os_group(os_details)
123
- filter_os(os_details, :android).group_by { |row| row['OS with version'].match('(Android [0-9]{1,2})').captures[0] }
114
+ filter_os(os_details, :android).group_by { |row| row['version'].match('(Android [0-9]{1,2})').captures[0] }
115
+ end
116
+
117
+ # Get all OS versions
118
+ def all_os
119
+ data = @stats.data[:os_version]
120
+
121
+ data.map do |row|
122
+ {
123
+ 'version' => row['OS with version'],
124
+ 'count' => row['Users'].to_i
125
+ }
126
+ end
127
+ end
128
+
129
+ def make_group_stats(os_data, platform)
130
+ data = make_os_groups(os_data, platform)
131
+
132
+ total_devices = os_total(os_data)
133
+ data.map do |k, v|
134
+ version_name = k
135
+ group_total = v.map { |version| version['count'].to_i }.reduce(0, :+)
136
+ { 'version' => version_name,
137
+ 'total' => group_total,
138
+ 'percentage' => as_percentage(total_devices.to_f, group_total) }
139
+ end
140
+ end
141
+
142
+ def make_os_groups(os_data, platform)
143
+ case platform
144
+ when :ios
145
+ ios_os_group(os_data)
146
+ when :android
147
+ android_os_group(os_data)
148
+ else
149
+ android_os_group(os_data).merge ios_os_group(os_data)
150
+ end
151
+ end
152
+
153
+ def os_total(os_data)
154
+ os_data.map { |row| row['count'] }.reduce(0, :+)
155
+ end
156
+
157
+ def major_version_sort(data)
158
+ data.sort_by do |row|
159
+ version = row['version']
160
+ number = version.match('([0-9.]+)').captures[0]
161
+ Gem::Version.new(number)
162
+ end.reverse
124
163
  end
125
164
  end
126
165
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: firebase-stats
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - chedabob
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-16 00:00:00.000000000 Z
11
+ date: 2021-03-21 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: android-devices
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: commander
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -38,7 +52,50 @@ dependencies:
38
52
  - - "~>"
39
53
  - !ruby/object:Gem::Version
40
54
  version: '1.5'
41
- description: A simple h
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '13'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '13'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.10'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.10'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.10'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.10'
97
+ description: A CLI tool to get different stats out of the huge Firebase Analytics
98
+ CSV
42
99
  email: matt.malone1@gmail.com
43
100
  executables:
44
101
  - firebase-stats
@@ -47,10 +104,12 @@ extra_rdoc_files: []
47
104
  files:
48
105
  - bin/firebase-stats
49
106
  - lib/.DS_Store
107
+ - lib/device_utils.rb
50
108
  - lib/firebase-stats.rb
51
109
  - lib/reader.rb
110
+ - lib/version.rb
52
111
  - lib/wrapper.rb
53
- homepage: https://rubygems.org/gems/firebase-stats
112
+ homepage: https://github.com/chedabob/firebase-stats
54
113
  licenses:
55
114
  - MIT
56
115
  metadata: {}
@@ -60,17 +119,17 @@ require_paths:
60
119
  - lib
61
120
  required_ruby_version: !ruby/object:Gem::Requirement
62
121
  requirements:
63
- - - "~>"
122
+ - - ">="
64
123
  - !ruby/object:Gem::Version
65
- version: '3'
124
+ version: '2.4'
66
125
  required_rubygems_version: !ruby/object:Gem::Requirement
67
126
  requirements:
68
127
  - - ">="
69
128
  - !ruby/object:Gem::Version
70
129
  version: '0'
71
130
  requirements: []
72
- rubygems_version: 3.2.3
131
+ rubygems_version: 3.2.14
73
132
  signing_key:
74
133
  specification_version: 4
75
- summary: Firebase CSV Stats extractor
134
+ summary: Firebase CSV Stats CLI
76
135
  test_files: []