pulse-meter 0.4.9 → 0.4.11
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -48
- data/lib/pulse-meter.rb +1 -68
- data/lib/pulse-meter/visualizer.rb +1 -40
- data/pulse-meter.gemspec +4 -26
- metadata +10 -558
- data/Procfile +0 -3
- data/bin/pulse +0 -6
- data/examples/basic.ru +0 -145
- data/examples/basic_sensor_data.rb +0 -96
- data/examples/udp_benchmark.rb +0 -29
- data/lib/cmd.rb +0 -171
- data/lib/pulse-meter/command_aggregator/async.rb +0 -83
- data/lib/pulse-meter/command_aggregator/sync.rb +0 -18
- data/lib/pulse-meter/command_aggregator/udp.rb +0 -48
- data/lib/pulse-meter/extensions/enumerable.rb +0 -24
- data/lib/pulse-meter/mixins/cmd.rb +0 -46
- data/lib/pulse-meter/mixins/dumper.rb +0 -87
- data/lib/pulse-meter/mixins/utils.rb +0 -155
- data/lib/pulse-meter/observer.rb +0 -120
- data/lib/pulse-meter/observer/extended.rb +0 -34
- data/lib/pulse-meter/sensor.rb +0 -61
- data/lib/pulse-meter/sensor/base.rb +0 -88
- data/lib/pulse-meter/sensor/configuration.rb +0 -106
- data/lib/pulse-meter/sensor/counter.rb +0 -39
- data/lib/pulse-meter/sensor/hashed_counter.rb +0 -36
- data/lib/pulse-meter/sensor/hashed_indicator.rb +0 -24
- data/lib/pulse-meter/sensor/indicator.rb +0 -35
- data/lib/pulse-meter/sensor/multi.rb +0 -97
- data/lib/pulse-meter/sensor/timeline.rb +0 -236
- data/lib/pulse-meter/sensor/timeline_reduce.rb +0 -68
- data/lib/pulse-meter/sensor/timelined/average.rb +0 -32
- data/lib/pulse-meter/sensor/timelined/counter.rb +0 -23
- data/lib/pulse-meter/sensor/timelined/hashed_counter.rb +0 -31
- data/lib/pulse-meter/sensor/timelined/hashed_indicator.rb +0 -30
- data/lib/pulse-meter/sensor/timelined/indicator.rb +0 -23
- data/lib/pulse-meter/sensor/timelined/max.rb +0 -19
- data/lib/pulse-meter/sensor/timelined/median.rb +0 -14
- data/lib/pulse-meter/sensor/timelined/min.rb +0 -19
- data/lib/pulse-meter/sensor/timelined/multi_percentile.rb +0 -34
- data/lib/pulse-meter/sensor/timelined/percentile.rb +0 -22
- data/lib/pulse-meter/sensor/timelined/uniq_counter.rb +0 -22
- data/lib/pulse-meter/sensor/timelined/zset_based.rb +0 -38
- data/lib/pulse-meter/sensor/uniq_counter.rb +0 -24
- data/lib/pulse-meter/server.rb +0 -0
- data/lib/pulse-meter/server/command_line_options.rb +0 -0
- data/lib/pulse-meter/server/config_options.rb +0 -0
- data/lib/pulse-meter/server/sensors.rb +0 -0
- data/lib/pulse-meter/udp_server.rb +0 -45
- data/lib/pulse-meter/version.rb +0 -3
- data/lib/pulse-meter/visualize/app.rb +0 -78
- data/lib/pulse-meter/visualize/base.rb +0 -15
- data/lib/pulse-meter/visualize/coffee/application.coffee +0 -40
- data/lib/pulse-meter/visualize/coffee/collections/page_info_list.coffee +0 -17
- data/lib/pulse-meter/visualize/coffee/collections/sensor_info_list.coffee +0 -4
- data/lib/pulse-meter/visualize/coffee/collections/widget_list.coffee +0 -14
- data/lib/pulse-meter/visualize/coffee/extensions.coffee +0 -26
- data/lib/pulse-meter/visualize/coffee/models/dinamic_widget.coffee +0 -34
- data/lib/pulse-meter/visualize/coffee/models/page_info.coffee +0 -2
- data/lib/pulse-meter/visualize/coffee/models/sensor_info.coffee +0 -2
- data/lib/pulse-meter/visualize/coffee/models/widget.coffee +0 -54
- data/lib/pulse-meter/visualize/coffee/presenters/area.coffee +0 -2
- data/lib/pulse-meter/visualize/coffee/presenters/gauge.coffee +0 -11
- data/lib/pulse-meter/visualize/coffee/presenters/line.coffee +0 -2
- data/lib/pulse-meter/visualize/coffee/presenters/pie.coffee +0 -20
- data/lib/pulse-meter/visualize/coffee/presenters/series.coffee +0 -44
- data/lib/pulse-meter/visualize/coffee/presenters/table.coffee +0 -10
- data/lib/pulse-meter/visualize/coffee/presenters/timeline.coffee +0 -13
- data/lib/pulse-meter/visualize/coffee/presenters/widget.coffee +0 -65
- data/lib/pulse-meter/visualize/coffee/router.coffee +0 -21
- data/lib/pulse-meter/visualize/coffee/views/dynamic_chart.coffee +0 -91
- data/lib/pulse-meter/visualize/coffee/views/dynamic_widget.coffee +0 -58
- data/lib/pulse-meter/visualize/coffee/views/page_title.coffee +0 -17
- data/lib/pulse-meter/visualize/coffee/views/page_titles.coffee +0 -15
- data/lib/pulse-meter/visualize/coffee/views/sensor_info_list.coffee +0 -19
- data/lib/pulse-meter/visualize/coffee/views/widget.coffee +0 -99
- data/lib/pulse-meter/visualize/coffee/views/widget_chart.coffee +0 -13
- data/lib/pulse-meter/visualize/coffee/views/widget_list.coffee +0 -15
- data/lib/pulse-meter/visualize/dsl/base.rb +0 -131
- data/lib/pulse-meter/visualize/dsl/errors.rb +0 -40
- data/lib/pulse-meter/visualize/dsl/layout.rb +0 -27
- data/lib/pulse-meter/visualize/dsl/page.rb +0 -33
- data/lib/pulse-meter/visualize/dsl/sensor.rb +0 -20
- data/lib/pulse-meter/visualize/dsl/widget.rb +0 -37
- data/lib/pulse-meter/visualize/dsl/widgets/area.rb +0 -20
- data/lib/pulse-meter/visualize/dsl/widgets/gauge.rb +0 -12
- data/lib/pulse-meter/visualize/dsl/widgets/line.rb +0 -21
- data/lib/pulse-meter/visualize/dsl/widgets/pie.rb +0 -16
- data/lib/pulse-meter/visualize/dsl/widgets/table.rb +0 -19
- data/lib/pulse-meter/visualize/layout.rb +0 -79
- data/lib/pulse-meter/visualize/page.rb +0 -25
- data/lib/pulse-meter/visualize/public/css/application.css +0 -56
- data/lib/pulse-meter/visualize/public/css/bootstrap.css +0 -4883
- data/lib/pulse-meter/visualize/public/css/bootstrap.min.css +0 -729
- data/lib/pulse-meter/visualize/public/css/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/lib/pulse-meter/visualize/public/css/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/lib/pulse-meter/visualize/public/css/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/lib/pulse-meter/visualize/public/css/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/lib/pulse-meter/visualize/public/css/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/lib/pulse-meter/visualize/public/css/images/ui-bg_glass_75_ffffff_1x400.png +0 -0
- data/lib/pulse-meter/visualize/public/css/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/lib/pulse-meter/visualize/public/css/images/ui-bg_inset-soft_95_fef1ec_1x100.png +0 -0
- data/lib/pulse-meter/visualize/public/css/images/ui-icons_222222_256x240.png +0 -0
- data/lib/pulse-meter/visualize/public/css/images/ui-icons_2e83ff_256x240.png +0 -0
- data/lib/pulse-meter/visualize/public/css/images/ui-icons_454545_256x240.png +0 -0
- data/lib/pulse-meter/visualize/public/css/images/ui-icons_888888_256x240.png +0 -0
- data/lib/pulse-meter/visualize/public/css/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/lib/pulse-meter/visualize/public/css/images/ui-icons_f6cf3b_256x240.png +0 -0
- data/lib/pulse-meter/visualize/public/css/jquery-ui-1.8.16.bootstrap.css +0 -1320
- data/lib/pulse-meter/visualize/public/favicon.ico +0 -208
- data/lib/pulse-meter/visualize/public/img/glyphicons-halflings-white.png +0 -0
- data/lib/pulse-meter/visualize/public/img/glyphicons-halflings.png +0 -0
- data/lib/pulse-meter/visualize/public/js/application.js +0 -973
- data/lib/pulse-meter/visualize/public/js/backbone-min.js +0 -38
- data/lib/pulse-meter/visualize/public/js/bootstrap.js +0 -1835
- data/lib/pulse-meter/visualize/public/js/jquery-1.7.2.min.js +0 -4
- data/lib/pulse-meter/visualize/public/js/jquery-ui-1.8.16.bootstrap.min.js +0 -791
- data/lib/pulse-meter/visualize/public/js/jquery-ui-1.8.23.custom.min.js +0 -21
- data/lib/pulse-meter/visualize/public/js/jquery-ui-timepicker-addon.js +0 -1687
- data/lib/pulse-meter/visualize/public/js/json2.js +0 -487
- data/lib/pulse-meter/visualize/public/js/underscore-min.js +0 -32
- data/lib/pulse-meter/visualize/sensor.rb +0 -63
- data/lib/pulse-meter/visualize/series_extractor.rb +0 -107
- data/lib/pulse-meter/visualize/views/main.haml +0 -30
- data/lib/pulse-meter/visualize/views/sensors.haml +0 -76
- data/lib/pulse-meter/visualize/views/widgets/area.haml +0 -53
- data/lib/pulse-meter/visualize/views/widgets/extend_options.haml +0 -11
- data/lib/pulse-meter/visualize/views/widgets/gauge.haml +0 -13
- data/lib/pulse-meter/visualize/views/widgets/line.haml +0 -54
- data/lib/pulse-meter/visualize/views/widgets/pie.haml +0 -13
- data/lib/pulse-meter/visualize/views/widgets/table.haml +0 -45
- data/lib/pulse-meter/visualize/widget.rb +0 -38
- data/lib/pulse-meter/visualize/widgets/gauge.rb +0 -47
- data/lib/pulse-meter/visualize/widgets/pie.rb +0 -36
- data/lib/pulse-meter/visualize/widgets/timeline.rb +0 -114
- data/spec/pulse_meter/command_aggregator/async_spec.rb +0 -53
- data/spec/pulse_meter/command_aggregator/sync_spec.rb +0 -25
- data/spec/pulse_meter/command_aggregator/udp_spec.rb +0 -45
- data/spec/pulse_meter/extensions/enumerable_spec.rb +0 -58
- data/spec/pulse_meter/mixins/cmd_spec.rb +0 -117
- data/spec/pulse_meter/mixins/dumper_spec.rb +0 -162
- data/spec/pulse_meter/mixins/utils_spec.rb +0 -212
- data/spec/pulse_meter/observer/extended_spec.rb +0 -92
- data/spec/pulse_meter/observer_spec.rb +0 -207
- data/spec/pulse_meter/sensor/base_spec.rb +0 -106
- data/spec/pulse_meter/sensor/configuration_spec.rb +0 -103
- data/spec/pulse_meter/sensor/counter_spec.rb +0 -54
- data/spec/pulse_meter/sensor/hashed_counter_spec.rb +0 -43
- data/spec/pulse_meter/sensor/hashed_indicator_spec.rb +0 -39
- data/spec/pulse_meter/sensor/indicator_spec.rb +0 -43
- data/spec/pulse_meter/sensor/multi_spec.rb +0 -137
- data/spec/pulse_meter/sensor/timeline_spec.rb +0 -88
- data/spec/pulse_meter/sensor/timelined/average_spec.rb +0 -6
- data/spec/pulse_meter/sensor/timelined/counter_spec.rb +0 -6
- data/spec/pulse_meter/sensor/timelined/hashed_counter_spec.rb +0 -8
- data/spec/pulse_meter/sensor/timelined/hashed_indicator_spec.rb +0 -8
- data/spec/pulse_meter/sensor/timelined/indicator_spec.rb +0 -6
- data/spec/pulse_meter/sensor/timelined/max_spec.rb +0 -7
- data/spec/pulse_meter/sensor/timelined/median_spec.rb +0 -7
- data/spec/pulse_meter/sensor/timelined/min_spec.rb +0 -7
- data/spec/pulse_meter/sensor/timelined/multi_percentile_spec.rb +0 -21
- data/spec/pulse_meter/sensor/timelined/percentile_spec.rb +0 -17
- data/spec/pulse_meter/sensor/timelined/uniq_counter_spec.rb +0 -9
- data/spec/pulse_meter/sensor/uniq_counter_spec.rb +0 -28
- data/spec/pulse_meter/udp_server_spec.rb +0 -36
- data/spec/pulse_meter/visualize/app_spec.rb +0 -27
- data/spec/pulse_meter/visualize/dsl/layout_spec.rb +0 -64
- data/spec/pulse_meter/visualize/dsl/page_spec.rb +0 -62
- data/spec/pulse_meter/visualize/dsl/sensor_spec.rb +0 -30
- data/spec/pulse_meter/visualize/dsl/widget_spec.rb +0 -6
- data/spec/pulse_meter/visualize/dsl/widgets/area_spec.rb +0 -44
- data/spec/pulse_meter/visualize/dsl/widgets/gauge_spec.rb +0 -22
- data/spec/pulse_meter/visualize/dsl/widgets/line_spec.rb +0 -44
- data/spec/pulse_meter/visualize/dsl/widgets/pie_spec.rb +0 -35
- data/spec/pulse_meter/visualize/dsl/widgets/table_spec.rb +0 -36
- data/spec/pulse_meter/visualize/layout_spec.rb +0 -54
- data/spec/pulse_meter/visualize/page_spec.rb +0 -153
- data/spec/pulse_meter/visualize/sensor_spec.rb +0 -120
- data/spec/pulse_meter/visualize/series_extractor_spec.rb +0 -80
- data/spec/pulse_meter/visualize/widgets/area_spec.rb +0 -6
- data/spec/pulse_meter/visualize/widgets/gauge_spec.rb +0 -63
- data/spec/pulse_meter/visualize/widgets/line_spec.rb +0 -6
- data/spec/pulse_meter/visualize/widgets/pie_spec.rb +0 -73
- data/spec/pulse_meter/visualize/widgets/table_spec.rb +0 -6
- data/spec/pulse_meter/visualizer_spec.rb +0 -42
- data/spec/pulse_meter_spec.rb +0 -73
- data/spec/shared_examples/dsl_widget.rb +0 -106
- data/spec/shared_examples/timeline_sensor.rb +0 -439
- data/spec/shared_examples/timelined_subclass.rb +0 -23
- data/spec/shared_examples/widget.rb +0 -97
- data/spec/spec_helper.rb +0 -40
- data/spec/support/matchers.rb +0 -34
- data/spec/support/observered.rb +0 -40
@@ -1,83 +0,0 @@
|
|
1
|
-
require 'singleton'
|
2
|
-
require 'thread'
|
3
|
-
|
4
|
-
module PulseMeter
|
5
|
-
module CommandAggregator
|
6
|
-
class Async
|
7
|
-
include Singleton
|
8
|
-
|
9
|
-
MAX_QUEUE_LENGTH = 10_000
|
10
|
-
|
11
|
-
attr_reader :max_queue_length
|
12
|
-
|
13
|
-
def initialize
|
14
|
-
@max_queue_length = MAX_QUEUE_LENGTH
|
15
|
-
@queue = Queue.new
|
16
|
-
@buffer = []
|
17
|
-
@in_multi = false
|
18
|
-
@consumer_thread = run_consumer
|
19
|
-
at_exit{ wait_for_pending_events }
|
20
|
-
end
|
21
|
-
|
22
|
-
def multi
|
23
|
-
@in_multi = true
|
24
|
-
yield
|
25
|
-
ensure
|
26
|
-
@in_multi = false
|
27
|
-
send_buffer_to_queue
|
28
|
-
end
|
29
|
-
|
30
|
-
def method_missing(*args)
|
31
|
-
@buffer << args
|
32
|
-
send_buffer_to_queue unless @in_multi
|
33
|
-
end
|
34
|
-
|
35
|
-
def wait_for_pending_events(max_seconds = 1)
|
36
|
-
left_to_wait = max_seconds.to_f
|
37
|
-
sleep_step = 0.01
|
38
|
-
while has_pending_events? && left_to_wait > 0
|
39
|
-
left_to_wait -= sleep_step
|
40
|
-
sleep(sleep_step)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
private
|
45
|
-
|
46
|
-
def has_pending_events?
|
47
|
-
!@queue.empty?
|
48
|
-
end
|
49
|
-
|
50
|
-
def send_buffer_to_queue
|
51
|
-
if @queue.size < @max_queue_length
|
52
|
-
@queue << @buffer
|
53
|
-
end
|
54
|
-
@buffer = []
|
55
|
-
end
|
56
|
-
|
57
|
-
def redis
|
58
|
-
PulseMeter.redis
|
59
|
-
end
|
60
|
-
|
61
|
-
def consume_commands
|
62
|
-
# redis and @queue are threadsafe
|
63
|
-
while commands = @queue.pop
|
64
|
-
begin
|
65
|
-
redis.multi do
|
66
|
-
commands.each do |command|
|
67
|
-
redis.send(*command)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
rescue StandardError => e
|
71
|
-
PulseMeter.error "error in consumer thread: #{e}, #{e.backtrace.join("\n")}"
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def run_consumer
|
77
|
-
Thread.new do
|
78
|
-
consume_commands
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
@@ -1,48 +0,0 @@
|
|
1
|
-
require 'socket'
|
2
|
-
require 'fcntl'
|
3
|
-
|
4
|
-
module PulseMeter
|
5
|
-
module CommandAggregator
|
6
|
-
class UDP
|
7
|
-
|
8
|
-
def initialize(host, port = nil)
|
9
|
-
@servers = if host.is_a?(Array)
|
10
|
-
host
|
11
|
-
else
|
12
|
-
[[host, port]]
|
13
|
-
end
|
14
|
-
raise ArgumentError, "No servers specified" if @servers.empty?
|
15
|
-
@buffer = []
|
16
|
-
@in_multi = false
|
17
|
-
@sock = UDPSocket.new
|
18
|
-
@sock.fcntl(Fcntl::F_SETFL, @sock.fcntl(Fcntl::F_GETFL) | Fcntl::O_NONBLOCK)
|
19
|
-
end
|
20
|
-
|
21
|
-
def multi
|
22
|
-
@in_multi = true
|
23
|
-
yield
|
24
|
-
ensure
|
25
|
-
@in_multi = false
|
26
|
-
send_buffer
|
27
|
-
end
|
28
|
-
|
29
|
-
def method_missing(*args)
|
30
|
-
@buffer << args
|
31
|
-
send_buffer unless @in_multi
|
32
|
-
end
|
33
|
-
|
34
|
-
private
|
35
|
-
|
36
|
-
def send_buffer
|
37
|
-
data = @buffer.to_json
|
38
|
-
@sock.send(data, 0, *@servers.sample)
|
39
|
-
rescue StandardError => e
|
40
|
-
PulseMeter.error "error sending data: #{e}, #{e.backtrace.join("\n")}"
|
41
|
-
ensure
|
42
|
-
@buffer = []
|
43
|
-
end
|
44
|
-
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
@@ -1,24 +0,0 @@
|
|
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
|
@@ -1,46 +0,0 @@
|
|
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
|
@@ -1,87 +0,0 @@
|
|
1
|
-
require 'yaml'
|
2
|
-
|
3
|
-
module PulseMeter
|
4
|
-
module Mixins
|
5
|
-
# Mixin with dumping utilities
|
6
|
-
module Dumper
|
7
|
-
# Prefix for Redis keys with dumped sensors' metadata
|
8
|
-
DUMP_REDIS_KEY = "pulse_meter:dump"
|
9
|
-
|
10
|
-
module InstanceMethods
|
11
|
-
# Serializes object and saves it to Redis
|
12
|
-
# @param safe [Boolean] forbids dump if sensor has already been dumped
|
13
|
-
# @raise [DumpConflictError] if object class conflicts with stored object class
|
14
|
-
# @raise [DumpError] if dumping fails for any reason
|
15
|
-
def dump!(safe = true)
|
16
|
-
ensure_storability!
|
17
|
-
serialized_obj = to_yaml
|
18
|
-
if safe
|
19
|
-
unless redis.hsetnx(DUMP_REDIS_KEY, name, serialized_obj)
|
20
|
-
stored = self.class.restore(name)
|
21
|
-
unless stored.class == self.class
|
22
|
-
raise DumpConflictError, "Attempt to create sensor #{name} of class #{self.class} but it already has class #{stored.class}"
|
23
|
-
end
|
24
|
-
end
|
25
|
-
else
|
26
|
-
redis.hset(DUMP_REDIS_KEY, name, serialized_obj)
|
27
|
-
end
|
28
|
-
rescue DumpError, RestoreError => exc
|
29
|
-
raise exc
|
30
|
-
rescue StandardError => exc
|
31
|
-
raise DumpError, "object cannot be dumped: #{exc}"
|
32
|
-
end
|
33
|
-
|
34
|
-
# Ensures that object is dumpable
|
35
|
-
# @raise [DumpError] if object cannot be dumped
|
36
|
-
def ensure_storability!
|
37
|
-
raise DumpError, "#name attribute must be readable" unless self.respond_to?(:name)
|
38
|
-
raise DumpError, "#redis attribute must be available" unless self.respond_to?(:redis) && self.redis
|
39
|
-
end
|
40
|
-
|
41
|
-
# Cleans up object dump in Redis
|
42
|
-
def cleanup_dump
|
43
|
-
redis.hdel(DUMP_REDIS_KEY, self.name)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
module ClassMethods
|
48
|
-
# Restores object from Redis
|
49
|
-
# @param name [String] object name
|
50
|
-
# @return [Object]
|
51
|
-
# @raise [RestoreError] if object cannot be restored for any reason
|
52
|
-
def restore(name)
|
53
|
-
serialized_obj = PulseMeter.redis.hget(DUMP_REDIS_KEY, name)
|
54
|
-
YAML::load(serialized_obj)
|
55
|
-
rescue
|
56
|
-
raise RestoreError, "cannot restore #{name}"
|
57
|
-
end
|
58
|
-
|
59
|
-
# Lists all dumped objects' names
|
60
|
-
# @return [Array<String>]
|
61
|
-
# @raise [RestoreError] if list cannot be retrieved for any reason
|
62
|
-
def list_names
|
63
|
-
PulseMeter.redis.hkeys(DUMP_REDIS_KEY)
|
64
|
-
rescue
|
65
|
-
raise RestoreError, "cannot get data from redis"
|
66
|
-
end
|
67
|
-
|
68
|
-
# Safely restores all dumped objects
|
69
|
-
# @return [Array<Object>]
|
70
|
-
def list_objects
|
71
|
-
list_names.each_with_object([]) do |name, objects|
|
72
|
-
begin
|
73
|
-
objects << restore(name)
|
74
|
-
rescue
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def self.included(base)
|
81
|
-
base.send :include, InstanceMethods
|
82
|
-
base.send :extend, ClassMethods
|
83
|
-
end
|
84
|
-
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
@@ -1,155 +0,0 @@
|
|
1
|
-
require 'securerandom'
|
2
|
-
|
3
|
-
module PulseMeter
|
4
|
-
module Mixins
|
5
|
-
# Mixin with various useful functions
|
6
|
-
module Utils
|
7
|
-
# Tries to find a class with the name specified in the argument string
|
8
|
-
# @param const_name [String] class name
|
9
|
-
# @return [Class] if given class definde
|
10
|
-
# @return [NilClass] if given class is not defined
|
11
|
-
def constantize(const_name)
|
12
|
-
return unless const_name.respond_to?(:to_s)
|
13
|
-
const_name.to_s.split('::').reduce(Module, :const_get)
|
14
|
-
rescue NameError
|
15
|
-
nil
|
16
|
-
end
|
17
|
-
|
18
|
-
# Ensures that hash value specified by key is Array
|
19
|
-
# @param options [Hash] hash to be looked at
|
20
|
-
# @param key [Object] hash key
|
21
|
-
# @param default [Object] default value to be returned
|
22
|
-
# @raise [ArgumentError] unless value is Array
|
23
|
-
# @return [Array]
|
24
|
-
def assert_array!(options, key, default = nil)
|
25
|
-
value = options[key] || default
|
26
|
-
raise ArgumentError, "#{key} should be defined" unless value
|
27
|
-
raise ArgumentError, "#{key} should be array" unless value.is_a?(Array)
|
28
|
-
value
|
29
|
-
end
|
30
|
-
|
31
|
-
# Ensures that hash value specified by key can be converted to positive integer.
|
32
|
-
# In case it can makes in-place conversion and returns the value.
|
33
|
-
# @param options [Hash] hash to be looked at
|
34
|
-
# @param key [Object] hash key
|
35
|
-
# @param default [Object] default value to be returned
|
36
|
-
# @raise [ArgumentError] unless value is positive integer
|
37
|
-
# @return [Fixnum]
|
38
|
-
def assert_positive_integer!(options, key, default = nil)
|
39
|
-
value = options[key] || default
|
40
|
-
raise ArgumentError, "#{key} should be defined" unless value
|
41
|
-
raise ArgumentError, "#{key} should be integer" unless value.respond_to?(:to_i)
|
42
|
-
raise ArgumentError, "#{key} should be positive" unless value.to_i > 0
|
43
|
-
options[key] = value.to_i
|
44
|
-
end
|
45
|
-
|
46
|
-
# Ensures that hash value specified by key is can be converted to float
|
47
|
-
# and it is within given range.
|
48
|
-
# In case it can makes in-place conversion and returns the value.
|
49
|
-
# @param options [Hash] hash to be looked at
|
50
|
-
# @param key [Object] hash key
|
51
|
-
# @param from [Float] lower bound
|
52
|
-
# @param to [Float] upper bound
|
53
|
-
# @raise [ArgumentError] unless value is float within given range
|
54
|
-
# @return [Float]
|
55
|
-
def assert_ranged_float!(options, key, from, to)
|
56
|
-
f = options[key]
|
57
|
-
raise ArgumentError, "#{key} should be defined" unless f
|
58
|
-
raise ArgumentError, "#{key} should be float" unless f.respond_to?(:to_f)
|
59
|
-
f = f.to_f
|
60
|
-
raise ArgumentError, "#{key} should be between #{from} and #{to}" unless f >= from && f <= to
|
61
|
-
options[key] = f
|
62
|
-
end
|
63
|
-
|
64
|
-
# Generates uniq random string
|
65
|
-
# @return [String]
|
66
|
-
def uniqid
|
67
|
-
SecureRandom.hex(32)
|
68
|
-
end
|
69
|
-
|
70
|
-
# Capitalizes the first letter of each word in string
|
71
|
-
# @param str [String]
|
72
|
-
# @return [String]
|
73
|
-
# @raise [ArgumentError] unless passed value responds to to_s
|
74
|
-
def titleize(str)
|
75
|
-
raise ArgumentError unless str.respond_to?(:to_s)
|
76
|
-
str.to_s.split(/[\s_]+/).map(&:capitalize).join(' ')
|
77
|
-
end
|
78
|
-
|
79
|
-
# Converts string from snake_case to CamelCase
|
80
|
-
# @param str [String] string to be camelized
|
81
|
-
# @param first_letter_upper [TrueClass, FalseClass] says if the first letter must be uppercased
|
82
|
-
# @return [String]
|
83
|
-
# @raise [ArgumentError] unless passed value responds to to_s
|
84
|
-
def camelize(str, first_letter_upper = false)
|
85
|
-
raise ArgumentError unless str.respond_to?(:to_s)
|
86
|
-
terms = str.to_s.split(/_/)
|
87
|
-
first = terms.shift
|
88
|
-
(first_letter_upper ? first.capitalize : first.downcase) + terms.map(&:capitalize).join
|
89
|
-
end
|
90
|
-
|
91
|
-
# Converts string from CamelCase to snake_case
|
92
|
-
# @param str [String] string to be underscore
|
93
|
-
# @return [String]
|
94
|
-
# @raise [ArgumentError] unless passed value responds to to_s
|
95
|
-
def underscore(str)
|
96
|
-
raise ArgumentError unless str.respond_to?(:to_s)
|
97
|
-
str.to_s.gsub(/::/, '/').
|
98
|
-
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
99
|
-
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
100
|
-
tr("-", "_").
|
101
|
-
downcase
|
102
|
-
end
|
103
|
-
|
104
|
-
# Converts string of the form YYYYmmddHHMMSS (considered as UTC) to Time
|
105
|
-
# @param str [String] string to be converted
|
106
|
-
# @return [Time]
|
107
|
-
# @raise [ArgumentError] unless passed value responds to to_s
|
108
|
-
def parse_time(str)
|
109
|
-
raise ArgumentError unless str.respond_to?(:to_s)
|
110
|
-
m = str.to_s.match(/\A(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})\z/)
|
111
|
-
if m
|
112
|
-
Time.gm(*m.captures.map(&:to_i))
|
113
|
-
else
|
114
|
-
raise ArgumentError, "`#{str}' is not a YYYYmmddHHMMSS time"
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
# Symbolizes hash keys
|
119
|
-
def symbolize_keys(h)
|
120
|
-
h.each_with_object({}) do |(k, v), acc|
|
121
|
-
new_k = if k.respond_to?(:to_sym)
|
122
|
-
k.to_sym
|
123
|
-
else
|
124
|
-
k
|
125
|
-
end
|
126
|
-
acc[new_k] = v
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
# Deeply capitalizes Array values or Hash keys
|
131
|
-
def camelize_keys(item)
|
132
|
-
case item
|
133
|
-
when Array
|
134
|
-
item.map{|i| camelize_keys(i)}
|
135
|
-
when Hash
|
136
|
-
item.each_with_object({}) { |(k, v), h| h[camelize(k)] = camelize_keys(v)}
|
137
|
-
else
|
138
|
-
item
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
# Yields block for each subset of given array
|
143
|
-
# @param array [Array] given array
|
144
|
-
def each_subset(array)
|
145
|
-
subsets_of(array).each {|subset| yield(subset)}
|
146
|
-
end
|
147
|
-
|
148
|
-
# Returs all array's subsets
|
149
|
-
# @param array [Array]
|
150
|
-
def subsets_of(array)
|
151
|
-
0.upto(array.length).flat_map { |n| array.combination(n).to_a }
|
152
|
-
end
|
153
|
-
end
|
154
|
-
end
|
155
|
-
end
|