merry_go_round 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/.travis.yml +4 -0
- data/Contributing.markdown +19 -0
- data/Gemfile +19 -0
- data/LICENSE +22 -0
- data/Rakefile +20 -0
- data/Readme.markdown +53 -0
- data/bin/merry +7 -0
- data/lib/merry_go_round/aggregation.rb +16 -0
- data/lib/merry_go_round/aggregator.rb +69 -0
- data/lib/merry_go_round/cli.rb +17 -0
- data/lib/merry_go_round/entry.rb +26 -0
- data/lib/merry_go_round/railtie.rb +4 -0
- data/lib/merry_go_round/version.rb +3 -0
- data/lib/merry_go_round.rb +53 -0
- data/lib/rails/generators/merry_go_round/install/USAGE +3 -0
- data/lib/rails/generators/merry_go_round/install/install_generator.rb +23 -0
- data/lib/rails/generators/merry_go_round/install/templates/add_aggregations.rb +23 -0
- data/merry_go_round.gemspec +26 -0
- data/test/merry_go_round_test.rb +13 -0
- data/test/test_helper.rb +17 -0
- metadata +138 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
## Submitting a Pull Request
|
2
|
+
|
3
|
+
1. [Fork the repository.][fork]
|
4
|
+
2. [Create a topic branch.][branch]
|
5
|
+
3. Add tests for your unimplemented feature or bug fix.
|
6
|
+
4. Run `bundle exec rake`. If your tests pass, return to step 3.
|
7
|
+
5. Implement your feature or bug fix.
|
8
|
+
6. Run `bundle exec rake`. If your tests fail, return to step 5.
|
9
|
+
7. Run `open coverage/index.html`. If your changes are not completely covered
|
10
|
+
by your tests, return to step 3.
|
11
|
+
8. Add documentation for your feature or bug fix.
|
12
|
+
9. Run `bundle exec rake doc`. If your changes are not 100% documented, go
|
13
|
+
back to step 8.
|
14
|
+
10. Add, commit, and push your changes.
|
15
|
+
11. [Submit a pull request.][pr]
|
16
|
+
|
17
|
+
[fork]: http://help.github.com/fork-a-repo/
|
18
|
+
[branch]: http://learn.github.com/p/branching.html
|
19
|
+
[pr]: http://help.github.com/send-pull-requests/
|
data/Gemfile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Gem dependencies
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
gem 'rake', group: [:development, :test]
|
7
|
+
|
8
|
+
# Development dependencies
|
9
|
+
group :development do
|
10
|
+
gem 'yard'
|
11
|
+
gem 'redcarpet'
|
12
|
+
end
|
13
|
+
|
14
|
+
# Testing dependencies
|
15
|
+
group :test do
|
16
|
+
gem 'minitest'
|
17
|
+
gem 'minitest-wscolor'
|
18
|
+
gem 'simplecov', require: false
|
19
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Seesaw Decisions Corporation
|
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/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
|
3
|
+
require 'rake/testtask'
|
4
|
+
Rake::TestTask.new(:test) do |t|
|
5
|
+
t.libs << 'test'
|
6
|
+
t.pattern = 'test/**/*_test.rb'
|
7
|
+
end
|
8
|
+
task default: :test
|
9
|
+
|
10
|
+
begin
|
11
|
+
require 'yard'
|
12
|
+
YARD::Rake::YardocTask.new(:doc) do |task|
|
13
|
+
task.files = ['Readme.markdown', 'LICENSE', 'lib/**/*.rb']
|
14
|
+
task.options = [
|
15
|
+
'--output-dir', 'doc',
|
16
|
+
'--markup', 'markdown',
|
17
|
+
]
|
18
|
+
end
|
19
|
+
rescue LoadError
|
20
|
+
end
|
data/Readme.markdown
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# Merry Go Round
|
2
|
+
|
3
|
+
*Note: This is a work in progress and it not production ready. If want to help, we'll love you forever.*
|
4
|
+
|
5
|
+
Simple data-warehousing with Redis and ActiveRecord.
|
6
|
+
|
7
|
+
All data is stored in Redis until it is aggregated. Once it is aggregated, it is stored in ActiveRecord. Merry Go Round handles all of the collecting, aggregating, and querying for you. All you have to do it put your data in and get your data out. All of the hard work of warehousing is done for you automatically.
|
8
|
+
|
9
|
+
Redis is just used as a temporary store until the data can be warehoused in ActiveRecord. You can blow away Redis at anytime and only lose data since the last aggregation.
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Add this line to your application's Gemfile:
|
14
|
+
|
15
|
+
``` ruby
|
16
|
+
gem 'merry_go_round'
|
17
|
+
```
|
18
|
+
|
19
|
+
And then execute:
|
20
|
+
|
21
|
+
$ bundle
|
22
|
+
|
23
|
+
Or install it yourself as:
|
24
|
+
|
25
|
+
$ gem install merry_go_round
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
You'll need to add the migrations to your app. Simply run:
|
30
|
+
|
31
|
+
$ merry install
|
32
|
+
|
33
|
+
Merry Go Round will automatically detect most Redis servers. If you need to configure it, add an initializer with:
|
34
|
+
|
35
|
+
``` ruby
|
36
|
+
MerryGoRound.configure do |config|
|
37
|
+
config.redis = { url: 'redis://redis.example.com:7372/12', namespace: 'mynamespace' }
|
38
|
+
end
|
39
|
+
```
|
40
|
+
|
41
|
+
### Aggregating
|
42
|
+
|
43
|
+
To run the aggregator, run:
|
44
|
+
|
45
|
+
$ merry go
|
46
|
+
|
47
|
+
By default, it will aggregate everything at 1 minute, 1 hour, 1 day, 1 week, 1 month, and 1 year. All you need to do is run the command and it will automatically aggregate for each time period. If that time period is not complete, it will not aggregate them (i.e. if you have been running Merry Go Round for 5 days, it won't generate week and higher aggregations).
|
48
|
+
|
49
|
+
It is recommened to run the aggregator via cron (or [Heroku Scheduler](https://devcenter.heroku.com/articles/scheduler)) every few minutes. Since it uses ActiveRecord to store the aggregations, it will have to load your environment.
|
50
|
+
|
51
|
+
## Contributing
|
52
|
+
|
53
|
+
See the [contributing guide](Contributing.markdown).
|
data/bin/merry
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
module MerryGoRound
|
4
|
+
# Aggregation is the ActiveRecord store for aggregated data points. You should
|
5
|
+
# never create aggregations directly unless you know what you're doing.
|
6
|
+
class Aggregation < ActiveRecord::Base
|
7
|
+
attr_accessible :key, :value, :timestamp, :granularity, :parent_id
|
8
|
+
|
9
|
+
belongs_to :aggregation, foreign_key: :parent_id
|
10
|
+
has_many :aggregations, foreign_key: :parent_id
|
11
|
+
|
12
|
+
def self.values_for_key(key, granularity = 60)
|
13
|
+
where('key = ? AND granularity = ?', granularity)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module MerryGoRound
|
2
|
+
class Aggregator
|
3
|
+
GRANULARITIES = [:minute, :hour, :day, :week, :year] # :month, :quarter
|
4
|
+
|
5
|
+
def aggregate!
|
6
|
+
from_redis
|
7
|
+
existing_slivers
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def redis
|
13
|
+
MerryGoRound.redis
|
14
|
+
end
|
15
|
+
|
16
|
+
# Aggregate stuff since the last aggregation in Redis
|
17
|
+
def from_redis
|
18
|
+
# Aggregate to the first granularity
|
19
|
+
redis_granularity = GRANULARITIES.first
|
20
|
+
|
21
|
+
# Get entry keys from Redis
|
22
|
+
redis_keys = redis.keys 'entry-*'
|
23
|
+
|
24
|
+
# Loop through the Redis keys
|
25
|
+
redis_keys.each do |redis_key|
|
26
|
+
# Extract the timestamp
|
27
|
+
timestamp = Time.utc(redis_key.sub('entry-', '').to_i)
|
28
|
+
|
29
|
+
# Make sure this timestamp hasn't already been aggregated
|
30
|
+
redis.multi do
|
31
|
+
# Get the hash of Merry Go Round keys and values
|
32
|
+
hash = redis.hgetall redis_key
|
33
|
+
|
34
|
+
# Loop through each key/value in the hash
|
35
|
+
hash.each do |key, value|
|
36
|
+
Sliver.create(key: key, value: value, timestamp: timestamp, granularity: redis_granularity)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Delete the key
|
40
|
+
redis.del redis_key
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Aggregate existing slivers (i.e. hour -> day)
|
46
|
+
def existing_slivers
|
47
|
+
# Loop through all of the granularities except for the first one
|
48
|
+
grans = GRANULARITIES.slice(1, GRANULARITIES.length - 1)
|
49
|
+
grans.each_with_index do |granularity, index|
|
50
|
+
# Get the previous granularity
|
51
|
+
prev_gran = GRANULARITIES[index - 1]
|
52
|
+
|
53
|
+
# Get slivers with the previous granularity
|
54
|
+
Sliver.where(granularity: prev_gran, )
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.seconds(granularity)
|
59
|
+
map = {
|
60
|
+
minute: 60,
|
61
|
+
hour: 3600,
|
62
|
+
day: 86400,
|
63
|
+
week: 604800,
|
64
|
+
year: 31536000
|
65
|
+
}
|
66
|
+
map[granularity]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'merry_go_round'
|
3
|
+
|
4
|
+
module MerryGoRound
|
5
|
+
class Cli < Thor
|
6
|
+
desc 'go', 'Aggregate collected data in Redis into ActiveRecord Slivers.'
|
7
|
+
def go
|
8
|
+
MerryGoRound.aggregate!
|
9
|
+
end
|
10
|
+
|
11
|
+
desc 'install', 'Install the Merry Go Round migration'
|
12
|
+
def install
|
13
|
+
system 'rails generate merry_go_round:install'
|
14
|
+
puts "\n\nThe migratation has been installed. Don't forget to run `rake db:migrate`.\n"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module MerryGoRound
|
2
|
+
class Entry
|
3
|
+
def initialize(key, increment = 1, timestamp = Time.now)
|
4
|
+
@key = key
|
5
|
+
@increment = increment
|
6
|
+
|
7
|
+
# Note, storing in the past isn't supported. If you set this to something the
|
8
|
+
# aggregator has already run, the results are undefined.
|
9
|
+
@timestamp = timestamp
|
10
|
+
end
|
11
|
+
|
12
|
+
def record!
|
13
|
+
# Normalize time. Drop seconds and convert to UTC
|
14
|
+
time = Time.at(@timestamp.to_i - @timestamp.sec).utc.to_i
|
15
|
+
|
16
|
+
# Store in Redis
|
17
|
+
redis.hincrby "entry-#{time.to_s}", @key, @increment
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def redis
|
23
|
+
MerryGoRound.redis
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'merry_go_round/version'
|
2
|
+
require 'merry_go_round/aggregator'
|
3
|
+
require 'merry_go_round/entry'
|
4
|
+
require 'merry_go_round/aggregation'
|
5
|
+
require 'merry_go_round/railtie' if defined? Rails
|
6
|
+
|
7
|
+
require 'redis'
|
8
|
+
require 'redis/namespace'
|
9
|
+
|
10
|
+
module MerryGoRound
|
11
|
+
def self.configure
|
12
|
+
yield self
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.aggregate!
|
16
|
+
Aggregator.new.aggregate!
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.record(*args)
|
20
|
+
Entry.new(*args).record!
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.redis
|
24
|
+
# Set redis to nothing make the setter run and setup a default if it's nothing
|
25
|
+
self.redis = {} unless defined? @@redis
|
26
|
+
|
27
|
+
# Return the namespaced Redis instance
|
28
|
+
@@redis
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.redis=(options = {})
|
32
|
+
client = nil
|
33
|
+
if options.is_a?(Redis)
|
34
|
+
client = options
|
35
|
+
else
|
36
|
+
url = options[:url] || determine_redis_provider || 'redis://localhost:6379/0'
|
37
|
+
driver = options[:driver] || 'ruby'
|
38
|
+
namespace = options[:namespace] || 'merry_go_round'
|
39
|
+
|
40
|
+
client = Redis.connect(url: url, driver: driver)
|
41
|
+
end
|
42
|
+
|
43
|
+
@@redis = Redis::Namespace.new(namespace, redis: client)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def self.determine_redis_provider
|
49
|
+
return ENV['REDISTOGO_URL'] if ENV['REDISTOGO_URL']
|
50
|
+
provider = ENV['REDIS_PROVIDER'] || 'REDIS_URL'
|
51
|
+
ENV[provider]
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module MerryGoRound
|
2
|
+
module Generators
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
include Rails::Generators::Migration
|
5
|
+
|
6
|
+
source_root File.expand_path('../templates', __FILE__)
|
7
|
+
desc 'Add Merry Go Round migrations'
|
8
|
+
|
9
|
+
def self.next_migration_number(path)
|
10
|
+
unless @prev_migration_nr
|
11
|
+
@prev_migration_nr = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
|
12
|
+
else
|
13
|
+
@prev_migration_nr += 1
|
14
|
+
end
|
15
|
+
@prev_migration_nr.to_s
|
16
|
+
end
|
17
|
+
|
18
|
+
def copy_migrations
|
19
|
+
migration_template 'add_aggregations.rb', 'db/migrate/add_merry_go_round_aggregations.rb'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class AddMerryGoRoundAggregations < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :merry_go_round_aggregations do |t|
|
4
|
+
# The name of whatever you're tracking
|
5
|
+
t.string :key, null: false
|
6
|
+
|
7
|
+
# The integer value of your count
|
8
|
+
t.integer :value, null: false, default: 0
|
9
|
+
|
10
|
+
# When it was counted rounded to a normalized time
|
11
|
+
t.datetime :timestamp, null: false
|
12
|
+
|
13
|
+
# A string representing the granularity (minute, hour, day, week, month, year)
|
14
|
+
t.string :granularity, null: false
|
15
|
+
|
16
|
+
# Foreign key for tree structure
|
17
|
+
t.integer :parent_id
|
18
|
+
end
|
19
|
+
|
20
|
+
add_index :merry_go_round_aggregations, [:key, :granularity, :timestamp, :parent_id], name: 'merry_go_round_aggregations_kgtp'
|
21
|
+
add_index :merry_go_round_aggregations, [:parent_id, :granularity, :timestamp], name: 'merry_go_round_aggregations_pgt'
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'merry_go_round/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = 'merry_go_round'
|
8
|
+
gem.version = MerryGoRound::VERSION
|
9
|
+
gem.authors = ['Sam Soffes']
|
10
|
+
gem.email = ['sam@soff.es']
|
11
|
+
gem.description = 'Simple data-warehousing.'
|
12
|
+
gem.summary = 'Simple data-warehousing with Redis and PostgreSQL.'
|
13
|
+
gem.homepage = 'https://github.com/seesawco/merry_go_round'
|
14
|
+
gem.license = 'MIT'
|
15
|
+
|
16
|
+
gem.files = `git ls-files`.split($/)
|
17
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
18
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
19
|
+
gem.require_paths = ['lib']
|
20
|
+
|
21
|
+
gem.required_ruby_version = '>= 1.9.2'
|
22
|
+
gem.add_dependency 'activerecord', '>= 3.0.0'
|
23
|
+
gem.add_dependency 'redis', '>= 3.0.0'
|
24
|
+
gem.add_dependency 'redis-namespace'
|
25
|
+
gem.add_dependency 'thor'
|
26
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class MerryGoRoundTest < MerryGoRound::TestCase
|
4
|
+
def test_configure
|
5
|
+
redis = Redis.new
|
6
|
+
MerryGoRound.configure do |config|
|
7
|
+
config.redis = redis
|
8
|
+
end
|
9
|
+
|
10
|
+
# It returns a namespaced Redis, so call `.redis` again on it
|
11
|
+
assert_equal redis, MerryGoRound.redis.redis
|
12
|
+
end
|
13
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
Bundler.require :test
|
4
|
+
|
5
|
+
require 'simplecov'
|
6
|
+
SimpleCov.start
|
7
|
+
|
8
|
+
require 'minitest/autorun'
|
9
|
+
require 'merry_go_round'
|
10
|
+
|
11
|
+
# Support files
|
12
|
+
Dir["#{File.expand_path(File.dirname(__FILE__))}/support/*.rb"].each do |file|
|
13
|
+
require file
|
14
|
+
end
|
15
|
+
|
16
|
+
class MerryGoRound::TestCase < MiniTest::Unit::TestCase
|
17
|
+
end
|
metadata
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: merry_go_round
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Sam Soffes
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-12 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activerecord
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 3.0.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.0.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: redis
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 3.0.0
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 3.0.0
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: redis-namespace
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: thor
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
description: Simple data-warehousing.
|
79
|
+
email:
|
80
|
+
- sam@soff.es
|
81
|
+
executables:
|
82
|
+
- merry
|
83
|
+
extensions: []
|
84
|
+
extra_rdoc_files: []
|
85
|
+
files:
|
86
|
+
- .gitignore
|
87
|
+
- .travis.yml
|
88
|
+
- Contributing.markdown
|
89
|
+
- Gemfile
|
90
|
+
- LICENSE
|
91
|
+
- Rakefile
|
92
|
+
- Readme.markdown
|
93
|
+
- bin/merry
|
94
|
+
- lib/merry_go_round.rb
|
95
|
+
- lib/merry_go_round/aggregation.rb
|
96
|
+
- lib/merry_go_round/aggregator.rb
|
97
|
+
- lib/merry_go_round/cli.rb
|
98
|
+
- lib/merry_go_round/entry.rb
|
99
|
+
- lib/merry_go_round/railtie.rb
|
100
|
+
- lib/merry_go_round/version.rb
|
101
|
+
- lib/rails/generators/merry_go_round/install/USAGE
|
102
|
+
- lib/rails/generators/merry_go_round/install/install_generator.rb
|
103
|
+
- lib/rails/generators/merry_go_round/install/templates/add_aggregations.rb
|
104
|
+
- merry_go_round.gemspec
|
105
|
+
- test/merry_go_round_test.rb
|
106
|
+
- test/test_helper.rb
|
107
|
+
homepage: https://github.com/seesawco/merry_go_round
|
108
|
+
licenses:
|
109
|
+
- MIT
|
110
|
+
post_install_message:
|
111
|
+
rdoc_options: []
|
112
|
+
require_paths:
|
113
|
+
- lib
|
114
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
115
|
+
none: false
|
116
|
+
requirements:
|
117
|
+
- - ! '>='
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: 1.9.2
|
120
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
segments:
|
127
|
+
- 0
|
128
|
+
hash: 3503042711735793145
|
129
|
+
requirements: []
|
130
|
+
rubyforge_project:
|
131
|
+
rubygems_version: 1.8.23
|
132
|
+
signing_key:
|
133
|
+
specification_version: 3
|
134
|
+
summary: Simple data-warehousing with Redis and PostgreSQL.
|
135
|
+
test_files:
|
136
|
+
- test/merry_go_round_test.rb
|
137
|
+
- test/test_helper.rb
|
138
|
+
has_rdoc:
|