dummy_log_generator 0.0.4 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -1
- data/CHANGELOG.md +9 -0
- data/README.md +6 -8
- data/dummy_log_generator.conf +2 -1
- data/dummy_log_generator.gemspec +0 -2
- data/lib/dummy_log_generator.rb +1 -3
- data/lib/dummy_log_generator/cli.rb +17 -20
- data/lib/dummy_log_generator/dsl.rb +14 -20
- data/lib/dummy_log_generator/generator.rb +101 -68
- data/lib/dummy_log_generator/setting.rb +14 -0
- data/lib/dummy_log_generator/version.rb +1 -1
- data/lib/dummy_log_generator/worker.rb +13 -4
- data/lib/ext/hash/except.rb +15 -0
- data/lib/ext/hash/keys.rb +138 -0
- data/lib/ext/hash/slice.rb +42 -0
- metadata +6 -31
- data/lib/dummy_log_generator/formatter.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6a76a35eb0df876125713ea8afd7d3128368e73b
|
4
|
+
data.tar.gz: e97dc9abc1fff91fcb1e4c6b5b8179b9c25cf596
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 65200ca5573a8f275ee1dfd1c5869ce30d1e5840737ff55eefc5c45d90c0d9b7c2729976274e6d8a549183c6337d29c3484e2bbf9f4b1aa84e407752f9bd586a
|
7
|
+
data.tar.gz: 15921096adbdd0d1214a7a6afb0b9d29a74b5be39da3af8b4a0b01918597c671d903d044658fa98f7dfeca88289d7ad05e9efc9e007294e2392f4cf0cf2c4cab
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -27,6 +27,7 @@ Sample configuration is as follows:
|
|
27
27
|
```ruby
|
28
28
|
# dummy_log_generator.conf
|
29
29
|
configure 'sample' do
|
30
|
+
output dummy.log
|
30
31
|
rate 500
|
31
32
|
delimiter "\t"
|
32
33
|
labeled true
|
@@ -40,7 +41,7 @@ configure 'sample' do
|
|
40
41
|
end
|
41
42
|
```
|
42
43
|
|
43
|
-
Running dummy_log_generator outputs like
|
44
|
+
Running dummy_log_generator outputs to `dummy.log` like
|
44
45
|
|
45
46
|
```
|
46
47
|
id:422 time:[2013-11-19 02:34:58] level:INFO method:POST uri:/api/v1/textdata reqtime:3.9726677258569842 foobar:LFK6XV1N
|
@@ -52,6 +53,10 @@ id:424 time:[2013-11-19 02:34:58] level:WARN method:POST uri:/api/v1/textdata
|
|
52
53
|
|
53
54
|
Following parameters for configuration is available
|
54
55
|
|
56
|
+
* output
|
57
|
+
|
58
|
+
Specify a filename to output, or IO object (STDOUT, STDERR)
|
59
|
+
|
55
60
|
* rate
|
56
61
|
|
57
62
|
Specify how many messages to generate per second. Default: 500 msgs / sec
|
@@ -88,10 +93,6 @@ You can specify following data types to your `field` parameters:
|
|
88
93
|
|
89
94
|
* :string
|
90
95
|
|
91
|
-
* :format
|
92
|
-
|
93
|
-
You can specify a format of string as `%s`.
|
94
|
-
|
95
96
|
* :any
|
96
97
|
|
97
98
|
You can specify an array of strings, then the generator picks one from them randomly
|
@@ -143,9 +144,6 @@ There is a [fluent-plugin-dummydata-producer](https://github.com/tagomoris/fluen
|
|
143
144
|
## ToDO
|
144
145
|
|
145
146
|
1. write tests
|
146
|
-
2. make it slim (remove active_support, etc)
|
147
|
-
3. outputs to a file (currently, outputs to STDOUT)
|
148
|
-
4. speed up (evaluate fields at only starting up)
|
149
147
|
|
150
148
|
## Contributing
|
151
149
|
|
data/dummy_log_generator.conf
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
configure 'sample' do
|
2
|
+
# output "dummy_log_generator.log"
|
2
3
|
rate 500
|
3
4
|
delimiter "\t"
|
4
5
|
labeled true
|
5
|
-
field :id, type: :integer, countup: true
|
6
|
+
field :id, type: :integer, countup: true, format: "%04d"
|
6
7
|
field :time, type: :datetime, format: "[%Y-%m-%d %H:%M:%S]", random: false
|
7
8
|
field :level, type: :string, any: %w[DEBUG INFO WARN ERROR]
|
8
9
|
field :method, type: :string, any: %w[GET POST PUT]
|
data/dummy_log_generator.gemspec
CHANGED
@@ -20,8 +20,6 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.add_dependency "thor"
|
22
22
|
spec.add_dependency "serverengine"
|
23
|
-
spec.add_dependency "active_support"
|
24
|
-
spec.add_dependency "i18n"
|
25
23
|
|
26
24
|
spec.add_development_dependency "bundler", "~> 1.3"
|
27
25
|
spec.add_development_dependency "rake"
|
data/lib/dummy_log_generator.rb
CHANGED
@@ -1,8 +1,6 @@
|
|
1
|
-
require 'logger'
|
2
1
|
require "dummy_log_generator/version"
|
3
2
|
require "dummy_log_generator/error"
|
3
|
+
require "dummy_log_generator/setting"
|
4
4
|
require "dummy_log_generator/generator"
|
5
|
-
require "dummy_log_generator/formatter"
|
6
5
|
require "dummy_log_generator/worker"
|
7
6
|
require "dummy_log_generator/dsl"
|
8
|
-
|
@@ -1,39 +1,39 @@
|
|
1
1
|
require 'thor'
|
2
2
|
require 'dummy_log_generator'
|
3
|
-
require '
|
3
|
+
require 'ext/hash/keys'
|
4
|
+
require 'ext/hash/except'
|
4
5
|
|
5
6
|
module DummyLogGenerator
|
6
7
|
class CLI < Thor
|
7
|
-
|
8
|
+
# options for serverengine
|
9
|
+
class_option :pid_path, :aliases => ["-p"], :type => :string, :default => 'dummy_log_generator.pid'
|
8
10
|
default_command :start
|
9
11
|
|
10
12
|
def initialize(args = [], opts = [], config = {})
|
11
13
|
super(args, opts, config)
|
12
|
-
|
13
|
-
@options = @options.dup # avoid frozen
|
14
|
-
if options[:config] && File.exists?(options[:config])
|
15
|
-
dsl = instance_eval(File.read(options[:config]), options[:config])
|
16
|
-
@options[:generator] = dsl.generator
|
17
|
-
@options[:formatter] = dsl.formatter
|
18
|
-
@options[:rate] = dsl.config.rate
|
19
|
-
end
|
20
14
|
end
|
21
15
|
|
22
16
|
desc "start", "Start a dummy_log_generator"
|
23
|
-
option :
|
17
|
+
option :config, :aliases => ["-c"], :type => :string, :default => 'dummy_log_generator.conf'
|
18
|
+
# options for serverengine
|
24
19
|
option :daemonize, :aliases => ["-d"], :type => :boolean
|
25
|
-
option :
|
26
|
-
|
27
|
-
option :rate, :aliases => ["-i"], :type => :numeric
|
20
|
+
option :workers, :aliases => ["-w"], :type => :numeric
|
21
|
+
option :worker_type, :type => :string, :default => 'process'
|
28
22
|
def start
|
29
|
-
|
23
|
+
@options = @options.dup # avoid frozen
|
24
|
+
if options[:config] && File.exists?(options[:config])
|
25
|
+
dsl = instance_eval(File.read(options[:config]), options[:config])
|
26
|
+
@options[:setting] = dsl.setting
|
27
|
+
# options for serverengine
|
28
|
+
@options[:workers] ||= dsl.setting.workers
|
29
|
+
end
|
30
30
|
|
31
|
-
|
31
|
+
opts = @options.symbolize_keys.except(:config)
|
32
|
+
se = ServerEngine.create(nil, DummyLogGenerator::Worker, opts)
|
32
33
|
se.run
|
33
34
|
end
|
34
35
|
|
35
36
|
desc "stop", "Stops a dummy_log_generator"
|
36
|
-
option :pid_path, :aliases => ["-p"], :type => :string
|
37
37
|
def stop
|
38
38
|
pid = File.read(@options["pid_path"]).to_i
|
39
39
|
|
@@ -46,7 +46,6 @@ module DummyLogGenerator
|
|
46
46
|
end
|
47
47
|
|
48
48
|
desc "graceful_stop", "Gracefully stops a dummy_log_generator"
|
49
|
-
option :pid_path, :aliases => ["-p"], :type => :string
|
50
49
|
def graceful_stop
|
51
50
|
pid = File.read(@options["pid_path"]).to_i
|
52
51
|
|
@@ -59,7 +58,6 @@ module DummyLogGenerator
|
|
59
58
|
end
|
60
59
|
|
61
60
|
desc "restart", "Restarts a dummy_log_generator"
|
62
|
-
option :pid_path, :aliases => ["-p"], :type => :string
|
63
61
|
def restart
|
64
62
|
pid = File.read(@options["pid_path"]).to_i
|
65
63
|
|
@@ -72,7 +70,6 @@ module DummyLogGenerator
|
|
72
70
|
end
|
73
71
|
|
74
72
|
desc "graceful_restart", "Graceful restarts a dummy_log_generator"
|
75
|
-
option :pid_path, :aliases => ["-p"], :type => :string
|
76
73
|
def graceful_restart
|
77
74
|
pid = File.read(@options["pid_path"]).to_i
|
78
75
|
|
@@ -1,39 +1,33 @@
|
|
1
|
-
module DummyLogGenerator
|
2
|
-
class Config
|
3
|
-
attr_accessor :rate
|
4
|
-
|
5
|
-
def initiaize
|
6
|
-
@rate = 500
|
7
|
-
end
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
1
|
module DummyLogGenerator
|
12
2
|
class Dsl
|
13
|
-
attr_reader :
|
14
|
-
attr_reader :formatter
|
15
|
-
attr_reader :config
|
3
|
+
attr_reader :setting
|
16
4
|
|
17
5
|
def initialize
|
18
|
-
@
|
19
|
-
@formatter = Formatter.new
|
20
|
-
@config = Config.new
|
6
|
+
@setting = Setting.new
|
21
7
|
end
|
22
8
|
|
23
9
|
def rate(rate)
|
24
|
-
|
10
|
+
setting.rate = rate
|
11
|
+
end
|
12
|
+
|
13
|
+
def output(output)
|
14
|
+
setting.output = output
|
25
15
|
end
|
26
16
|
|
27
17
|
def field(name, opts)
|
28
|
-
|
18
|
+
setting.fields[name] = opts
|
29
19
|
end
|
30
20
|
|
31
21
|
def delimiter(delimiter)
|
32
|
-
|
22
|
+
setting.delimiter = delimiter
|
33
23
|
end
|
34
24
|
|
35
25
|
def labeled(labeled)
|
36
|
-
|
26
|
+
setting.labeled = labeled
|
27
|
+
end
|
28
|
+
|
29
|
+
def workers(workers)
|
30
|
+
setting.workers = workers
|
37
31
|
end
|
38
32
|
end
|
39
33
|
end
|
@@ -1,35 +1,45 @@
|
|
1
1
|
module DummyLogGenerator
|
2
2
|
class Generator
|
3
|
-
|
4
|
-
|
3
|
+
def initialize(setting)
|
4
|
+
prepare_format_proc(setting.labeled, setting.delimiter)
|
5
|
+
prepare_field_procs(setting.fields)
|
6
|
+
end
|
5
7
|
|
6
|
-
def
|
7
|
-
@
|
8
|
-
|
8
|
+
def prepare_format_proc(labeled, delimiter)
|
9
|
+
@format_proc =
|
10
|
+
if labeled
|
11
|
+
Proc.new {|fields| fields.map {|key, val| "#{key}:#{val}" }.join(delimiter) }
|
12
|
+
else
|
13
|
+
Proc.new {|fields| fields.values.join(delimiter) }
|
14
|
+
end
|
9
15
|
end
|
10
16
|
|
11
|
-
def
|
12
|
-
|
17
|
+
def prepare_field_procs(fields)
|
18
|
+
rand = ::DummyLogGenerator::Random.new
|
19
|
+
@field_procs = {}
|
13
20
|
fields.each do |key, opts|
|
14
21
|
opts = opts.dup
|
15
22
|
type = opts.delete(:type)
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
23
|
+
if rand.respond_to?(type)
|
24
|
+
@field_procs[key] = rand.send(type, opts)
|
25
|
+
else
|
26
|
+
raise ConfigError.new(type)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def generate(prev_data = {})
|
32
|
+
data = {}
|
33
|
+
@field_procs.each do |key, proc|
|
34
|
+
prev = prev_data[key] || -1
|
35
|
+
data[key] = proc.call(prev)
|
29
36
|
end
|
30
37
|
data
|
31
38
|
end
|
32
|
-
|
39
|
+
|
40
|
+
def format(fields)
|
41
|
+
@format_proc.call(fields)
|
42
|
+
end
|
33
43
|
end
|
34
44
|
|
35
45
|
class Random
|
@@ -38,59 +48,82 @@ module DummyLogGenerator
|
|
38
48
|
@chars = ('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a # no symbols and multi-bytes for now
|
39
49
|
end
|
40
50
|
|
41
|
-
def string(
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
51
|
+
def string(length: 8, any: nil, value: nil)
|
52
|
+
if value
|
53
|
+
string = value.to_s
|
54
|
+
Proc.new { string }
|
55
|
+
elsif any
|
56
|
+
Proc.new { self.any(any) }
|
57
|
+
else
|
58
|
+
Proc.new { Array.new(length){@chars[rand(@chars.size-1)]}.join }
|
59
|
+
end
|
50
60
|
end
|
51
61
|
|
52
|
-
def integer(format: nil, range: nil, countup: false,
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
62
|
+
def integer(format: nil, range: nil, countup: false, value: nil)
|
63
|
+
if format
|
64
|
+
if value
|
65
|
+
integer = sprintf(format, value.to_i)
|
66
|
+
Proc.new { integer }
|
67
|
+
elsif range
|
68
|
+
Proc.new { sprintf(format, self.range(range)) }
|
69
|
+
elsif countup
|
70
|
+
Proc.new {|prev| sprintf(format, prev.to_i + 1) }
|
71
|
+
else
|
72
|
+
Proc.new { sprintf(format, rand(0..2,147,483,647)) }
|
73
|
+
end
|
74
|
+
else
|
75
|
+
if value
|
76
|
+
integer = value.to_i
|
77
|
+
Proc.new { integer }
|
78
|
+
elsif range
|
79
|
+
Proc.new { self.range(range) }
|
80
|
+
elsif countup
|
81
|
+
Proc.new {|prev| prev + 1 }
|
82
|
+
else
|
83
|
+
Proc.new { rand(0..2,147,483,647) }
|
84
|
+
end
|
85
|
+
end
|
64
86
|
end
|
65
87
|
|
66
|
-
def float(format: nil, range: nil,
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
88
|
+
def float(format: nil, range: nil, value: nil)
|
89
|
+
if format
|
90
|
+
if value
|
91
|
+
float = value.to_f
|
92
|
+
Proc.new { sprintf(format, float) }
|
93
|
+
elsif range
|
94
|
+
Proc.new { sprintf(format, self.range(range)) }
|
95
|
+
else
|
96
|
+
Proc.new { r = rand(1..358); sprintf(format, r * Math.cos(r)) }
|
97
|
+
end
|
98
|
+
else
|
99
|
+
if value
|
100
|
+
float = value.to_f
|
101
|
+
Proc.new { float }
|
102
|
+
elsif range
|
103
|
+
Proc.new { self.range(range) }
|
104
|
+
else
|
105
|
+
Proc.new { r = rand(1..358); r * Math.cos(r) }
|
106
|
+
end
|
107
|
+
end
|
76
108
|
end
|
77
109
|
|
78
|
-
def datetime(format: "%Y-%m-%d %H:%M:%S.%3N", random: false,
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
110
|
+
def datetime(format: "%Y-%m-%d %H:%M:%S.%3N", random: false, value: nil)
|
111
|
+
if value
|
112
|
+
Proc.new { value.sprintf(format) }
|
113
|
+
elsif random
|
114
|
+
Proc.new {
|
115
|
+
y = rand(1970..2037);
|
116
|
+
m = rand(1..12);
|
117
|
+
d = rand(1..27);
|
118
|
+
h = rand(0..23);
|
119
|
+
min = rand(0..59);
|
120
|
+
s = rand(0..59);
|
121
|
+
usec = rand(0..999999);
|
122
|
+
Time.local(y, m, d, h, min, s, usec)
|
123
|
+
}
|
124
|
+
else
|
125
|
+
Proc.new { Time.now }
|
126
|
+
end
|
94
127
|
end
|
95
128
|
|
96
129
|
def range(range)
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module DummyLogGenerator
|
2
|
+
class Setting
|
3
|
+
attr_accessor :rate, :output, :labeled, :delimiter, :fields, :workers
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@rate = 500
|
7
|
+
@output = STDOUT
|
8
|
+
@labeled = true
|
9
|
+
@delimiter = "\t"
|
10
|
+
@fields = {}
|
11
|
+
@workers = 1
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -7,9 +7,16 @@ module DummyLogGenerator
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def reload
|
10
|
-
@
|
11
|
-
@
|
12
|
-
|
10
|
+
@generator = Generator.new(config[:setting])
|
11
|
+
@rate = config[:setting].rate
|
12
|
+
|
13
|
+
output = config[:setting].output
|
14
|
+
if output.respond_to?(:write) and output.respond_to?(:close)
|
15
|
+
@output = output
|
16
|
+
else
|
17
|
+
@output = open(output, (File::WRONLY | File::APPEND | File::CREAT))
|
18
|
+
@output.sync = true
|
19
|
+
end
|
13
20
|
end
|
14
21
|
|
15
22
|
# thanks! ref. https://github.com/tagomoris/fluent-plugin-dummydata-producer/blob/a550fd4424f71cd9227e138c3c89f600ba40a0d5/lib/fluent/plugin/in_dummydata_producer.rb#L63
|
@@ -25,7 +32,7 @@ module DummyLogGenerator
|
|
25
32
|
# ToDo: what if generation is slower than I/O?
|
26
33
|
# We may should generate data and output in parallel
|
27
34
|
prev_data = @generator.generate(prev_data)
|
28
|
-
|
35
|
+
@output.write "#{@generator.format(prev_data)}\n"
|
29
36
|
end
|
30
37
|
rate_count += batch_num
|
31
38
|
sleep 0.1
|
@@ -35,6 +42,8 @@ module DummyLogGenerator
|
|
35
42
|
sleep 0.04
|
36
43
|
end
|
37
44
|
end
|
45
|
+
ensure
|
46
|
+
@output.close
|
38
47
|
end
|
39
48
|
|
40
49
|
def stop
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Hash
|
2
|
+
# Return a hash that includes everything but the given keys. This is useful for
|
3
|
+
# limiting a set of parameters to everything but a few known toggles:
|
4
|
+
#
|
5
|
+
# @person.update(params[:person].except(:admin))
|
6
|
+
def except(*keys)
|
7
|
+
dup.except!(*keys)
|
8
|
+
end
|
9
|
+
|
10
|
+
# Replaces the hash without the given keys.
|
11
|
+
def except!(*keys)
|
12
|
+
keys.each { |key| delete(key) }
|
13
|
+
self
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
class Hash
|
2
|
+
# Return a new hash with all keys converted using the block operation.
|
3
|
+
#
|
4
|
+
# hash = { name: 'Rob', age: '28' }
|
5
|
+
#
|
6
|
+
# hash.transform_keys{ |key| key.to_s.upcase }
|
7
|
+
# # => {"NAME"=>"Rob", "AGE"=>"28"}
|
8
|
+
def transform_keys
|
9
|
+
result = {}
|
10
|
+
each_key do |key|
|
11
|
+
result[yield(key)] = self[key]
|
12
|
+
end
|
13
|
+
result
|
14
|
+
end
|
15
|
+
|
16
|
+
# Destructively convert all keys using the block operations.
|
17
|
+
# Same as transform_keys but modifies +self+.
|
18
|
+
def transform_keys!
|
19
|
+
keys.each do |key|
|
20
|
+
self[yield(key)] = delete(key)
|
21
|
+
end
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
# Return a new hash with all keys converted to strings.
|
26
|
+
#
|
27
|
+
# hash = { name: 'Rob', age: '28' }
|
28
|
+
#
|
29
|
+
# hash.stringify_keys
|
30
|
+
# # => {"name"=>"Rob", "age"=>"28"}
|
31
|
+
def stringify_keys
|
32
|
+
transform_keys{ |key| key.to_s }
|
33
|
+
end
|
34
|
+
|
35
|
+
# Destructively convert all keys to strings. Same as
|
36
|
+
# +stringify_keys+, but modifies +self+.
|
37
|
+
def stringify_keys!
|
38
|
+
transform_keys!{ |key| key.to_s }
|
39
|
+
end
|
40
|
+
|
41
|
+
# Return a new hash with all keys converted to symbols, as long as
|
42
|
+
# they respond to +to_sym+.
|
43
|
+
#
|
44
|
+
# hash = { 'name' => 'Rob', 'age' => '28' }
|
45
|
+
#
|
46
|
+
# hash.symbolize_keys
|
47
|
+
# # => {"name"=>"Rob", "age"=>"28"}
|
48
|
+
def symbolize_keys
|
49
|
+
transform_keys{ |key| key.to_sym rescue key }
|
50
|
+
end
|
51
|
+
alias_method :to_options, :symbolize_keys
|
52
|
+
|
53
|
+
# Destructively convert all keys to symbols, as long as they respond
|
54
|
+
# to +to_sym+. Same as +symbolize_keys+, but modifies +self+.
|
55
|
+
def symbolize_keys!
|
56
|
+
transform_keys!{ |key| key.to_sym rescue key }
|
57
|
+
end
|
58
|
+
alias_method :to_options!, :symbolize_keys!
|
59
|
+
|
60
|
+
# Validate all keys in a hash match <tt>*valid_keys</tt>, raising ArgumentError
|
61
|
+
# on a mismatch. Note that keys are NOT treated indifferently, meaning if you
|
62
|
+
# use strings for keys but assert symbols as keys, this will fail.
|
63
|
+
#
|
64
|
+
# { name: 'Rob', years: '28' }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key: years"
|
65
|
+
# { name: 'Rob', age: '28' }.assert_valid_keys('name', 'age') # => raises "ArgumentError: Unknown key: name"
|
66
|
+
# { name: 'Rob', age: '28' }.assert_valid_keys(:name, :age) # => passes, raises nothing
|
67
|
+
def assert_valid_keys(*valid_keys)
|
68
|
+
valid_keys.flatten!
|
69
|
+
each_key do |k|
|
70
|
+
raise ArgumentError.new("Unknown key: #{k}") unless valid_keys.include?(k)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Return a new hash with all keys converted by the block operation.
|
75
|
+
# This includes the keys from the root hash and from all
|
76
|
+
# nested hashes.
|
77
|
+
#
|
78
|
+
# hash = { person: { name: 'Rob', age: '28' } }
|
79
|
+
#
|
80
|
+
# hash.deep_transform_keys{ |key| key.to_s.upcase }
|
81
|
+
# # => {"PERSON"=>{"NAME"=>"Rob", "AGE"=>"28"}}
|
82
|
+
def deep_transform_keys(&block)
|
83
|
+
result = {}
|
84
|
+
each do |key, value|
|
85
|
+
result[yield(key)] = value.is_a?(Hash) ? value.deep_transform_keys(&block) : value
|
86
|
+
end
|
87
|
+
result
|
88
|
+
end
|
89
|
+
|
90
|
+
# Destructively convert all keys by using the block operation.
|
91
|
+
# This includes the keys from the root hash and from all
|
92
|
+
# nested hashes.
|
93
|
+
def deep_transform_keys!(&block)
|
94
|
+
keys.each do |key|
|
95
|
+
value = delete(key)
|
96
|
+
self[yield(key)] = value.is_a?(Hash) ? value.deep_transform_keys!(&block) : value
|
97
|
+
end
|
98
|
+
self
|
99
|
+
end
|
100
|
+
|
101
|
+
# Return a new hash with all keys converted to strings.
|
102
|
+
# This includes the keys from the root hash and from all
|
103
|
+
# nested hashes.
|
104
|
+
#
|
105
|
+
# hash = { person: { name: 'Rob', age: '28' } }
|
106
|
+
#
|
107
|
+
# hash.deep_stringify_keys
|
108
|
+
# # => {"person"=>{"name"=>"Rob", "age"=>"28"}}
|
109
|
+
def deep_stringify_keys
|
110
|
+
deep_transform_keys{ |key| key.to_s }
|
111
|
+
end
|
112
|
+
|
113
|
+
# Destructively convert all keys to strings.
|
114
|
+
# This includes the keys from the root hash and from all
|
115
|
+
# nested hashes.
|
116
|
+
def deep_stringify_keys!
|
117
|
+
deep_transform_keys!{ |key| key.to_s }
|
118
|
+
end
|
119
|
+
|
120
|
+
# Return a new hash with all keys converted to symbols, as long as
|
121
|
+
# they respond to +to_sym+. This includes the keys from the root hash
|
122
|
+
# and from all nested hashes.
|
123
|
+
#
|
124
|
+
# hash = { 'person' => { 'name' => 'Rob', 'age' => '28' } }
|
125
|
+
#
|
126
|
+
# hash.deep_symbolize_keys
|
127
|
+
# # => {:person=>{:name=>"Rob", :age=>"28"}}
|
128
|
+
def deep_symbolize_keys
|
129
|
+
deep_transform_keys{ |key| key.to_sym rescue key }
|
130
|
+
end
|
131
|
+
|
132
|
+
# Destructively convert all keys to symbols, as long as they respond
|
133
|
+
# to +to_sym+. This includes the keys from the root hash and from all
|
134
|
+
# nested hashes.
|
135
|
+
def deep_symbolize_keys!
|
136
|
+
deep_transform_keys!{ |key| key.to_sym rescue key }
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class Hash
|
2
|
+
# Slice a hash to include only the given keys. This is useful for
|
3
|
+
# limiting an options hash to valid keys before passing to a method:
|
4
|
+
#
|
5
|
+
# def search(criteria = {})
|
6
|
+
# criteria.assert_valid_keys(:mass, :velocity, :time)
|
7
|
+
# end
|
8
|
+
#
|
9
|
+
# search(options.slice(:mass, :velocity, :time))
|
10
|
+
#
|
11
|
+
# If you have an array of keys you want to limit to, you should splat them:
|
12
|
+
#
|
13
|
+
# valid_keys = [:mass, :velocity, :time]
|
14
|
+
# search(options.slice(*valid_keys))
|
15
|
+
def slice(*keys)
|
16
|
+
keys.map! { |key| convert_key(key) } if respond_to?(:convert_key, true)
|
17
|
+
keys.each_with_object(self.class.new) { |k, hash| hash[k] = self[k] if has_key?(k) }
|
18
|
+
end
|
19
|
+
|
20
|
+
# Replaces the hash with only the given keys.
|
21
|
+
# Returns a hash containing the removed key/value pairs.
|
22
|
+
#
|
23
|
+
# { a: 1, b: 2, c: 3, d: 4 }.slice!(:a, :b)
|
24
|
+
# # => {:c=>3, :d=>4}
|
25
|
+
def slice!(*keys)
|
26
|
+
keys.map! { |key| convert_key(key) } if respond_to?(:convert_key, true)
|
27
|
+
omit = slice(*self.keys - keys)
|
28
|
+
hash = slice(*keys)
|
29
|
+
hash.default = default
|
30
|
+
hash.default_proc = default_proc if default_proc
|
31
|
+
replace(hash)
|
32
|
+
omit
|
33
|
+
end
|
34
|
+
|
35
|
+
# Removes and returns the key/value pairs matching the given keys.
|
36
|
+
#
|
37
|
+
# { a: 1, b: 2, c: 3, d: 4 }.extract!(:a, :b) # => {:a=>1, :b=>2}
|
38
|
+
# { a: 1, b: 2 }.extract!(:a, :x) # => {:a=>1}
|
39
|
+
def extract!(*keys)
|
40
|
+
keys.each_with_object(self.class.new) { |key, result| result[key] = delete(key) if has_key?(key) }
|
41
|
+
end
|
42
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dummy_log_generator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- sonots
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-11-
|
11
|
+
date: 2013-11-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -38,34 +38,6 @@ dependencies:
|
|
38
38
|
- - '>='
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: active_support
|
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: i18n
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - '>='
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
|
-
type: :runtime
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - '>='
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
69
41
|
- !ruby/object:Gem::Dependency
|
70
42
|
name: bundler
|
71
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -158,10 +130,13 @@ files:
|
|
158
130
|
- lib/dummy_log_generator/cli.rb
|
159
131
|
- lib/dummy_log_generator/dsl.rb
|
160
132
|
- lib/dummy_log_generator/error.rb
|
161
|
-
- lib/dummy_log_generator/formatter.rb
|
162
133
|
- lib/dummy_log_generator/generator.rb
|
134
|
+
- lib/dummy_log_generator/setting.rb
|
163
135
|
- lib/dummy_log_generator/version.rb
|
164
136
|
- lib/dummy_log_generator/worker.rb
|
137
|
+
- lib/ext/hash/except.rb
|
138
|
+
- lib/ext/hash/keys.rb
|
139
|
+
- lib/ext/hash/slice.rb
|
165
140
|
homepage: https://github.com/sonots/dummy_log_generator
|
166
141
|
licenses:
|
167
142
|
- MIT
|
@@ -1,18 +0,0 @@
|
|
1
|
-
module DummyLogGenerator
|
2
|
-
class Formatter
|
3
|
-
attr_accessor :labeled, :delimiter
|
4
|
-
|
5
|
-
def initialize
|
6
|
-
@labeled = true
|
7
|
-
@delimiter = "\t"
|
8
|
-
end
|
9
|
-
|
10
|
-
def format(fields)
|
11
|
-
if labeled
|
12
|
-
fields.map {|key, val| "#{key}:#{val}" }.join(delimiter)
|
13
|
-
else
|
14
|
-
fields.values.join(delimiter)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|