gem_velocity 0.0.1
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 +15 -0
- data/.gitignore +22 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +41 -0
- data/Rakefile +9 -0
- data/TODO +17 -0
- data/examples/rails-4.0.0-3.2.14-0.9.1.png +0 -0
- data/examples/rails-4.0.0-3.2.14-2.3.5.png +0 -0
- data/gem_velocity.gemspec +33 -0
- data/lib/gem_velocity.rb +10 -0
- data/lib/gem_velocity/gem_data.rb +51 -0
- data/lib/gem_velocity/gruff_builder.rb +75 -0
- data/lib/gem_velocity/helpers.rb +13 -0
- data/lib/gem_velocity/velocitator.rb +131 -0
- data/lib/gem_velocity/version.rb +3 -0
- data/spec/gem_data_spec.rb +29 -0
- data/spec/gruff_builder_spec.rb +59 -0
- data/spec/helpers_spec.rb +19 -0
- data/spec/no_time_cop_spec.rb +22 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/velocitator_spec.rb +158 -0
- metadata +212 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NDhhODBiMzNlZWIzMjcyODdmMmYwZWI5NjdkM2M2YWYwZmIyZDQ1OA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ZjZkNmI0MzgzNDU4ZDkxMzBlZWQ2YzMyZTIyYmY5ZWM3Zjg5ZWUwYg==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MTFkY2Q5YmU2YTk1OTliMDAyMTU5MTdjY2I4MmE4YzU1OWE2NmNiY2QyNDYz
|
10
|
+
MWFlZDU5ODg3NzI4MTAyMTI1ZDMyMzc4ZDIxNTllODM5ODE1MjNmYmQ5MzUy
|
11
|
+
Y2EyODMyMzk3YTRkZDkyN2VlZjRmYmYyMjY3MWM1NTFjZTQyZmU=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZTE2M2I5Mzk3NGUzMGI5ZWY3YWE1ODJmY2ExY2I4NjVkOGZkMmE2NzQ3Nzk5
|
14
|
+
NWNkMTllMzJjMzBkZGE1NzQ1ZmI3MzdmYjczNjQ3YTJkZjk4ZDE4MmQ5NWVh
|
15
|
+
M2ZkYjUzZTczNDNjMTUwM2FhNmVlZGMyMGM2Njk5MDJjMzE2YWE=
|
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
spec/tmp
|
19
|
+
public/
|
20
|
+
images/
|
21
|
+
spec/fixtures/vcr_cassettes
|
22
|
+
spec/fixtures/vcr_cassettes/
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Shai Rosenfeld
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# GemVelocity
|
2
|
+
|
3
|
+
A way to see gem velocity. Right now it's just aggregated totals.
|
4
|
+
|
5
|
+
So, not a number of downloads each day, but rather just the general timeline of total downloads.
|
6
|
+
|
7
|
+
# Example
|
8
|
+
|
9
|
+
This spec below:
|
10
|
+
|
11
|
+
<pre>
|
12
|
+
it "has a shortcut graph method #1" do
|
13
|
+
VCR.use_cassette('velocitator-rails-multiple-graph-shortcut-3') do
|
14
|
+
velocitator = Velocitator.new("rails", ["4.0.0","3.2.14","2.3.5"])
|
15
|
+
file = velocitator.graph("/tmp")
|
16
|
+
File.exist?(file).should be_true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
</pre>
|
20
|
+
|
21
|
+
Produces:
|
22
|
+
|
23
|
+

|
24
|
+
|
25
|
+
This spec below (notice the date range):
|
26
|
+
|
27
|
+
<pre>
|
28
|
+
it "has a shortcut graph method #2" do
|
29
|
+
VCR.use_cassette('velocitator-rails-multiple-graph-shortcut-4') do
|
30
|
+
velocitator = Velocitator.new("rails", ["4.0.0","3.2.14","0.9.1"])
|
31
|
+
file = velocitator.graph("/tmp", [3.months.ago, Time.now])
|
32
|
+
File.exist?(file).should be_true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
</pre>
|
36
|
+
|
37
|
+
Produces:
|
38
|
+
|
39
|
+

