logtime 0.0.2
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
- checksums.yaml.gz.sig +0 -0
- data/.gitignore +5 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +40 -0
- data/LICENSE.md +21 -0
- data/VERSION +1 -0
- data/bin/logtime +3 -0
- data/certs/paperback.pem +21 -0
- data/config/application.rb +6 -0
- data/config/database.rb +4 -0
- data/config/initialisation.rb +8 -0
- data/config/schema.rb +41 -0
- data/lib/app/commands/add.rb +41 -0
- data/lib/app/commands/list.rb +56 -0
- data/lib/app/commands/start.rb +28 -0
- data/lib/app/commands/stop.rb +29 -0
- data/lib/app/helpers/estimate.rb +13 -0
- data/lib/app/helpers/statistics.rb +45 -0
- data/lib/app/helpers/time_to_words.rb +33 -0
- data/lib/app/logtime.rb +67 -0
- data/lib/app/models/log.rb +42 -0
- data/lib/app/models/series.rb +35 -0
- data/lib/app/models/tag.rb +9 -0
- data/lib/app/subcommands/keyword.rb +214 -0
- data/lib/app/subcommands/series.rb +58 -0
- data/lib/app/subcommands/tags.rb +79 -0
- data/lib/commands/add.rb +41 -0
- data/lib/commands/list.rb +67 -0
- data/lib/commands/start.rb +28 -0
- data/lib/commands/stop.rb +29 -0
- data/lib/commands/version.rb +12 -0
- data/lib/helpers/estimate.rb +13 -0
- data/lib/helpers/statistics.rb +48 -0
- data/lib/helpers/time_difference.rb +20 -0
- data/lib/helpers/time_display.rb +5 -0
- data/lib/helpers/time_to_words.rb +33 -0
- data/lib/logtime.rb +68 -0
- data/lib/models/log.rb +47 -0
- data/lib/models/series.rb +35 -0
- data/lib/models/tag.rb +9 -0
- data/lib/subcommands/keyword.rb +214 -0
- data/lib/subcommands/series.rb +59 -0
- data/lib/subcommands/tags.rb +37 -0
- data/logtime.gemspec +23 -0
- data.tar.gz.sig +2 -0
- metadata +167 -0
- metadata.gz.sig +0 -0
@@ -0,0 +1,214 @@
|
|
1
|
+
class Keywords < Thor
|
2
|
+
# desc "add <account> <keyword>", "Add a new <keyword> to an <account>"
|
3
|
+
# option :interactive, :type => :boolean, :alias => :i
|
4
|
+
# def add(account, keyword=nil)
|
5
|
+
# account = Account.find_by(:name => account)
|
6
|
+
|
7
|
+
# if account.blank?
|
8
|
+
# say 'no account found', :red
|
9
|
+
# else
|
10
|
+
# if options[:interactive]
|
11
|
+
# say "To stop adding keywords type exit", :cyan
|
12
|
+
# while true
|
13
|
+
# keyword = ask ':'
|
14
|
+
# break if keyword == 'exit'
|
15
|
+
# if Keyword.new(:keyword => keyword, :account_id => account.id).save
|
16
|
+
# say 'added', :green
|
17
|
+
# else
|
18
|
+
# say 'failed', :red
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
# else
|
22
|
+
# keyword.split(',').each do |k|
|
23
|
+
# k = Keyword.new(:keyword => k, :account_id => account.id)
|
24
|
+
|
25
|
+
# if k.save
|
26
|
+
# say k.keyword + ' keyword added', :green
|
27
|
+
# else
|
28
|
+
# say 'could not add keyword!', :red
|
29
|
+
# error k.errors.first[0].to_s + ' ' + k.errors.first[1]
|
30
|
+
# end
|
31
|
+
# end
|
32
|
+
# end
|
33
|
+
# end
|
34
|
+
# end
|
35
|
+
|
36
|
+
# desc "delete <account> <keyword>", "Removes <keyword> on an <account>"
|
37
|
+
# def delete(account, keyword)
|
38
|
+
# account = Account.search(account)
|
39
|
+
|
40
|
+
# if account.blank?
|
41
|
+
# say 'no account found', :red
|
42
|
+
# else
|
43
|
+
# keyword.split(',').each do |k|
|
44
|
+
# k = Keyword.search(k)
|
45
|
+
|
46
|
+
# if k.blank?
|
47
|
+
# say 'could not find keyword!', :red
|
48
|
+
# else
|
49
|
+
# say k.keyword + ' removed', :green if k.destroy
|
50
|
+
# end
|
51
|
+
# end
|
52
|
+
# end
|
53
|
+
# end
|
54
|
+
|
55
|
+
# desc "list", "Lists keywords belonging to an <account>"
|
56
|
+
# option :account
|
57
|
+
# def list(account=nil)
|
58
|
+
# if account.nil?
|
59
|
+
# keywords = Keyword.all
|
60
|
+
|
61
|
+
# table = [['# Keyword', '# Position', '']] # header
|
62
|
+
# keywords.each do |k|
|
63
|
+
# stat = k.keyword_statistics.last unless k.keyword_statistics.empty?
|
64
|
+
# table << [k.keyword, stat.position || '', stat.created_at.pretty ] # row
|
65
|
+
# end
|
66
|
+
|
67
|
+
# say ''
|
68
|
+
# print_table table
|
69
|
+
# say ''
|
70
|
+
# else
|
71
|
+
# account = Account.search(account)
|
72
|
+
# if account.blank?
|
73
|
+
# say 'no account found', :red
|
74
|
+
# elsif account.keywords.empty?
|
75
|
+
# say 'no keywords exist for that account yet', :red
|
76
|
+
# else
|
77
|
+
# table = [['# Keyword', '# Position', '']] # header
|
78
|
+
# account.keywords.each do |k|
|
79
|
+
# stat = k.keyword_statistics.last unless k.keyword_statistics.empty?
|
80
|
+
# table << [k.keyword, stat.position || '', stat.created_at.pretty] # row
|
81
|
+
# end
|
82
|
+
|
83
|
+
# say ''
|
84
|
+
# print_table table
|
85
|
+
# say ''
|
86
|
+
# end
|
87
|
+
# end
|
88
|
+
# end
|
89
|
+
|
90
|
+
# desc "stats", "Compare keywords over time"
|
91
|
+
# option :search, :default => 'year', :banner => 'year,month,week,day'
|
92
|
+
# option :length, :type => :numeric, :default => 1
|
93
|
+
# option :engine, :default => :google
|
94
|
+
# def stats(account)
|
95
|
+
# account = Account.search(account)
|
96
|
+
|
97
|
+
# if account.blank?
|
98
|
+
# say 'no account found', :red
|
99
|
+
# elsif account.keywords.empty?
|
100
|
+
# say 'no keywords exist for that account yet', :red
|
101
|
+
# else
|
102
|
+
|
103
|
+
# table = [['# Keyword', 'n', 'High', 'Low', 'Current', 'Delta']] # header
|
104
|
+
# searched = 0;
|
105
|
+
# account.keywords.each do |k|
|
106
|
+
# stats = KeywordStatistic.send options[:search], k.id, options[:length], options[:engine]
|
107
|
+
# stats.order(:position)
|
108
|
+
|
109
|
+
# if !stats.empty?
|
110
|
+
# delta = stats.last.position - stats.first.position
|
111
|
+
# delta = '' if delta == 0
|
112
|
+
# table << [k.keyword, stats.size, stats.last.position, stats.first.position, stats.last.position, delta] # row
|
113
|
+
# searched = searched + stats.size
|
114
|
+
# end
|
115
|
+
# end
|
116
|
+
|
117
|
+
# if searched == 0
|
118
|
+
# say 'these keywords have not been indexed yet', :red
|
119
|
+
# else
|
120
|
+
# say ''
|
121
|
+
# say account.name + ' has ' + searched.to_s + ' recorded positions for ' + account.keywords.size.to_s + ' keywords', :green
|
122
|
+
# say ''
|
123
|
+
# print_table table
|
124
|
+
# say ''
|
125
|
+
# end
|
126
|
+
# end
|
127
|
+
# end
|
128
|
+
|
129
|
+
# #desc "import", "imports csv file"
|
130
|
+
# #options :file
|
131
|
+
# #def import(file)
|
132
|
+
|
133
|
+
# #end
|
134
|
+
|
135
|
+
# desc "index", "gets keyword position and saves it for later use"
|
136
|
+
# def index(account)
|
137
|
+
# account = Account.search(account)
|
138
|
+
# if account.blank?
|
139
|
+
# say 'no account found', :red
|
140
|
+
# else
|
141
|
+
# table = [['# Keyword', '# Google', '# GoogleUS']] # header
|
142
|
+
# account.keywords.each do |k|
|
143
|
+
# # Google
|
144
|
+
# google = ::Ranking.new(:keyword => k.keyword, :url => account.domain, :limit =>100).from_googleAU
|
145
|
+
# if !google.blank?
|
146
|
+
# KeywordStatistic.new(:keyword_id => k.id, :engine => :google, :position => google).save
|
147
|
+
# say '.', :green, false
|
148
|
+
# else
|
149
|
+
# say '.', :red, false
|
150
|
+
# end
|
151
|
+
|
152
|
+
# # GoogleUS
|
153
|
+
# googleUS = ::Ranking.new(:keyword => k.keyword, :url => account.domain, :limit =>100).from_googleUS
|
154
|
+
# if !googleUS.blank?
|
155
|
+
# KeywordStatistic.new(:keyword_id => k.id, :engine => :googleUS, :position => googleUS).save
|
156
|
+
# say '.', :green, false
|
157
|
+
# else
|
158
|
+
# say '.', :red, false
|
159
|
+
# end
|
160
|
+
|
161
|
+
# # Bing
|
162
|
+
# # bing = ::Ranking.new(:keyword => k.keyword, :url => account.domain, :limit =>100).from_bingAU
|
163
|
+
# # if !bing.blank?
|
164
|
+
# # KeywordStatistic.new(:keyword_id => k.id, :engine => :bing, :position => bing).save
|
165
|
+
# # say '.', :green, false
|
166
|
+
# # else
|
167
|
+
# # say '.', :red, false
|
168
|
+
# # end
|
169
|
+
|
170
|
+
|
171
|
+
# # Yahoo
|
172
|
+
# # yahoo = ::Ranking.new(:keyword => k.keyword, :url => account.domain, :limit =>100).from_yahooAU
|
173
|
+
# # if !yahoo.blank?
|
174
|
+
# # KeywordStatistic.new(:keyword_id => k.id, :engine => :yahoo, :position => yahoo).save
|
175
|
+
# # say '.', :green, false
|
176
|
+
# # else
|
177
|
+
# # say '.', :red, false
|
178
|
+
# # end
|
179
|
+
|
180
|
+
# table << [k.keyword, google, googleUS]
|
181
|
+
# end
|
182
|
+
|
183
|
+
# say ''
|
184
|
+
# print_table table
|
185
|
+
# say ''
|
186
|
+
# end
|
187
|
+
# end
|
188
|
+
|
189
|
+
# desc "export", "export keywords with positions"
|
190
|
+
# option :file
|
191
|
+
# def export(account)
|
192
|
+
# account = Account.search(account)
|
193
|
+
# if account.blank?
|
194
|
+
# say 'no account found', :red
|
195
|
+
# else
|
196
|
+
# table = [['# Date', '# Keyword', '# Position']] # header
|
197
|
+
|
198
|
+
# options[:file] = 'export.csv' unless options.includes? :file
|
199
|
+
# CSV.open(options[:file], 'w') do |csv|
|
200
|
+
# account.keywords.each do |keyword|
|
201
|
+
# keyword.keyword_statistics.each do |stat|
|
202
|
+
# row = [stat.created_at, keyword.keyword, stat.position]
|
203
|
+
# table << row
|
204
|
+
# csv << row
|
205
|
+
# end
|
206
|
+
# end
|
207
|
+
# end
|
208
|
+
|
209
|
+
# say ''
|
210
|
+
# print_table table
|
211
|
+
# say ''
|
212
|
+
# end
|
213
|
+
# end
|
214
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module SubCommands
|
2
|
+
class Series < Thor
|
3
|
+
desc "ls", "list series"
|
4
|
+
option :order, :type => :string, :default => "updated_at"
|
5
|
+
def ls
|
6
|
+
series = ::Series.all.order(options[:order].to_sym => :desc)
|
7
|
+
|
8
|
+
series_stats = Statistics.new
|
9
|
+
table = [['#', 'log', 'start', 'end', 'hours']] # header
|
10
|
+
series.each do |s|
|
11
|
+
next if s.log_id.blank?
|
12
|
+
|
13
|
+
start = s.start
|
14
|
+
finish = s.end
|
15
|
+
|
16
|
+
# total time
|
17
|
+
series_stats << timer = start.difference(finish || Time.now)
|
18
|
+
|
19
|
+
start = start.display if start
|
20
|
+
finish = finish.display if finish
|
21
|
+
|
22
|
+
table << [s.id,
|
23
|
+
Log.find(s.log_id).name,
|
24
|
+
start, finish || "active",
|
25
|
+
(timer/3600).round(2).to_s] # row
|
26
|
+
end
|
27
|
+
puts ''
|
28
|
+
print_table table
|
29
|
+
puts ''
|
30
|
+
|
31
|
+
say [series.count.to_s, "series out of", ::Series.count].join(' '), :cyan
|
32
|
+
say [(series_stats.mean/3600).round(2), " hours avg"].join(' '), :cyan
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "rm [ID]", "remove series"
|
36
|
+
option :confirm, :type => :boolean, :default => false, :alias => '-y'
|
37
|
+
def rm(id)
|
38
|
+
if ::Series.where(id: id).count == 0
|
39
|
+
say "Series #" + id.to_s + " not found", :red
|
40
|
+
exit
|
41
|
+
end
|
42
|
+
|
43
|
+
series = ::Series.find(id)
|
44
|
+
|
45
|
+
if !options[:confirm]
|
46
|
+
say "You must --confirm before removing this series", :red
|
47
|
+
exit
|
48
|
+
end
|
49
|
+
|
50
|
+
if !series.finished?
|
51
|
+
series.log.deactivate
|
52
|
+
end
|
53
|
+
|
54
|
+
destroyed = series.destroy
|
55
|
+
say "Series #" + id.to_s + " has been destroyed", :green
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module SubCommands
|
2
|
+
class Tags < Thor
|
3
|
+
desc "add", "create new tag"
|
4
|
+
def add(tag)
|
5
|
+
tag = ::Tag.new(tag: tag.strip)
|
6
|
+
|
7
|
+
if !tag.save
|
8
|
+
tag.errors.full_messages.each do |error|
|
9
|
+
say error, :red
|
10
|
+
end
|
11
|
+
exit 1
|
12
|
+
end
|
13
|
+
|
14
|
+
say tag.tag + " added!", :green
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "rm", "remove tag"
|
18
|
+
# option :prune, :type => :boolean, :alias => '-p', :default => false not implemented yet
|
19
|
+
def rm(tag)
|
20
|
+
tag = ::Tag.where(tag: tag)
|
21
|
+
p tag.inspect
|
22
|
+
end
|
23
|
+
|
24
|
+
desc "ls", "list tags"
|
25
|
+
option :order, :type => :string, :default => "created_at"
|
26
|
+
def ls
|
27
|
+
tags = ::Tag.order(options[:order].to_sym => :desc)
|
28
|
+
|
29
|
+
table = [['#', '']] # header
|
30
|
+
tags.each do |tag|
|
31
|
+
table << [tag.id, tag.tag] # row
|
32
|
+
end
|
33
|
+
print_table table
|
34
|
+
end
|
35
|
+
|
36
|
+
# desc "add <name> <domain>", "Adds an account that owns a <domain>"
|
37
|
+
# def add(name, domain)
|
38
|
+
# account = Account.new({
|
39
|
+
# :name => name,
|
40
|
+
# :domain => domain
|
41
|
+
# })
|
42
|
+
|
43
|
+
# if account.save
|
44
|
+
# say name + ' added', :green
|
45
|
+
# else
|
46
|
+
# say 'could not add account!', :red
|
47
|
+
# error account.errors.first[0].to_s + ' ' + account.errors.first[1]
|
48
|
+
# end
|
49
|
+
# end
|
50
|
+
|
51
|
+
# desc "delete <account>", "Deletes <account>"
|
52
|
+
# #option :force, :type => :boolean, :alias => '-f', :default => false
|
53
|
+
# def delete(account)
|
54
|
+
# account = Account.search(account)
|
55
|
+
|
56
|
+
# if account.blank?
|
57
|
+
# say 'no account found', :red
|
58
|
+
# else
|
59
|
+
# say 'WARNING ', :red, false
|
60
|
+
# should_destroy = ask "Are you sure you want to delete " + account.name + "?", :limited_to => ["y", "n"]
|
61
|
+
# account.destroy and say account.name + ' destroyed!', :red if should_destroy == 'y'
|
62
|
+
# say 'no action was taken', :green if should_destroy == 'n'
|
63
|
+
# end
|
64
|
+
# end
|
65
|
+
|
66
|
+
# desc "list", "Lists all accounts"
|
67
|
+
# def list
|
68
|
+
# accounts = Account.all
|
69
|
+
|
70
|
+
# table = [['# Name', '# Domain', '# Keywords']] # header
|
71
|
+
# accounts.each do |a|
|
72
|
+
# table << [a.name, a.domain, a.keywords.size] # row
|
73
|
+
# end
|
74
|
+
# say ''
|
75
|
+
# print_table table
|
76
|
+
# say ''
|
77
|
+
# end
|
78
|
+
end
|
79
|
+
end
|
data/lib/commands/add.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
module Commands
|
2
|
+
module Add
|
3
|
+
def self.included(thor)
|
4
|
+
thor.class_eval do
|
5
|
+
option :tag, :type => :string, :alias => '-t', default: ""
|
6
|
+
option :estimate, :type => :string, :alias => '-e', default: false
|
7
|
+
option :start, :type => :boolean, default: true
|
8
|
+
desc "add [NAME]", "create new log"
|
9
|
+
def add(name)
|
10
|
+
log = Log.new(name: name).tag(options[:tag])
|
11
|
+
|
12
|
+
# estimate option
|
13
|
+
if options[:estimate]
|
14
|
+
estimation = ChronicDuration.parse(options[:estimate]) if !estimation
|
15
|
+
if !estimation
|
16
|
+
say "could not parse estimation time: " + options[:estimate], :red
|
17
|
+
exit
|
18
|
+
end
|
19
|
+
log.estimation = estimation
|
20
|
+
end
|
21
|
+
|
22
|
+
# save log
|
23
|
+
if !log.save
|
24
|
+
log.errors.full_messages.each do |error|
|
25
|
+
say error, :red
|
26
|
+
end
|
27
|
+
exit
|
28
|
+
end
|
29
|
+
|
30
|
+
# start option
|
31
|
+
if options[:start]
|
32
|
+
log.activate if Series.begin(log_id: log.id)
|
33
|
+
say name.to_s + " added and started", :green
|
34
|
+
else
|
35
|
+
say name.to_s + " added", :green
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Commands
|
2
|
+
module List
|
3
|
+
def self.included(thor)
|
4
|
+
thor.class_eval do
|
5
|
+
option :active, :type => :boolean, :default => true
|
6
|
+
#option :tag, :type => :string, :alias => '-t'
|
7
|
+
desc "ls", "list time series"
|
8
|
+
def ls(tag='')
|
9
|
+
logs = Log.where(active: options[:active]).includes(:series).includes(:tags)
|
10
|
+
logs = logs.tagged(tag) if !tag.blank?
|
11
|
+
|
12
|
+
creep_stats = Statistics.new
|
13
|
+
table = [['#', 'name', 'active', 'tags', 'series', 'time', 'estimate', 'creep %']] # header
|
14
|
+
logs.each do |log|
|
15
|
+
|
16
|
+
# tags
|
17
|
+
tags = log.tags.map do |t|
|
18
|
+
t.tag
|
19
|
+
end
|
20
|
+
|
21
|
+
# only show logs with tag, if selected
|
22
|
+
# if !tag.blank?
|
23
|
+
# next unless tags.include? tag
|
24
|
+
# end
|
25
|
+
|
26
|
+
# active text
|
27
|
+
active = "ACTIVE" if log.active == "t"
|
28
|
+
|
29
|
+
# total counter
|
30
|
+
total_time = (log.total/3600).round(2)
|
31
|
+
|
32
|
+
# estimation creep
|
33
|
+
if log.estimation
|
34
|
+
creep = (total_time/log.estimation)*100
|
35
|
+
creep_stats << creep
|
36
|
+
creep = creep.round(3)
|
37
|
+
estimation = (log.estimation/3600).round(3) # log estimation to hours
|
38
|
+
end
|
39
|
+
|
40
|
+
table << [log.id,
|
41
|
+
log.name,
|
42
|
+
active || '',
|
43
|
+
tags,
|
44
|
+
log.series.count || '',
|
45
|
+
total_time || '',
|
46
|
+
estimation || '',
|
47
|
+
creep || '']
|
48
|
+
end
|
49
|
+
|
50
|
+
if logs.count == 0
|
51
|
+
puts ""
|
52
|
+
say "No logs found", :red
|
53
|
+
puts ""
|
54
|
+
exit
|
55
|
+
else
|
56
|
+
puts ""
|
57
|
+
print_table table
|
58
|
+
puts ""
|
59
|
+
say [logs.count.to_s, "logs out of", Log.count.to_s].join(' '), :cyan
|
60
|
+
say [creep_stats.count, "estimations"].join(' '), :cyan
|
61
|
+
say [creep_stats.mean.round(2), "percent mean creep"].join(' '), :cyan
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Commands
|
2
|
+
module Start
|
3
|
+
def self.included(thor)
|
4
|
+
thor.class_eval do
|
5
|
+
desc "start [NAME]", "start new timer"
|
6
|
+
def start(name)
|
7
|
+
|
8
|
+
# not found
|
9
|
+
if Log.where(name: name).count == 0
|
10
|
+
say name.to_s + " not found", :red
|
11
|
+
exit
|
12
|
+
end
|
13
|
+
|
14
|
+
log = Log.find_by(name: name)
|
15
|
+
|
16
|
+
# already active?
|
17
|
+
if log.active == "t"
|
18
|
+
say name.to_s + " already active", :red
|
19
|
+
exit
|
20
|
+
end
|
21
|
+
|
22
|
+
# begin new series, activate log
|
23
|
+
series = Series.begin(log_id: log.id) and log.activate
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Commands
|
2
|
+
module Stop
|
3
|
+
def self.included(thor)
|
4
|
+
thor.class_eval do
|
5
|
+
desc "stop [NAME]", "stop active timer"
|
6
|
+
def stop(name)
|
7
|
+
if Log.where(name: name).count == 0
|
8
|
+
say name.to_s + " not found", :red
|
9
|
+
exit
|
10
|
+
end
|
11
|
+
|
12
|
+
log = Log.find_by(name: name)
|
13
|
+
if log.active == "f"
|
14
|
+
say name.to_s + " not active", :red
|
15
|
+
exit
|
16
|
+
end
|
17
|
+
|
18
|
+
series = log.series.last
|
19
|
+
if series.stop and log.deactivate
|
20
|
+
say name + " stopped!", :green
|
21
|
+
|
22
|
+
# this_series = log.series.last
|
23
|
+
say (series.total/3600).round(3).to_s + " hours out of " + (log.total/3600).round(3).to_s, :cyan
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module StatisticsHelper
|
2
|
+
class Series < Array
|
3
|
+
def sum
|
4
|
+
inject(0.0) { |result, el| result + el }
|
5
|
+
end
|
6
|
+
|
7
|
+
def mean
|
8
|
+
return 0 if size == 0
|
9
|
+
avg = sum / size
|
10
|
+
end
|
11
|
+
|
12
|
+
alias :average :mean
|
13
|
+
alias :avg :mean
|
14
|
+
end
|
15
|
+
|
16
|
+
class Statistics
|
17
|
+
def initialize
|
18
|
+
@statistics = Series.new
|
19
|
+
end
|
20
|
+
|
21
|
+
def add(statistic)
|
22
|
+
@statistics << statistic
|
23
|
+
end
|
24
|
+
|
25
|
+
def count
|
26
|
+
@statistics.count
|
27
|
+
end
|
28
|
+
|
29
|
+
def mean
|
30
|
+
@statistics.mean
|
31
|
+
end
|
32
|
+
|
33
|
+
def <<(statistic)
|
34
|
+
add(statistic)
|
35
|
+
end
|
36
|
+
|
37
|
+
def +(statistics)
|
38
|
+
@statistics + statistics.data
|
39
|
+
end
|
40
|
+
|
41
|
+
def data
|
42
|
+
@statistics
|
43
|
+
end
|
44
|
+
|
45
|
+
alias :average :mean
|
46
|
+
alias :avg :mean
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module TimeDifferenceHelper
|
2
|
+
def difference(relative)
|
3
|
+
if relative > self
|
4
|
+
difference = relative - self
|
5
|
+
else
|
6
|
+
difference = self - relative
|
7
|
+
end
|
8
|
+
|
9
|
+
# hours = difference / 3600
|
10
|
+
# difference -= hours * 3600
|
11
|
+
# minutes = difference / 60
|
12
|
+
# difference -= minutes * 60
|
13
|
+
# seconds = difference
|
14
|
+
# "#{hours.to_s.rjust(2, '0')}:#{minutes.to_s.rjust(2, '0')}:#{seconds.to_s.rjust(2, '0')}"
|
15
|
+
|
16
|
+
# hours = difference / 3600
|
17
|
+
return difference
|
18
|
+
end
|
19
|
+
Time.send :include, self
|
20
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module TimeToWordsHelper
|
2
|
+
def time_to_words_ago(time)
|
3
|
+
a = (Time.now-time).to_i
|
4
|
+
case a
|
5
|
+
when 0 then 'just now'
|
6
|
+
when 1 then 'a second ago'
|
7
|
+
when 2..59 then a.to_s+' seconds ago'
|
8
|
+
when 60..119 then 'a minute ago' # 120 = 2 minutes
|
9
|
+
when 120..3540 then (a/60).to_i.to_s+' minutes ago'
|
10
|
+
when 3541..7100 then 'an hour ago' # 3600 = 1 hour
|
11
|
+
when 7101..82800 then ((a+99)/3600).to_i.to_s+' hours ago'
|
12
|
+
when 82801..172000 then 'a day ago' # 86400 = 1 day
|
13
|
+
when 172001..518400 then ((a+800)/(60*60*24)).to_i.to_s+' days ago'
|
14
|
+
when 518400..1036800 then 'a week ago'
|
15
|
+
else ((a+180000)/(60*60*24*7)).to_i.to_s+' weeks ago'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def time_to_words(seconds)
|
20
|
+
seconds
|
21
|
+
case a
|
22
|
+
when 0..60 then 'seconds'
|
23
|
+
when 60..69 then 'minute'
|
24
|
+
when 70..3600 then 'minutes'
|
25
|
+
when 3600..7199 then 'day'
|
26
|
+
when 7200..107999 then 'days' # 3600 = 1 hour
|
27
|
+
when 108000..215999 then 'month'
|
28
|
+
when 216000..1296000 then 'months'
|
29
|
+
when 1296000..1296000 then 'year'
|
30
|
+
else 'years'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|