firebase-stats 0.1.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 +7 -0
- data/bin/firebase-stats +56 -0
- data/lib/.DS_Store +0 -0
- data/lib/firebase-stats.rb +4 -0
- data/lib/reader.rb +76 -0
- data/lib/wrapper.rb +126 -0
- metadata +76 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1f9de921405769947da53d014425be7283f4417086404cf286aec2878ef76626
|
4
|
+
data.tar.gz: 1a3e5974d548846245ac4cf82514d6cd5032b539031b23bca24d48ea9cc4276d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ddc6212d166cc9adde36d87cd1e683dd9595461d30832b7baddde6bbd5fa5cfbd3379f2cf4129c59196db6d7cf6df15a95907d5bd18364b56de9777c29b36653
|
7
|
+
data.tar.gz: 4a9557ea13c60f54c1c4015c8fd1b817b4b17fd1dbbcb652a74f02be52c7046a8187f818b1bf0cb7740b5aab29b0878a4c281bbe397edcaa8791228c07cdb6eb
|
data/bin/firebase-stats
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'commander/import'
|
6
|
+
require 'firebase-stats'
|
7
|
+
require 'table_print'
|
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'
|
12
|
+
|
13
|
+
global_option('--platform STRING', String, 'Show only stats for this OS. Either ios, android or all (default)')
|
14
|
+
|
15
|
+
def map_platform(options)
|
16
|
+
raw_platform = options.platform ||= 'all'
|
17
|
+
platform = :all
|
18
|
+
platform = :ios if raw_platform.downcase.include?('ios')
|
19
|
+
platform = :android if raw_platform.downcase.include?('android')
|
20
|
+
platform
|
21
|
+
end
|
22
|
+
|
23
|
+
command :devices do |c|
|
24
|
+
c.syntax = 'firebase_stats_cli devices [options]'
|
25
|
+
c.summary = 'Prints out device stats'
|
26
|
+
c.description = ''
|
27
|
+
c.option '--friendly', 'Maps Android model numbers to friendly names'
|
28
|
+
|
29
|
+
c.action do |args, options|
|
30
|
+
stats = FirebaseStats::Reader.new
|
31
|
+
stats.parse_file(args[0])
|
32
|
+
|
33
|
+
platform = map_platform(options)
|
34
|
+
|
35
|
+
wrapper = FirebaseStats::Wrapper.new(stats, platform)
|
36
|
+
tp wrapper.devices(friendly: options.friendly)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
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'
|
45
|
+
|
46
|
+
c.action do |args, options|
|
47
|
+
stats = FirebaseStats::Reader.new
|
48
|
+
stats.parse_file(args[0])
|
49
|
+
|
50
|
+
platform = map_platform(options)
|
51
|
+
|
52
|
+
wrapper = FirebaseStats::Wrapper.new(stats, platform)
|
53
|
+
|
54
|
+
options.grouped.nil? ? tp(wrapper.os_version) : tp(wrapper.os_grouped)
|
55
|
+
end
|
56
|
+
end
|
data/lib/.DS_Store
ADDED
Binary file
|
data/lib/reader.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class FirebaseStats
|
4
|
+
require 'csv'
|
5
|
+
|
6
|
+
# Parses the Firebase CSV file into sections
|
7
|
+
class Reader
|
8
|
+
attr_reader :data
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
super
|
12
|
+
@data = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
# @param [String] filename
|
16
|
+
def parse_file(filename)
|
17
|
+
lines = File.readlines(filename)
|
18
|
+
parse(lines)
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param [Array<String>] input
|
22
|
+
def parse(input)
|
23
|
+
curr_lines = []
|
24
|
+
input.each_with_index do |line, idx|
|
25
|
+
curr_lines.append(line) unless comment?(line) || line.strip.empty?
|
26
|
+
|
27
|
+
if (idx == input.length - 1) || line.strip.empty?
|
28
|
+
process_lines curr_lines unless curr_lines.empty?
|
29
|
+
curr_lines = []
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
# @param [Array<String>] lines
|
37
|
+
def process_lines(lines)
|
38
|
+
section = match_header lines[0]
|
39
|
+
return if section.nil?
|
40
|
+
|
41
|
+
parsed = CSV.parse(lines.join, headers: true)
|
42
|
+
@data[section] = parsed if @data[section].nil?
|
43
|
+
end
|
44
|
+
|
45
|
+
# @param [String] header
|
46
|
+
# @return [Symbol, nil]
|
47
|
+
# rubocop:disable Metrics/MethodLength
|
48
|
+
def match_header(header)
|
49
|
+
mappings = {
|
50
|
+
'Day,28-Day,7-Day,1-Day' => :active_users,
|
51
|
+
'Day,Average engagement time' => :daily_engagement,
|
52
|
+
'Page path and screen class,User engagement,Screen views' => :screens,
|
53
|
+
'Day,Total revenue' => :revenue,
|
54
|
+
'App,Crash-free users' => :crash_free_users,
|
55
|
+
'App,Version,Status' => :version_adoption,
|
56
|
+
'Source,first_open conversions,LTV' => :acquisition,
|
57
|
+
'Date,Week 0,Week 1,Week 2,Week 3,Week 4,Week 5' => :retention_cohorts,
|
58
|
+
'Country ID,Sessions,% Total' => :audience_country,
|
59
|
+
'Device model,Users' => :devices,
|
60
|
+
'OS with version,Users' => :os_version,
|
61
|
+
'Gender,Users' => :gender,
|
62
|
+
'Category,Female,Male' => :gender_age,
|
63
|
+
'Platform,Users' => :platform,
|
64
|
+
'Platform,Users,% Total,User engagement,Total revenue' => :platform_engagement
|
65
|
+
}
|
66
|
+
|
67
|
+
mappings[header.strip]
|
68
|
+
end
|
69
|
+
# rubocop:enable Metrics/MethodLength
|
70
|
+
|
71
|
+
# @param [String] line
|
72
|
+
def comment?(line)
|
73
|
+
line.include?('#')
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
data/lib/wrapper.rb
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class FirebaseStats
|
4
|
+
require 'csv'
|
5
|
+
# require 'android/devices'
|
6
|
+
|
7
|
+
# Transforms the parsed Firebase file into something more user friendly
|
8
|
+
class Wrapper
|
9
|
+
# @param [FirebaseStats::Reader] stats
|
10
|
+
# @param [Symbol] platform One of :all, :ios, :android
|
11
|
+
def initialize(stats, platform = :all)
|
12
|
+
super()
|
13
|
+
@stats = stats
|
14
|
+
@platform = platform
|
15
|
+
end
|
16
|
+
|
17
|
+
def os_version
|
18
|
+
filtered = filter_os(@stats.data[:os_version], @platform)
|
19
|
+
|
20
|
+
cleaned = []
|
21
|
+
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)
|
26
|
+
}
|
27
|
+
end
|
28
|
+
cleaned
|
29
|
+
end
|
30
|
+
|
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) }
|
47
|
+
end
|
48
|
+
computed
|
49
|
+
end
|
50
|
+
|
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
|
56
|
+
end
|
57
|
+
total
|
58
|
+
end
|
59
|
+
|
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
|
67
|
+
}
|
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
|
+
end
|
73
|
+
cleaned
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
# @param [CSV::Table] os_data
|
79
|
+
# @param [Symbol] platform One of :all, :ios, :android
|
80
|
+
def filter_os(os_data, platform)
|
81
|
+
case platform
|
82
|
+
when :android
|
83
|
+
os_data.select { |row| row['OS with version'].downcase.include?('android') }
|
84
|
+
when :ios
|
85
|
+
os_data.select { |row| row['OS with version'].downcase.include?('ios') }
|
86
|
+
else
|
87
|
+
os_data
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
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
|
+
def as_percentage(total, value)
|
110
|
+
percentage = (value / total) * 100
|
111
|
+
if percentage < 0.01
|
112
|
+
percentage.round(4)
|
113
|
+
else
|
114
|
+
percentage.round(2)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
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] }
|
120
|
+
end
|
121
|
+
|
122
|
+
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] }
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
metadata
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: firebase-stats
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- chedabob
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-03-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: commander
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.5'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: table_print
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.5'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.5'
|
41
|
+
description: A simple h
|
42
|
+
email: matt.malone1@gmail.com
|
43
|
+
executables:
|
44
|
+
- firebase-stats
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- bin/firebase-stats
|
49
|
+
- lib/.DS_Store
|
50
|
+
- lib/firebase-stats.rb
|
51
|
+
- lib/reader.rb
|
52
|
+
- lib/wrapper.rb
|
53
|
+
homepage: https://rubygems.org/gems/firebase-stats
|
54
|
+
licenses:
|
55
|
+
- MIT
|
56
|
+
metadata: {}
|
57
|
+
post_install_message:
|
58
|
+
rdoc_options: []
|
59
|
+
require_paths:
|
60
|
+
- lib
|
61
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - "~>"
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '3'
|
66
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
requirements: []
|
72
|
+
rubygems_version: 3.2.3
|
73
|
+
signing_key:
|
74
|
+
specification_version: 4
|
75
|
+
summary: Firebase CSV Stats extractor
|
76
|
+
test_files: []
|