|
40
|
+
|
41
|
+
Also, you should be able to pass in max,min values to size the graph. See `spec/` for more info.
|
data/Rakefile
ADDED
data/TODO
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
move VCR to an :around spec
|
2
|
+
wtf? does a time period actually work?
|
3
|
+
|
4
|
+
## Collection
|
5
|
+
|
6
|
+
Have a grapher class that takes a collection on singular and builds the corresponding gruff? Graph.buid(coolextion) vs collection.graph
|
7
|
+
|
8
|
+
All of them have same date range max min, same line_data size
|
9
|
+
|
10
|
+
Make sure to pad 0's
|
11
|
+
|
12
|
+
Earliest date, latest date
|
13
|
+
|
14
|
+
Most max of all
|
15
|
+
|
16
|
+
Have a date-calc abstraction that does all the padding calculation aggregation?
|
17
|
+
|
Binary file
|
Binary file
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'gem_velocity/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "gem_velocity"
|
8
|
+
spec.version = GemVelocity::VERSION
|
9
|
+
spec.authors = ["Shai Rosenfeld"]
|
10
|
+
spec.email = ["srosenfeld@engineyard.com"]
|
11
|
+
spec.description = %q{generate gem velocity images}
|
12
|
+
spec.summary = %q{generate gem velocity images}
|
13
|
+
spec.homepage = "https://github.com/shaiguitar/gem_velocities"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "gruff"
|
22
|
+
spec.add_dependency "activesupport"
|
23
|
+
spec.add_dependency "gems"
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
26
|
+
spec.add_development_dependency "rake"
|
27
|
+
spec.add_development_dependency "rspec"
|
28
|
+
spec.add_development_dependency "pry"
|
29
|
+
spec.add_development_dependency "vcr"
|
30
|
+
spec.add_development_dependency "webmock", "= 1.13" # vcr requirement?
|
31
|
+
spec.add_development_dependency "timecop"
|
32
|
+
|
33
|
+
end
|
data/lib/gem_velocity.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'gems'
|
2
|
+
|
3
|
+
class GemData
|
4
|
+
def initialize(name)
|
5
|
+
@name = name
|
6
|
+
end
|
7
|
+
|
8
|
+
def versions
|
9
|
+
versions_metadata.map{|v| v["number"]}
|
10
|
+
end
|
11
|
+
|
12
|
+
def versions_built_at
|
13
|
+
h = {}
|
14
|
+
versions_metadata.map{|v| h.merge!(v["number"] => v["built_at"] )}
|
15
|
+
h
|
16
|
+
end
|
17
|
+
|
18
|
+
def downloads_day(version)
|
19
|
+
# todo rename method? aggregated downloads per day
|
20
|
+
total_so_far = 0
|
21
|
+
# start day 0 as first download day.
|
22
|
+
found_first_download = false
|
23
|
+
ret = downloads_metadata(version).map do |day,downloads_that_day|
|
24
|
+
if found_first_download
|
25
|
+
total_so_far += downloads_that_day
|
26
|
+
[day, total_so_far]
|
27
|
+
else
|
28
|
+
if !downloads_that_day.zero?
|
29
|
+
found_first_download = true
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end.compact
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def versions_metadata
|
39
|
+
# cache api call.
|
40
|
+
@versions_metadata ||= Gems.versions(@name)
|
41
|
+
end
|
42
|
+
|
43
|
+
def downloads_metadata(version)
|
44
|
+
# cache api call.
|
45
|
+
@downloads_metadata ||= {}
|
46
|
+
return @downloads_metadata[version] if @downloads_metadata[version]
|
47
|
+
@downloads_metadata[version] ||= Gems.downloads(@name, version).to_a
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
begin
|
3
|
+
require 'gruff'
|
4
|
+
rescue LoadError
|
5
|
+
puts "You may need to install imagemagick, if rmagick isn't around..."
|
6
|
+
end
|
7
|
+
|
8
|
+
class GruffBuilder
|
9
|
+
|
10
|
+
class NoData < StandardError; end
|
11
|
+
|
12
|
+
MIN_VALUE = 0
|
13
|
+
MAX_VALUE = 300
|
14
|
+
|
15
|
+
attr_accessor :root, :relative_path, :versions, :gem_name
|
16
|
+
attr_accessor :title, :labels, :line_datas, :min_value, :max_value
|
17
|
+
|
18
|
+
def initialize(root, relative_path, versions, gem_name, gruff_options = {})
|
19
|
+
@root = root || raise("you must set a root. default is root/public/images")
|
20
|
+
@relative_path = relative_path || "public/images/"
|
21
|
+
@versions = versions.is_a?(Array) ? versions : raise("versions must be an array")
|
22
|
+
@gem_name = gem_name
|
23
|
+
@title = gruff_options[:title] || ""
|
24
|
+
@labels = gruff_options[:labels] || {}
|
25
|
+
@line_datas = gruff_options[:line_datas]
|
26
|
+
@min_value = gruff_options[:min_value] || MIN_VALUE
|
27
|
+
@max_value = gruff_options[:max_value] || MAX_VALUE
|
28
|
+
end
|
29
|
+
|
30
|
+
def relative_filename
|
31
|
+
"#{@relative_path}#{filename}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def filename
|
35
|
+
"#{graph_name(versions.join("-"))}.png"
|
36
|
+
end
|
37
|
+
|
38
|
+
def absolute_filename
|
39
|
+
"#{absolute_destination}/#{filename}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def write
|
43
|
+
raise NoData if @line_datas.nil? || @line_datas.empty?
|
44
|
+
ensure_destination
|
45
|
+
gruff.title = @title
|
46
|
+
gruff.labels = @labels
|
47
|
+
@line_datas.each_with_index do |line_data,index|
|
48
|
+
gruff.data graph_name(@versions[index]), line_data
|
49
|
+
end
|
50
|
+
gruff.minimum_value = @min_value
|
51
|
+
gruff.maximum_value = @max_value
|
52
|
+
gruff.write(absolute_filename)
|
53
|
+
absolute_filename
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def absolute_destination
|
59
|
+
File.expand_path(File.join(@root, @relative_path))
|
60
|
+
end
|
61
|
+
|
62
|
+
def ensure_destination
|
63
|
+
FileUtils.mkdir_p(File.expand_path(absolute_destination))
|
64
|
+
end
|
65
|
+
|
66
|
+
def graph_name(append_text = nil)
|
67
|
+
append_text = append_text.nil? ? "" : "-#{append_text}"
|
68
|
+
"#{gem_name}"+ append_text
|
69
|
+
end
|
70
|
+
|
71
|
+
def gruff
|
72
|
+
@gruff ||= Gruff::Line.new
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
class Velocitator
|
2
|
+
|
3
|
+
include ::Helpers
|
4
|
+
|
5
|
+
attr_accessor :gem_name, :versions
|
6
|
+
|
7
|
+
# modifiers on the end result image being rendered.
|
8
|
+
attr_accessor :date_range, :max_value, :min_value, :root
|
9
|
+
|
10
|
+
def initialize(gem_name, versions)
|
11
|
+
@gem_name = gem_name || raise(ArgumentError, 'need a name')
|
12
|
+
@versions = if versions.is_a?(String)
|
13
|
+
[versions]
|
14
|
+
else
|
15
|
+
versions
|
16
|
+
end || raise(ArgumentError, 'required versions')
|
17
|
+
end
|
18
|
+
|
19
|
+
def date_range=(args)
|
20
|
+
return nil if args.nil?
|
21
|
+
unless args.is_a?(Array) && args.size == 2
|
22
|
+
raise(ArgumentError, "must pass a range with time objects like [start,end]")
|
23
|
+
end
|
24
|
+
@date_range = args.map{|t| time_format_str(t) }
|
25
|
+
end
|
26
|
+
|
27
|
+
def line_datas
|
28
|
+
versions.map do |v|
|
29
|
+
specific_days_in_range.map do |day_in_range|
|
30
|
+
day_in_range = time_format_str_small(day_in_range) #conform to rubygems api format
|
31
|
+
if gem_data.downloads_day(v).map {|day,total| day}.include?(day_in_range)
|
32
|
+
total = Hash[gem_data.downloads_day(v)][day_in_range]
|
33
|
+
else
|
34
|
+
0
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def effective_date_range
|
41
|
+
# we allow overwriting by passing a date range.
|
42
|
+
if @date_range.is_a?(Array) && @date_range.compact.size==2
|
43
|
+
@date_range
|
44
|
+
else
|
45
|
+
default_date_range
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# call, after you set all the attributes you want.
|
50
|
+
# you can set (or there will be fallback defaults)
|
51
|
+
#
|
52
|
+
# max, min
|
53
|
+
# date_range (leave nil for default values in either start or end)
|
54
|
+
def gruff_builder
|
55
|
+
opts = {
|
56
|
+
:title => "#{gem_name}-#{versions.join("-")}",
|
57
|
+
# just the first and last dates. give a small offset so it fits into the pciture.
|
58
|
+
# line_datas.first.size -2 should be the max of any one of the line-datas, all should be same size.
|
59
|
+
:labels => ({1 => time_format_str_small(effective_start_time), (line_datas.first.size-2) => time_format_str_small(effective_end_time) }),
|
60
|
+
:max_value => max_value || default_max_value,
|
61
|
+
:min_value => min_value || default_min_value,
|
62
|
+
:line_datas => line_datas
|
63
|
+
}
|
64
|
+
builder = GruffBuilder.new(@root || Dir.pwd,nil,versions,gem_name,opts)
|
65
|
+
builder
|
66
|
+
end
|
67
|
+
|
68
|
+
def graph(root_arg = nil, range = nil, min = nil, max = nil)
|
69
|
+
# if nil, defaults will be used
|
70
|
+
self.date_range = range
|
71
|
+
self.root = root_arg
|
72
|
+
self.max_value = max
|
73
|
+
self.min_value = min
|
74
|
+
gruff_builder.write
|
75
|
+
end
|
76
|
+
|
77
|
+
def specific_days_in_range
|
78
|
+
all_days = []
|
79
|
+
s = Date.parse(effective_start_time)
|
80
|
+
e = Date.parse(effective_end_time)
|
81
|
+
i = s
|
82
|
+
while (i <= e )
|
83
|
+
all_days << i
|
84
|
+
i += 1.day
|
85
|
+
end
|
86
|
+
all_days
|
87
|
+
end
|
88
|
+
|
89
|
+
def default_min_value
|
90
|
+
0
|
91
|
+
end
|
92
|
+
|
93
|
+
def default_max_value
|
94
|
+
totals = []
|
95
|
+
versions.each {|v|
|
96
|
+
totals << gem_data.downloads_day(v).map {|day,total| total}
|
97
|
+
}
|
98
|
+
totals.flatten.compact.max
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def effective_start_time
|
104
|
+
effective_date_range.first
|
105
|
+
end
|
106
|
+
|
107
|
+
def effective_end_time
|
108
|
+
effective_date_range.last
|
109
|
+
end
|
110
|
+
|
111
|
+
def default_date_range
|
112
|
+
range = default_start, default_end
|
113
|
+
end
|
114
|
+
|
115
|
+
def default_start
|
116
|
+
earliest_start = versions.map{|v| Date.parse(time_built(v)) }.min
|
117
|
+
default_start = time_format_str(earliest_start)
|
118
|
+
end
|
119
|
+
|
120
|
+
def default_end
|
121
|
+
default_end = time_format_str(Time.now)
|
122
|
+
end
|
123
|
+
|
124
|
+
def time_built(version)
|
125
|
+
gem_data.versions_built_at[version]
|
126
|
+
end
|
127
|
+
|
128
|
+
def gem_data
|
129
|
+
@gem_data ||= GemData.new(@gem_name)
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GemData do
|
4
|
+
before do
|
5
|
+
Timecop.travel(Time.local(2013, 10, 7, 0, 0, 0))
|
6
|
+
Timecop.freeze
|
7
|
+
end
|
8
|
+
|
9
|
+
it "collects version info for a given gem" do
|
10
|
+
VCR.use_cassette('gem-data-haml-i18n-extractor-0.0.17-versions') do
|
11
|
+
GemData.new("haml-i18n-extractor").versions.should include "0.0.17"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it "maps built_at and versions for access" do
|
16
|
+
VCR.use_cassette('gem-data-haml-i18n-extractor-0.0.17-versions-built-at') do
|
17
|
+
GemData.new("haml-i18n-extractor").versions_built_at["0.0.17"].should == "2013-06-16T00:00:00Z"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it "can show download information" do
|
22
|
+
VCR.use_cassette('gem-data-haml-i18n-extractor-0.0.17-downloads-day') do
|
23
|
+
GemData.new("haml-i18n-extractor").downloads_day("0.0.17").should == [["2013-07-11", 3], ["2013-07-12", 5], ["2013-07-13", 6], ["2013-07-14", 6], ["2013-07-15", 8], ["2013-07-16", 10], ["2013-07-17", 16], ["2013-07-18", 16], ["2013-07-19", 19], ["2013-07-20", 20], ["2013-07-21", 20], ["2013-07-22", 22], ["2013-07-23", 23], ["2013-07-24", 29], ["2013-07-25", 29], ["2013-07-26", 29], ["2013-07-27", 29], ["2013-07-28", 29], ["2013-07-29", 30], ["2013-07-30", 32], ["2013-07-31", 34], ["2013-08-01", 34], ["2013-08-02", 34], ["2013-08-03", 34], ["2013-08-04", 34], ["2013-08-05", 36], ["2013-08-06", 36], ["2013-08-07", 36], ["2013-08-08", 39], ["2013-08-09", 39], ["2013-08-10", 39], ["2013-08-11", 39], ["2013-08-12", 40], ["2013-08-13", 42], ["2013-08-14", 43], ["2013-08-15", 45], ["2013-08-16", 45], ["2013-08-17", 46], ["2013-08-18", 46], ["2013-08-19", 46], ["2013-08-20", 46], ["2013-08-21", 47], ["2013-08-22", 49], ["2013-08-23", 53], ["2013-08-24", 53], ["2013-08-25", 54], ["2013-08-26", 54], ["2013-08-27", 56], ["2013-08-28", 56], ["2013-08-29", 58], ["2013-08-30", 58], ["2013-08-31", 58], ["2013-09-01", 60], ["2013-09-02", 62], ["2013-09-03", 63], ["2013-09-04", 63], ["2013-09-05", 65], ["2013-09-06", 67], ["2013-09-07", 67], ["2013-09-08", 67], ["2013-09-09", 68], ["2013-09-10", 68], ["2013-09-11", 68], ["2013-09-12", 73], ["2013-09-13", 73], ["2013-09-14", 73], ["2013-09-15", 73], ["2013-09-16", 74], ["2013-09-17", 74], ["2013-09-18", 74], ["2013-09-19", 75], ["2013-09-20", 76], ["2013-09-21", 76], ["2013-09-22", 76], ["2013-09-23", 76], ["2013-09-24", 79], ["2013-09-25", 83], ["2013-09-26", 90], ["2013-09-27", 90], ["2013-09-28", 90], ["2013-09-29", 92], ["2013-09-30", 92], ["2013-10-01", 92], ["2013-10-02", 92], ["2013-10-03", 92], ["2013-10-04", 94], ["2013-10-05", 94], ["2013-10-06", 94], ["2013-10-07", 95]]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
end
|
29
|
+
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GruffBuilder do
|
4
|
+
before do
|
5
|
+
@tmp_dir = SpecHelper.tmpdir
|
6
|
+
end
|
7
|
+
|
8
|
+
it "raises if no root or if versions isnt an array" do
|
9
|
+
lambda { builder = GruffBuilder.new(nil,nil,nil,nil, {}) }.should raise_error
|
10
|
+
end
|
11
|
+
|
12
|
+
it "has defaults" do
|
13
|
+
builder = GruffBuilder.new(@tmp_dir,nil,[],nil, {})
|
14
|
+
builder.root = @tmp_dir
|
15
|
+
builder.relative_path = "images/"
|
16
|
+
builder.versions = []
|
17
|
+
builder.gem_name = nil
|
18
|
+
|
19
|
+
builder.title = ""
|
20
|
+
builder.labels = {}
|
21
|
+
builder.line_datas = nil
|
22
|
+
builder.min_value = 0
|
23
|
+
builder.max_value = 300
|
24
|
+
end
|
25
|
+
|
26
|
+
it "has a filename" do
|
27
|
+
builder = GruffBuilder.new(@tmp_dir,nil,["0.0.17"],"foo-baz", {})
|
28
|
+
builder.relative_filename.should eq "public/images/foo-baz-0.0.17.png"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "can not write a file if there is no line data" do
|
32
|
+
builder = GruffBuilder.new(@tmp_dir,nil,["0.0.17"],"foo-baz", {})
|
33
|
+
lambda { builder.write }.should raise_error GruffBuilder::NoData
|
34
|
+
end
|
35
|
+
|
36
|
+
it "can write out a file" do
|
37
|
+
builder = GruffBuilder.new(@tmp_dir,nil,["0.0.17"],"foo-baz", {})
|
38
|
+
builder.line_datas = [1,2,3]
|
39
|
+
builder.write
|
40
|
+
file = builder.absolute_filename
|
41
|
+
File.exists?(file).should be_true
|
42
|
+
end
|
43
|
+
|
44
|
+
it "can write out a file with gruff data" do
|
45
|
+
gruff_options = {
|
46
|
+
:title => "A pickture",
|
47
|
+
:labels => {1 => "label", 3 => "label2"},
|
48
|
+
:line_datas => [1,2,3,10,8,12],
|
49
|
+
:min_value => 0,
|
50
|
+
:max_value => 20,
|
51
|
+
}
|
52
|
+
builder = GruffBuilder.new(@tmp_dir,nil,["0.0.17"],"foo-baz", gruff_options)
|
53
|
+
builder.write
|
54
|
+
file = builder.absolute_filename
|
55
|
+
File.exists?(file).should be_true
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class Whatever
|
4
|
+
extend Helpers
|
5
|
+
end
|
6
|
+
|
7
|
+
describe Helpers do
|
8
|
+
|
9
|
+
it "can format date" do
|
10
|
+
date = Date.parse("2013-09-15")
|
11
|
+
Whatever.time_format_str(date).should eq "2013-09-15T00:00:00Z"
|
12
|
+
end
|
13
|
+
|
14
|
+
it "can format str" do
|
15
|
+
date = "2013-09-15"
|
16
|
+
Whatever.time_format_str(date).should eq "2013-09-15T00:00:00Z"
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'with no time stubbing' do
|
4
|
+
|
5
|
+
it "has a shortcut graph method #1" do
|
6
|
+
VCR.use_cassette('velocitator-rails-multiple-graph-shortcut-3') do
|
7
|
+
velocitator = Velocitator.new("rails", ["4.0.0","3.2.14","2.3.5"])
|
8
|
+
file = velocitator.graph("/tmp")
|
9
|
+
File.exist?(file).should be_true
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it "has a shortcut graph method #2" do
|
14
|
+
VCR.use_cassette('velocitator-rails-multiple-graph-shortcut-4') do
|
15
|
+
velocitator = Velocitator.new("rails", ["4.0.0","3.2.14","0.9.1"])
|
16
|
+
file = velocitator.graph("/tmp", [3.months.ago, Time.now])
|
17
|
+
File.exist?(file).should be_true
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'gem_velocity'
|
2
|
+
require 'pry'
|
3
|
+
require 'vcr'
|
4
|
+
require 'active_support/all' # time
|
5
|
+
require 'timecop'
|
6
|
+
|
7
|
+
VCR.configure do |c|
|
8
|
+
c.cassette_library_dir = 'spec/fixtures/vcr_cassettes'
|
9
|
+
c.hook_into :webmock # or :fakeweb
|
10
|
+
end
|
11
|
+
|
12
|
+
module SpecHelper
|
13
|
+
def self.tmpdir
|
14
|
+
File.expand_path File.join(File.dirname(__FILE__), "tmp")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
RSpec.configure do |c|
|
19
|
+
c.after(:suite) do
|
20
|
+
FileUtils.rm_rf(SpecHelper.tmpdir)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
@@ -0,0 +1,158 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Velocitator do
|
4
|
+
|
5
|
+
before do
|
6
|
+
# for Time.now
|
7
|
+
# Also, the 10 mins flattens out to 00: but we don't care at this point as it's day by day.
|
8
|
+
Timecop.travel(Time.local(2013, 9, 20, 10, 0, 0))
|
9
|
+
Timecop.freeze
|
10
|
+
end
|
11
|
+
|
12
|
+
after do
|
13
|
+
Timecop.return
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'raises if you dont pass name and version(s)' do
|
17
|
+
lambda { Velocitator.new(nil,nil) }.should raise_error ArgumentError
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "a specific version" do
|
21
|
+
it "sets a specific date range according to the gem's info" do
|
22
|
+
VCR.use_cassette('velocitator-haml-i18n-extractor-0.0.17-versions-info') do
|
23
|
+
velocitator = Velocitator.new("haml-i18n-extractor", "0.0.17")
|
24
|
+
velocitator.effective_date_range.should eq ["2013-06-16T00:00:00Z", "2013-09-20T00:00:00Z"]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it "can override the default time ranges if its in the range" do
|
29
|
+
VCR.use_cassette('velocitator-haml-i18n-extractor-0.0.17-versions-override') do
|
30
|
+
velocitator = Velocitator.new("haml-i18n-extractor", "0.0.17")
|
31
|
+
velocitator.date_range = [1.day.ago, Time.now]
|
32
|
+
velocitator.effective_date_range.should eq ["2013-09-19T00:00:00Z", "2013-09-20T00:00:00Z"]
|
33
|
+
velocitator.line_datas.size.should eq (velocitator.versions.size)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
it "can set a max and min" do
|
38
|
+
VCR.use_cassette('velocitator-haml-i18n-extractor-0.0.17-versions') do
|
39
|
+
velocitator = Velocitator.new("haml-i18n-extractor", "0.0.17")
|
40
|
+
lambda {
|
41
|
+
velocitator.max_value = 500
|
42
|
+
velocitator.min_value = 10
|
43
|
+
}.should_not raise_error
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it "can render a graph" do
|
48
|
+
VCR.use_cassette('velocitator-haml-i18n-extractor-0.0.17-versions-graph') do
|
49
|
+
velocitator = Velocitator.new("haml-i18n-extractor", "0.0.17")
|
50
|
+
velocitator.date_range = [1.day.ago, Time.now]
|
51
|
+
velocitator.root = SpecHelper.tmpdir
|
52
|
+
builder = velocitator.gruff_builder
|
53
|
+
|
54
|
+
# fixture / webmock / data etc.. if it fails, rm -rf spec/fixtures/vcr_cassettes
|
55
|
+
builder.line_datas.should == [[75,76]]
|
56
|
+
builder.title.should == "haml-i18n-extractor-0.0.17"
|
57
|
+
builder.labels.should == ({1=>"2013-09-19", (builder.line_datas.first.size-2) =>"2013-09-20"})
|
58
|
+
builder.max_value.should == 95
|
59
|
+
builder.min_value.should == 0
|
60
|
+
|
61
|
+
file = builder.write
|
62
|
+
File.exist?(file).should be_true
|
63
|
+
#`open #{file} -a preview.app`
|
64
|
+
#Kernel.sleep(10)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
it "has a shortcut graph method #1" do
|
69
|
+
VCR.use_cassette('velocitator-haml-i18n-extractor-0.0.17-graph-shortcut-1') do
|
70
|
+
velocitator = Velocitator.new("haml-i18n-extractor", "0.0.17")
|
71
|
+
file = velocitator.graph(SpecHelper.tmpdir,[1.day.ago, Time.now])
|
72
|
+
File.exist?(file).should be_true
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
it "has a shortcut graph method #2" do
|
77
|
+
VCR.use_cassette('velocitator-haml-i18n-extractor-0.0.17-graph-shortcut-2') do
|
78
|
+
velocitator = Velocitator.new("haml-i18n-extractor", "0.0.17")
|
79
|
+
file = velocitator.graph
|
80
|
+
File.exist?(file).should be_true
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
it "has a shortcut graph metho #3" do
|
85
|
+
VCR.use_cassette('velocitator-haml-i18n-extractor-0.0.17-graph-shortcut-3') do
|
86
|
+
velocitator = Velocitator.new("haml-i18n-extractor", "0.0.17")
|
87
|
+
file = velocitator.graph(nil,nil,0,1000)
|
88
|
+
File.exist?(file).should be_true
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "Multiple versions" do
|
95
|
+
before do
|
96
|
+
@some_versions = ["0.0.17", "0.0.5","0.0.10"]
|
97
|
+
Timecop.travel(Time.local(2013, 9, 20, 10, 0, 0))
|
98
|
+
Timecop.freeze
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
after do
|
103
|
+
Timecop.return
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
it "can initialize multiple versions" do
|
108
|
+
VCR.use_cassette('velocitator-haml-i18n-extractor-multiple-versions') do
|
109
|
+
velocitator = Velocitator.new("haml-i18n-extractor", @some_versions)
|
110
|
+
velocitator.versions.should == @some_versions
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
it "sets the earliest start range from to all of the versions info" do
|
115
|
+
VCR.use_cassette('velocitator-haml-i18n-extractor-0.0.17-multiple-versions-info') do
|
116
|
+
# some_versions.map{|v| GemData.new("haml-i18n-extractor").versions_built_at[v]}
|
117
|
+
# => ["2013-06-16T00:00:00Z", "2013-03-22T00:00:00Z", "2013-05-06T00:00:00Z"]
|
118
|
+
velocitator = Velocitator.new("haml-i18n-extractor", @some_versions)
|
119
|
+
velocitator.effective_date_range.should eq ["2013-03-22T00:00:00Z", "2013-09-20T00:00:00Z"]
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
it "sets the max value to the max of all of versions" do
|
124
|
+
VCR.use_cassette('velocitator-haml-i18n-extractor-0.0.17-multiple-versions-max-value') do
|
125
|
+
velocitator = Velocitator.new("haml-i18n-extractor", @some_versions)
|
126
|
+
velocitator.default_max_value.should eq 95
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
it "sets the max value to the max of all of versions" do
|
131
|
+
VCR.use_cassette('velocitator-haml-i18n-extractor-0.0.17-multiple-versions-max-value') do
|
132
|
+
velocitator = Velocitator.new("haml-i18n-extractor", @some_versions)
|
133
|
+
velocitator.default_max_value.should eq 95
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should set the line data to an array of versions.size with equal length which should be the max value of any one of them" do
|
138
|
+
VCR.use_cassette('velocitator-haml-i18n-extractor-0.0.17-multiple-versions-line-data') do
|
139
|
+
velocitator = Velocitator.new("haml-i18n-extractor", @some_versions)
|
140
|
+
velocitator.line_datas.size.should == @some_versions.size
|
141
|
+
# all of them should be the same size, padded with 0's if there is no download info
|
142
|
+
velocitator.line_datas.map{|d| d.size }.uniq.size.should == 1
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
it "has a shortcut graph method" do
|
147
|
+
VCR.use_cassette('velocitator-haml-i18n-extractor-multiple-graph-shortcut') do
|
148
|
+
velocitator = Velocitator.new("haml-i18n-extractor", @some_versions)
|
149
|
+
file = velocitator.graph
|
150
|
+
puts file.inspect
|
151
|
+
File.exist?(file).should be_true
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
end
|
158
|
+
|
metadata
ADDED
@@ -0,0 +1,212 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gem_velocity
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Shai Rosenfeld
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-10-07 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: gruff
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ! '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ! '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activesupport
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: gems
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.3'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.3'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ! '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ! '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ! '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ! '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: pry
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ! '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ! '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: vcr
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ! '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: webmock
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - '='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '1.13'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - '='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '1.13'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: timecop
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ! '>='
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ! '>='
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
description: generate gem velocity images
|
154
|
+
email:
|
155
|
+
- srosenfeld@engineyard.com
|
156
|
+
executables: []
|
157
|
+
extensions: []
|
158
|
+
extra_rdoc_files: []
|
159
|
+
files:
|
160
|
+
- .gitignore
|
161
|
+
- Gemfile
|
162
|
+
- LICENSE.txt
|
163
|
+
- README.md
|
164
|
+
- Rakefile
|
165
|
+
- TODO
|
166
|
+
- examples/rails-4.0.0-3.2.14-0.9.1.png
|
167
|
+
- examples/rails-4.0.0-3.2.14-2.3.5.png
|
168
|
+
- gem_velocity.gemspec
|
169
|
+
- lib/gem_velocity.rb
|
170
|
+
- lib/gem_velocity/gem_data.rb
|
171
|
+
- lib/gem_velocity/gruff_builder.rb
|
172
|
+
- lib/gem_velocity/helpers.rb
|
173
|
+
- lib/gem_velocity/velocitator.rb
|
174
|
+
- lib/gem_velocity/version.rb
|
175
|
+
- spec/gem_data_spec.rb
|
176
|
+
- spec/gruff_builder_spec.rb
|
177
|
+
- spec/helpers_spec.rb
|
178
|
+
- spec/no_time_cop_spec.rb
|
179
|
+
- spec/spec_helper.rb
|
180
|
+
- spec/velocitator_spec.rb
|
181
|
+
homepage: https://github.com/shaiguitar/gem_velocities
|
182
|
+
licenses:
|
183
|
+
- MIT
|
184
|
+
metadata: {}
|
185
|
+
post_install_message:
|
186
|
+
rdoc_options: []
|
187
|
+
require_paths:
|
188
|
+
- lib
|
189
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
190
|
+
requirements:
|
191
|
+
- - ! '>='
|
192
|
+
- !ruby/object:Gem::Version
|
193
|
+
version: '0'
|
194
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
195
|
+
requirements:
|
196
|
+
- - ! '>='
|
197
|
+
- !ruby/object:Gem::Version
|
198
|
+
version: '0'
|
199
|
+
requirements: []
|
200
|
+
rubyforge_project:
|
201
|
+
rubygems_version: 2.0.3
|
202
|
+
signing_key:
|
203
|
+
specification_version: 4
|
204
|
+
summary: generate gem velocity images
|
205
|
+
test_files:
|
206
|
+
- spec/gem_data_spec.rb
|
207
|
+
- spec/gruff_builder_spec.rb
|
208
|
+
- spec/helpers_spec.rb
|
209
|
+
- spec/no_time_cop_spec.rb
|
210
|
+
- spec/spec_helper.rb
|
211
|
+
- spec/velocitator_spec.rb
|
212
|
+
has_rdoc:
|