firebase-stats 0.1.0 → 1.0.5
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 +4 -4
- data/bin/firebase-stats +56 -15
- data/lib/device_utils.rb +24 -0
- data/lib/firebase-stats.rb +2 -0
- data/lib/reader.rb +2 -2
- data/lib/version.rb +5 -0
- data/lib/wrapper.rb +110 -71
- metadata +67 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4c0052a1fd763bfd20e4561f5381098bc8436252f25ca478a51f152d9c9edc1f
|
4
|
+
data.tar.gz: 5057c8cf57c562d489d60ecf7d35fa4172ad025937da9b7fd3ddd72b09e8b86c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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, '
|
10
|
-
program :version,
|
11
|
-
program :description, 'CLI to
|
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 = '
|
24
|
+
c.syntax = 'devices <path to csv> [options]'
|
25
25
|
c.summary = 'Prints out device stats'
|
26
|
-
c.description = ''
|
27
|
-
c.option '--friendly', '
|
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
|
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 = '
|
42
|
-
c.summary = 'Prints out
|
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
|
56
|
+
wrapper = FirebaseStats::Wrapper.new(stats)
|
53
57
|
|
54
|
-
|
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
|
data/lib/device_utils.rb
ADDED
@@ -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
|
data/lib/firebase-stats.rb
CHANGED
data/lib/reader.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
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.
|
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
data/lib/wrapper.rb
CHANGED
@@ -1,76 +1,85 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
module FirebaseStats
|
4
4
|
require 'csv'
|
5
|
-
|
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
|
-
|
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
|
-
|
18
|
-
|
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
|
-
|
23
|
-
'
|
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
|
-
|
28
|
-
|
29
|
-
|
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
|
-
|
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
|
-
|
57
|
+
cleaned
|
49
58
|
end
|
50
59
|
|
51
|
-
def
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
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
|
-
|
69
|
+
data
|
58
70
|
end
|
59
71
|
|
60
|
-
def
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
'
|
66
|
-
'
|
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
|
-
|
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['
|
92
|
+
os_data.select { |row| row['version'].downcase.include?('android') }
|
84
93
|
when :ios
|
85
|
-
os_data.select { |row| row['
|
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['
|
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['
|
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:
|
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-
|
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
|
-
|
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://
|
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: '
|
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.
|
131
|
+
rubygems_version: 3.2.14
|
73
132
|
signing_key:
|
74
133
|
specification_version: 4
|
75
|
-
summary: Firebase CSV Stats
|
134
|
+
summary: Firebase CSV Stats CLI
|
76
135
|
test_files: []
|