pulse_meter_cli 0.4.12

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.
@@ -0,0 +1,19 @@
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
+ *.sw?
19
+ /.idea
@@ -0,0 +1 @@
1
+ 1.9.3-p125
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color -fd
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use 1.9.2
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
4
+ - 1.9.3
5
+ branches:
6
+ only:
7
+ - master
8
+ - develop
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Ilya Averyanov
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.
@@ -0,0 +1,40 @@
1
+ [![Gem Version](https://badge.fury.io/rb/pulse_meter_cli.png)](http://badge.fury.io/rb/pulse_meter_cli)
2
+ [![Build Status](https://secure.travis-ci.org/savonarola/pulse_meter_cli.png)](http://travis-ci.org/savonarola/pulse_meter_cli)
3
+ [![Dependency Status](https://gemnasium.com/savonarola/pulse_meter_cli.png)](https://gemnasium.com/savonarola/pulse_meter_cli)
4
+ [![Code Climate](https://codeclimate.com/github/savonarola/pulse_meter_cli.png)](https://codeclimate.com/github/savonarola/pulse_meter_cli)
5
+
6
+ # PulseMeter
7
+
8
+ PulseMeter is a gem for fast and convenient realtime aggregating of software internal stats through Redis.
9
+
10
+ ## Live Demo
11
+
12
+ A small live demo of PulseMeter gem is located here: [rubybox.ru](http://rubybox.ru), its source code can be found here: [https://github.com/savonarola/pulse_meter_cli-demo](https://github.com/savonarola/pulse_meter_cli-demo)
13
+
14
+ ## Features
15
+
16
+ The gem contains command line tool `pulse` for PulseMeter gem.
17
+
18
+ ## Installation
19
+
20
+ Add this line to your application's Gemfile:
21
+
22
+ ```ruby
23
+ gem 'pulse_meter_cli', require: false
24
+ ```
25
+
26
+ And then execute:
27
+
28
+ $ bundle
29
+
30
+ Or install it yourself as:
31
+
32
+ $ gem install pulse_meter_cli
33
+
34
+ ## Contributing
35
+
36
+ 1. Fork it
37
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
38
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
39
+ 4. Push to the branch (`git push origin my-new-feature`)
40
+ 5. Create new Pull Request
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env rake
2
+ require 'bundler/gem_tasks'
3
+ require 'rspec/core/rake_task'
4
+ require 'yard'
5
+ require 'yard/rake/yardoc_task'
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+
9
+ YARD::Rake::YardocTask.new(:yard)
10
+
11
+ ROOT = File.dirname(__FILE__)
12
+
13
+ task :default => :spec
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '../lib/'))
3
+ require 'pulse_meter_cli'
4
+ require 'cmd'
5
+
6
+ Cmd::All.start
@@ -0,0 +1,171 @@
1
+ require 'thor'
2
+ require 'terminal-table'
3
+ require 'time'
4
+ require 'json'
5
+ require 'csv'
6
+
7
+ module Cmd
8
+ class All < Thor
9
+ include PulseMeter::Mixins::Utils
10
+ include PulseMeter::Mixins::Cmd
11
+ no_tasks do
12
+ def create_redis
13
+ Redis.new :host => options[:host], :port => options[:port], :db => options[:db]
14
+ end
15
+
16
+ def self.common_options
17
+ method_option :host, :default => '127.0.0.1', :desc => "Redis host"
18
+ method_option :port, :default => 6379, :desc => "Redis port"
19
+ method_option :db, :default => 0, :desc => "Redis db"
20
+ end
21
+
22
+ def self.sensor_options(required = [])
23
+ [
24
+ [:interval, :numeric, "Rotation interval"],
25
+ [:ttl, :numeric, "How long summarized data will be stored"],
26
+ [:raw_data_ttl, :numeric, "How long unsummarized raw data will be stored"],
27
+ [:reduce_delay, :numeric, "Delay between end of interval and summarization"],
28
+ [:annotation, :string, "Sensor annotation"]
29
+ ].each do |name, type, desc = data|
30
+ method_option name, :required => required.include?(name), :type => type, :desc => desc
31
+ end
32
+ end
33
+ end
34
+
35
+ desc "sensors", "List all sensors available"
36
+ common_options
37
+ method_option :format, :default => :table, :desc => "Output format: table or csv"
38
+ def sensors
39
+ with_redis {puts all_sensors_table(options[:format])}
40
+ end
41
+
42
+ desc "reduce", "Execute reduction for all sensors' raw data"
43
+ common_options
44
+ def reduce
45
+ with_redis do
46
+ puts 'Registered sensors to be reduced'
47
+ puts all_sensors_table
48
+ PulseMeter::Sensor::Timeline.reduce_all_raw
49
+ puts "DONE"
50
+ end
51
+ end
52
+
53
+ desc "event NAME VALUE", "Send event VALUE to sensor NAME"
54
+ common_options
55
+ method_option :format, :default => :plain, :desc => "Event format: plain or json"
56
+ def event(name, value)
57
+ if "json" == options[:format]
58
+ value = JSON.parse(value)
59
+ end
60
+ with_safe_restore_of(name) {|sensor|
61
+ sensor.event(value)
62
+ }
63
+ PulseMeter.command_aggregator.wait_for_pending_events
64
+ end
65
+
66
+ desc "timeline NAME SECONDS", "Get sensor's NAME timeline for last SECONDS"
67
+ common_options
68
+ method_option :format, :default => :table, :desc => "Output format: table or csv"
69
+ def timeline(name, seconds)
70
+ with_safe_restore_of(name) do |sensor|
71
+ puts sensor.
72
+ timeline(seconds).
73
+ map {|data| [data.start_time, data.value || '']}.
74
+ to_table(options[:format])
75
+ end
76
+ end
77
+
78
+ desc "timeline_within NAME FROM TILL", "Get sensor's NAME timeline in interval. Time format: YYYY-MM-DD HH:MM:SS"
79
+ common_options
80
+ method_option :format, :default => :table, :desc => "Output format: table or csv"
81
+ def timeline_within(name, from, till)
82
+ with_safe_restore_of(name) do |sensor|
83
+ puts sensor.
84
+ timeline_within(Time.parse(from), Time.parse(till)).
85
+ map {|data| [data.start_time, data.value || '']}.
86
+ to_table(options[:format])
87
+ end
88
+ end
89
+
90
+ desc "delete NAME", "Delete sensor by name"
91
+ common_options
92
+ def delete(name)
93
+ with_safe_restore_of(name) {|sensor| sensor.cleanup}
94
+ puts "Sensor #{name} deleted"
95
+ end
96
+
97
+ desc "create NAME TYPE", "Create sensor of given type"
98
+ common_options
99
+ sensor_options([:ttl, :interval])
100
+ def create(name, type)
101
+ with_redis do
102
+ klass = constantize("PulseMeter::Sensor::Timelined::#{type}")
103
+ puts "PulseMeter::Sensor::Timelined::#{type}"
104
+ fail! "Unknown sensor type #{type}" unless klass
105
+ sensor = klass.new(name, options.dup)
106
+ puts "Sensor created"
107
+ puts all_sensors_table
108
+ end
109
+ end
110
+
111
+ desc "update NAME", "Update given sensor"
112
+ common_options
113
+ sensor_options
114
+ def update(name)
115
+ with_safe_restore_of(name) do |sensor|
116
+ opts = options.dup
117
+ [:ttl, :interval, :reduce_delay, :raw_data_ttl, :annotation].each do |attr|
118
+ opts[attr] ||= sensor.send(attr)
119
+ end
120
+ klass = sensor.class
121
+ new_sensor = klass.new(name, opts)
122
+ new_sensor.dump!(false)
123
+ puts "Sensor updated"
124
+ puts all_sensors_table
125
+ end
126
+ end
127
+
128
+ desc "create_simple NAME TYPE", "Create simple non-timelined sensor of given type"
129
+ common_options
130
+ method_option :annotation, :type => :string, :desc => "Sensor annotation"
131
+ def create_simple(name, type)
132
+ with_redis do
133
+ klass = constantize("PulseMeter::Sensor::#{type}")
134
+ fail! "Unknown sensor type #{type}" unless klass
135
+ sensor = klass.new(name, options.dup)
136
+ puts "Sensor created"
137
+ puts all_sensors_table
138
+ end
139
+ end
140
+
141
+ desc "value NAME", "Get value of non-timelined sensor"
142
+ def value(name)
143
+ with_safe_restore_of(name) do |sensor|
144
+ fail! "Sensor #{name} has no value method" unless sensor.respond_to?(:value)
145
+ puts "Value: #{sensor.value}"
146
+ end
147
+ end
148
+
149
+ desc "drop NAME DATE_FROM(YYYYmmddHHMMSS) DATE_TO(YYYYmmddHHMMSS)", "Drop timeline data of a particular sensor"
150
+ common_options
151
+ def drop(name, from, to)
152
+ time_from = parse_time(from)
153
+ time_to = parse_time(to)
154
+ with_safe_restore_of(name) do |sensor|
155
+ fail! "Sensor #{name} has no drop_within method" unless sensor.respond_to?(:drop_within)
156
+ sensor.drop_within(time_from, time_to)
157
+ end
158
+ end
159
+
160
+ desc "udp_proxy HOST PORT", "Start UDP proxy for sensor data"
161
+ common_options
162
+ def udp_proxy(host, port)
163
+ with_redis do
164
+ puts 'Starting UDP server'
165
+ server = PulseMeter::UDPServer.new(host, port)
166
+ server.start
167
+ end
168
+ end
169
+
170
+ end
171
+ end
@@ -0,0 +1,24 @@
1
+ module Enumerable
2
+ require 'csv'
3
+ require 'terminal-table'
4
+
5
+ def convert_time
6
+ map {|el| el.is_a?(Time) ? el.to_i : el}
7
+ end
8
+
9
+ def to_table(format = nil)
10
+ if "csv" == format.to_s
11
+ CSV.generate(:col_sep => ';') do |csv|
12
+ self.each {|row| csv << row.convert_time}
13
+ end
14
+ else
15
+ self.each_with_object(Terminal::Table.new) do |row, table|
16
+ table << if row.respond_to?(:map)
17
+ row.map(&:to_s)
18
+ else
19
+ row
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,46 @@
1
+ require 'pulse_meter/extensions/enumerable'
2
+
3
+ module PulseMeter
4
+ module Mixins
5
+ # Mixin with command-line utilities
6
+ module Cmd
7
+ def with_redis
8
+ PulseMeter.redis = create_redis
9
+ yield
10
+ end
11
+
12
+ def with_safe_restore_of(name, &block)
13
+ with_redis do
14
+ sensor = PulseMeter::Sensor::Base.restore(name)
15
+ block.call(sensor)
16
+ end
17
+ rescue PulseMeter::RestoreError
18
+ fail! "Sensor #{name} is unknown or cannot be restored"
19
+ end
20
+
21
+ def all_sensors
22
+ PulseMeter::Sensor::Timeline.list_objects
23
+ end
24
+
25
+ def all_sensors_table(format = nil)
26
+ data = [
27
+ ["Name", "Class", "ttl", "raw data ttl", "interval", "reduce delay"],
28
+ ]
29
+ data << :separator unless 'csv' == format.to_s
30
+ all_sensors.each do |s|
31
+ if s.kind_of? PulseMeter::Sensor::Timeline
32
+ data << [s.name, s.class, s.ttl, s.raw_data_ttl, s.interval, s.reduce_delay]
33
+ else
34
+ data << [s.name, s.class] + [''] * 4
35
+ end
36
+ end
37
+ data.to_table(format)
38
+ end
39
+
40
+ def fail!(description = nil)
41
+ puts description if description
42
+ exit 1
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,2 @@
1
+ require "pulse_meter_core"
2
+ require "pulse_meter/mixins/cmd"
@@ -0,0 +1,33 @@
1
+ # -*- encoding: utf-8 -*-
2
+ Gem::Specification.new do |gem|
3
+ gem.authors = ["Ilya Averyanov", "Sergey Averyanov"]
4
+ gem.email = ["av@fun-box.ru", "averyanov@gmail.com"]
5
+ gem.description = %q{CLI for pulse-meter metrics processor}
6
+ gem.summary = %q{
7
+ CLI for lightweight Redis-based metrics aggregator and processor PulseMeter
8
+ }
9
+ gem.homepage = "https://github.com/savonarola/pulse_meter_cli"
10
+
11
+ gem.required_ruby_version = '>= 1.9.2'
12
+ gem.files = `git ls-files`.split($\)
13
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
14
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
15
+ gem.name = "pulse_meter_cli"
16
+ gem.require_paths = ["lib"]
17
+ gem.version = "0.4.12"
18
+
19
+ gem.add_runtime_dependency('pulse_meter_core')
20
+ gem.add_runtime_dependency('terminal-table')
21
+ gem.add_runtime_dependency('thor')
22
+
23
+ gem.add_development_dependency('aquarium')
24
+ gem.add_development_dependency('hashie')
25
+ gem.add_development_dependency('mock_redis')
26
+ gem.add_development_dependency('rake')
27
+ gem.add_development_dependency('redcarpet')
28
+ gem.add_development_dependency('rspec')
29
+ gem.add_development_dependency('simplecov')
30
+ gem.add_development_dependency('timecop')
31
+ gem.add_development_dependency('yard')
32
+
33
+ end
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+ require 'pulse_meter/extensions/enumerable'
3
+
4
+ describe Enumerable do
5
+ let!(:time) {Time.new}
6
+ describe "#convert_time" do
7
+ it "converts Time objects to unixtime" do
8
+ [time].convert_time.should == [time.to_i]
9
+ end
10
+
11
+ it "does not change other members" do
12
+ [1, 2, 3].convert_time.should == [1, 2 ,3]
13
+ end
14
+ end
15
+
16
+ describe "#to_table" do
17
+ context "when format is csv" do
18
+ it "returns csv as string" do
19
+ [].to_table(:csv).should be_instance_of(String)
20
+ end
21
+
22
+ it "returns csv containing each subarray as a row" do
23
+ [[:a, :b], [:c, :d]].to_table(:csv).should == "a;b\nc;d\n"
24
+ end
25
+
26
+ it "converts Time objects to unixtime" do
27
+ [[time]].to_table(:csv).should == "#{time.to_i}\n"
28
+ end
29
+
30
+ it "takes format argument both as string and as symbol" do
31
+ [[:foo]].to_table("csv").should == "foo\n"
32
+ [[:foo]].to_table(:csv).should == "foo\n"
33
+ end
34
+ end
35
+
36
+ context "when format is table" do
37
+ it "return Terminal::Table instance" do
38
+ [].to_table.should be_instance_of(Terminal::Table)
39
+ end
40
+
41
+ it "returns table containing each subarray as a row" do
42
+ data = [[:a, :b], [:c, :d]]
43
+ table = [[:a, :b], [:c, :d]].to_table
44
+ table.rows.map do |row|
45
+ row.cells.map(&:to_s).map(&:strip).map(&:to_sym)
46
+ end.should == data
47
+ end
48
+ end
49
+
50
+ it "uses table format as default" do
51
+ [].to_table.should be_instance_of(Terminal::Table)
52
+ end
53
+
54
+ it "uses table format unless it is :csv or 'csv'" do
55
+ [].to_table(:unknown_format).should be_instance_of(Terminal::Table)
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,117 @@
1
+ require 'spec_helper'
2
+
3
+ describe PulseMeter::Mixins::Cmd do
4
+ class CmdDummy
5
+ include PulseMeter::Mixins::Cmd
6
+
7
+ def initialize(redis)
8
+ @redis = redis
9
+ end
10
+
11
+ def create_redis
12
+ @redis
13
+ end
14
+ end
15
+
16
+ let(:redis){ MockRedis.new }
17
+ let(:dummy){ CmdDummy.new(redis) }
18
+ before{ PulseMeter.redis = redis }
19
+
20
+ describe "#fail!" do
21
+ it "prints given message and exits" do
22
+ STDOUT.should_receive(:puts).with(:msg)
23
+ lambda {dummy.fail!(:msg)}.should raise_error(SystemExit)
24
+ end
25
+ end
26
+
27
+ describe '#with_redis' do
28
+ it "initializes redies and yields a block" do
29
+ PulseMeter.redis = nil
30
+ dummy.with_redis do
31
+ PulseMeter.redis.should_not be_nil
32
+ end
33
+ end
34
+ end
35
+
36
+ describe "#with_safe_restore_of" do
37
+ it "restores sensor by name and passes it to block" do
38
+ sensor = PulseMeter::Sensor::Counter.new(:foo)
39
+ dummy.with_safe_restore_of(:foo) do |s|
40
+ s.should be_instance_of(sensor.class)
41
+ end
42
+ end
43
+
44
+ it "prints error and exits if sensor cannot be restored" do
45
+ STDOUT.should_receive(:puts).with("Sensor nonexistant is unknown or cannot be restored")
46
+ lambda {dummy.with_safe_restore_of(:nonexistant) {|s| s}}.should raise_error(SystemExit)
47
+ end
48
+ end
49
+
50
+ describe "#all_sensors" do
51
+ it "is just an alias to PulseMeter::Sensor::Timeline.list_objects" do
52
+ PulseMeter::Sensor::Timeline.should_receive(:list_objects)
53
+ dummy.all_sensors
54
+ end
55
+ end
56
+
57
+ describe "#all_sensors_table" do
58
+ before {PulseMeter.redis.flushall}
59
+ let(:init_values){ {:ttl => 1, :raw_data_ttl => 2, :interval => 3, :reduce_delay => 4} }
60
+ let!(:s1) {PulseMeter::Sensor::Counter.new(:s1)}
61
+ let!(:s2) {PulseMeter::Sensor::Timelined::Counter.new(:s2, init_values)}
62
+ let!(:table) {dummy.all_sensors_table}
63
+ let!(:csv) {dummy.all_sensors_table(:csv)}
64
+ let!(:parsed_csv) {CSV.parse(csv, col_sep: ";")}
65
+
66
+ def rows(format)
67
+ if "csv" == format.to_s
68
+ parsed_csv
69
+ else
70
+ table.rows.map do |row|
71
+ row.cells.map(&:to_s).map(&:strip)
72
+ end
73
+ end
74
+ end
75
+
76
+ def sensor_row(name, format)
77
+ rows(format).select {|row| row[0] == name}.first
78
+ end
79
+
80
+ [:csv, :table].each do |format|
81
+ context "when format is #{format}" do
82
+
83
+ if "csv" == format.to_s
84
+ it "returns csv as string" do
85
+ csv.should be_instance_of(String)
86
+ end
87
+ else
88
+ it "returns Terminal::Table instance" do
89
+ table.should be_instance_of(Terminal::Table)
90
+ end
91
+ end
92
+
93
+ it "has title row" do
94
+ rows(format)[0].should == ["Name", "Class", "ttl", "raw data ttl", "interval", "reduce delay"]
95
+ end
96
+
97
+ it "has one row for each sensor (and a title)" do
98
+ rows(format).count.should == 3
99
+ end
100
+
101
+ it "can display timelined sensors" do
102
+ sensor_row("s2", format).should == [
103
+ s2.name, s2.class, s2.ttl, s2.raw_data_ttl, s2.interval, s2.reduce_delay
104
+ ].map(&:to_s)
105
+ end
106
+
107
+ it "can display static sensors" do
108
+ sensor_row("s1", format).should == [
109
+ s1.name, s1.class, "", "", "", ""
110
+ ].map(&:to_s)
111
+ end
112
+
113
+ end
114
+ end
115
+ end
116
+
117
+ end
@@ -0,0 +1,23 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ $:.unshift File.expand_path('../../lib/', __FILE__)
4
+
5
+ ROOT = File.expand_path('../..', __FILE__)
6
+
7
+ Bundler.require(:development)
8
+
9
+ SimpleCov.start
10
+
11
+ require 'pulse_meter_cli'
12
+ PulseMeter.redis = MockRedis.new
13
+
14
+ RSpec.configure do |config|
15
+ config.before(:each) do
16
+ PulseMeter.redis = MockRedis.new
17
+ Timecop.return
18
+ PulseMeter.logger = Logger.new("/dev/null")
19
+ end
20
+ config.filter_run :focus => true
21
+ config.run_all_when_everything_filtered = true
22
+ end
23
+
metadata ADDED
@@ -0,0 +1,265 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pulse_meter_cli
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.12
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ilya Averyanov
9
+ - Sergey Averyanov
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2013-06-16 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: pulse_meter_core
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: '0'
31
+ - !ruby/object:Gem::Dependency
32
+ name: terminal-table
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ type: :runtime
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: thor
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ - !ruby/object:Gem::Dependency
64
+ name: aquarium
65
+ requirement: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ type: :development
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ - !ruby/object:Gem::Dependency
80
+ name: hashie
81
+ requirement: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ type: :development
88
+ prerelease: false
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ - !ruby/object:Gem::Dependency
96
+ name: mock_redis
97
+ requirement: !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ! '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rake
113
+ requirement: !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ! '>='
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ none: false
123
+ requirements:
124
+ - - ! '>='
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ - !ruby/object:Gem::Dependency
128
+ name: redcarpet
129
+ requirement: !ruby/object:Gem::Requirement
130
+ none: false
131
+ requirements:
132
+ - - ! '>='
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ type: :development
136
+ prerelease: false
137
+ version_requirements: !ruby/object:Gem::Requirement
138
+ none: false
139
+ requirements:
140
+ - - ! '>='
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ - !ruby/object:Gem::Dependency
144
+ name: rspec
145
+ requirement: !ruby/object:Gem::Requirement
146
+ none: false
147
+ requirements:
148
+ - - ! '>='
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ type: :development
152
+ prerelease: false
153
+ version_requirements: !ruby/object:Gem::Requirement
154
+ none: false
155
+ requirements:
156
+ - - ! '>='
157
+ - !ruby/object:Gem::Version
158
+ version: '0'
159
+ - !ruby/object:Gem::Dependency
160
+ name: simplecov
161
+ requirement: !ruby/object:Gem::Requirement
162
+ none: false
163
+ requirements:
164
+ - - ! '>='
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ type: :development
168
+ prerelease: false
169
+ version_requirements: !ruby/object:Gem::Requirement
170
+ none: false
171
+ requirements:
172
+ - - ! '>='
173
+ - !ruby/object:Gem::Version
174
+ version: '0'
175
+ - !ruby/object:Gem::Dependency
176
+ name: timecop
177
+ requirement: !ruby/object:Gem::Requirement
178
+ none: false
179
+ requirements:
180
+ - - ! '>='
181
+ - !ruby/object:Gem::Version
182
+ version: '0'
183
+ type: :development
184
+ prerelease: false
185
+ version_requirements: !ruby/object:Gem::Requirement
186
+ none: false
187
+ requirements:
188
+ - - ! '>='
189
+ - !ruby/object:Gem::Version
190
+ version: '0'
191
+ - !ruby/object:Gem::Dependency
192
+ name: yard
193
+ requirement: !ruby/object:Gem::Requirement
194
+ none: false
195
+ requirements:
196
+ - - ! '>='
197
+ - !ruby/object:Gem::Version
198
+ version: '0'
199
+ type: :development
200
+ prerelease: false
201
+ version_requirements: !ruby/object:Gem::Requirement
202
+ none: false
203
+ requirements:
204
+ - - ! '>='
205
+ - !ruby/object:Gem::Version
206
+ version: '0'
207
+ description: CLI for pulse-meter metrics processor
208
+ email:
209
+ - av@fun-box.ru
210
+ - averyanov@gmail.com
211
+ executables:
212
+ - pulse
213
+ extensions: []
214
+ extra_rdoc_files: []
215
+ files:
216
+ - .gitignore
217
+ - .rbenv-version
218
+ - .rspec
219
+ - .rvmrc
220
+ - .travis.yml
221
+ - Gemfile
222
+ - LICENSE
223
+ - README.md
224
+ - Rakefile
225
+ - bin/pulse
226
+ - lib/cmd.rb
227
+ - lib/pulse_meter/extensions/enumerable.rb
228
+ - lib/pulse_meter/mixins/cmd.rb
229
+ - lib/pulse_meter_cli.rb
230
+ - pulse_meter_cli.gemspec
231
+ - spec/pulse_meter/extensions/enumerable_spec.rb
232
+ - spec/pulse_meter/mixins/cmd_spec.rb
233
+ - spec/spec_helper.rb
234
+ homepage: https://github.com/savonarola/pulse_meter_cli
235
+ licenses: []
236
+ post_install_message:
237
+ rdoc_options: []
238
+ require_paths:
239
+ - lib
240
+ required_ruby_version: !ruby/object:Gem::Requirement
241
+ none: false
242
+ requirements:
243
+ - - ! '>='
244
+ - !ruby/object:Gem::Version
245
+ version: 1.9.2
246
+ required_rubygems_version: !ruby/object:Gem::Requirement
247
+ none: false
248
+ requirements:
249
+ - - ! '>='
250
+ - !ruby/object:Gem::Version
251
+ version: '0'
252
+ segments:
253
+ - 0
254
+ hash: -3626993509759145837
255
+ requirements: []
256
+ rubyforge_project:
257
+ rubygems_version: 1.8.23
258
+ signing_key:
259
+ specification_version: 3
260
+ summary: CLI for lightweight Redis-based metrics aggregator and processor PulseMeter
261
+ test_files:
262
+ - spec/pulse_meter/extensions/enumerable_spec.rb
263
+ - spec/pulse_meter/mixins/cmd_spec.rb
264
+ - spec/spec_helper.rb
265
+ has_rdoc: