flydata 0.0.4.4 → 0.0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +4 -1
- data/Gemfile.lock +20 -5
- data/VERSION +1 -1
- data/flydata.gemspec +21 -6
- data/lib/fly_data_model.rb +4 -0
- data/lib/flydata.rb +2 -0
- data/lib/flydata/heroku.rb +150 -0
- data/lib/flydata/heroku/configuration_methods.rb +47 -0
- data/lib/flydata/heroku/instance_methods.rb +42 -0
- data/spec/fly_data_model_spec.rb +250 -0
- data/spec/flydata/heroku_spec.rb +668 -0
- data/spec/spec_helper.rb +15 -1
- metadata +62 -8
data/Gemfile
CHANGED
@@ -5,7 +5,7 @@ gem "i18n"
|
|
5
5
|
gem "activesupport"
|
6
6
|
gem "json"
|
7
7
|
gem "highline"
|
8
|
-
gem "fluentd"
|
8
|
+
gem "fluentd", "0.10.35"
|
9
9
|
|
10
10
|
group :development do
|
11
11
|
gem "bundler"
|
@@ -15,4 +15,7 @@ group :development do
|
|
15
15
|
gem "autotest-standalone"
|
16
16
|
gem "autotest-notification"
|
17
17
|
gem "ZenTest"
|
18
|
+
gem "activemodel"
|
19
|
+
gem "activerecord"
|
20
|
+
gem "sqlite3"
|
18
21
|
end
|
data/Gemfile.lock
CHANGED
@@ -2,22 +2,32 @@ GEM
|
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
4
|
ZenTest (4.8.2)
|
5
|
+
activemodel (3.2.8)
|
6
|
+
activesupport (= 3.2.8)
|
7
|
+
builder (~> 3.0.0)
|
8
|
+
activerecord (3.2.8)
|
9
|
+
activemodel (= 3.2.8)
|
10
|
+
activesupport (= 3.2.8)
|
11
|
+
arel (~> 3.0.2)
|
12
|
+
tzinfo (~> 0.3.29)
|
5
13
|
activesupport (3.2.8)
|
6
14
|
i18n (~> 0.6)
|
7
15
|
multi_json (~> 1.0)
|
16
|
+
arel (3.0.2)
|
8
17
|
autotest (4.4.6)
|
9
18
|
ZenTest (>= 4.4.1)
|
10
19
|
autotest-notification (2.3.4)
|
11
20
|
autotest-standalone (~> 4.5)
|
12
21
|
autotest-standalone (4.5.9)
|
13
|
-
|
22
|
+
builder (3.0.4)
|
23
|
+
cool.io (1.1.1)
|
14
24
|
iobuffer (>= 1.0.0)
|
15
25
|
diff-lcs (1.1.3)
|
16
|
-
fluentd (0.10.
|
26
|
+
fluentd (0.10.35)
|
17
27
|
cool.io (~> 1.1.0)
|
18
28
|
http_parser.rb (~> 0.5.1)
|
19
29
|
json (>= 1.4.3)
|
20
|
-
msgpack (
|
30
|
+
msgpack (>= 0.4.4, < 0.6.0, != 0.5.3, != 0.5.2, != 0.5.1, != 0.5.0)
|
21
31
|
yajl-ruby (~> 1.0)
|
22
32
|
git (1.2.5)
|
23
33
|
highline (1.6.15)
|
@@ -31,7 +41,7 @@ GEM
|
|
31
41
|
rdoc
|
32
42
|
json (1.7.5)
|
33
43
|
mime-types (1.19)
|
34
|
-
msgpack (0.
|
44
|
+
msgpack (0.5.5)
|
35
45
|
multi_json (1.3.6)
|
36
46
|
rake (0.9.2.2)
|
37
47
|
rdoc (3.12)
|
@@ -46,6 +56,8 @@ GEM
|
|
46
56
|
rspec-expectations (2.11.3)
|
47
57
|
diff-lcs (~> 1.1.3)
|
48
58
|
rspec-mocks (2.11.3)
|
59
|
+
sqlite3 (1.3.7)
|
60
|
+
tzinfo (0.3.37)
|
49
61
|
yajl-ruby (1.1.0)
|
50
62
|
|
51
63
|
PLATFORMS
|
@@ -53,15 +65,18 @@ PLATFORMS
|
|
53
65
|
|
54
66
|
DEPENDENCIES
|
55
67
|
ZenTest
|
68
|
+
activemodel
|
69
|
+
activerecord
|
56
70
|
activesupport
|
57
71
|
autotest
|
58
72
|
autotest-notification
|
59
73
|
autotest-standalone
|
60
74
|
bundler
|
61
|
-
fluentd
|
75
|
+
fluentd (= 0.10.35)
|
62
76
|
highline
|
63
77
|
i18n
|
64
78
|
jeweler
|
65
79
|
json
|
66
80
|
rest-client
|
67
81
|
rspec
|
82
|
+
sqlite3
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.5.0
|
data/flydata.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "flydata"
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.5.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Koichi Fujikawa"]
|
12
|
-
s.date = "2013-
|
12
|
+
s.date = "2013-08-14"
|
13
13
|
s.description = "FlyData Command Line Interface"
|
14
14
|
s.email = "sysadmin@flydata.co"
|
15
15
|
s.executables = ["flydata"]
|
@@ -22,6 +22,7 @@ Gem::Specification.new do |s|
|
|
22
22
|
"VERSION",
|
23
23
|
"bin/flydata",
|
24
24
|
"flydata.gemspec",
|
25
|
+
"lib/fly_data_model.rb",
|
25
26
|
"lib/flydata.rb",
|
26
27
|
"lib/flydata/api/base.rb",
|
27
28
|
"lib/flydata/api/data_entry.rb",
|
@@ -42,17 +43,22 @@ Gem::Specification.new do |s|
|
|
42
43
|
"lib/flydata/cron.rb",
|
43
44
|
"lib/flydata/flydata_crontab.sh",
|
44
45
|
"lib/flydata/helpers.rb",
|
46
|
+
"lib/flydata/heroku.rb",
|
47
|
+
"lib/flydata/heroku/configuration_methods.rb",
|
48
|
+
"lib/flydata/heroku/instance_methods.rb",
|
45
49
|
"lib/flydata/log_monitor.rb",
|
46
50
|
"lib/flydata/proxy.rb",
|
51
|
+
"spec/fly_data_model_spec.rb",
|
47
52
|
"spec/flydata/api/data_entry_spec.rb",
|
48
53
|
"spec/flydata/command/sender_spec.rb",
|
54
|
+
"spec/flydata/heroku_spec.rb",
|
49
55
|
"spec/flydata_spec.rb",
|
50
56
|
"spec/spec_helper.rb"
|
51
57
|
]
|
52
58
|
s.homepage = "http://flydata.co/"
|
53
59
|
s.licenses = ["All right reserved."]
|
54
60
|
s.require_paths = ["lib"]
|
55
|
-
s.rubygems_version = "1.8.
|
61
|
+
s.rubygems_version = "1.8.25"
|
56
62
|
s.summary = "FlyData CLI"
|
57
63
|
|
58
64
|
if s.respond_to? :specification_version then
|
@@ -64,7 +70,7 @@ Gem::Specification.new do |s|
|
|
64
70
|
s.add_runtime_dependency(%q<activesupport>, [">= 0"])
|
65
71
|
s.add_runtime_dependency(%q<json>, [">= 0"])
|
66
72
|
s.add_runtime_dependency(%q<highline>, [">= 0"])
|
67
|
-
s.add_runtime_dependency(%q<fluentd>, ["
|
73
|
+
s.add_runtime_dependency(%q<fluentd>, ["= 0.10.35"])
|
68
74
|
s.add_development_dependency(%q<bundler>, [">= 0"])
|
69
75
|
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
70
76
|
s.add_development_dependency(%q<rspec>, [">= 0"])
|
@@ -72,13 +78,16 @@ Gem::Specification.new do |s|
|
|
72
78
|
s.add_development_dependency(%q<autotest-standalone>, [">= 0"])
|
73
79
|
s.add_development_dependency(%q<autotest-notification>, [">= 0"])
|
74
80
|
s.add_development_dependency(%q<ZenTest>, [">= 0"])
|
81
|
+
s.add_development_dependency(%q<activemodel>, [">= 0"])
|
82
|
+
s.add_development_dependency(%q<activerecord>, [">= 0"])
|
83
|
+
s.add_development_dependency(%q<sqlite3>, [">= 0"])
|
75
84
|
else
|
76
85
|
s.add_dependency(%q<rest-client>, [">= 0"])
|
77
86
|
s.add_dependency(%q<i18n>, [">= 0"])
|
78
87
|
s.add_dependency(%q<activesupport>, [">= 0"])
|
79
88
|
s.add_dependency(%q<json>, [">= 0"])
|
80
89
|
s.add_dependency(%q<highline>, [">= 0"])
|
81
|
-
s.add_dependency(%q<fluentd>, ["
|
90
|
+
s.add_dependency(%q<fluentd>, ["= 0.10.35"])
|
82
91
|
s.add_dependency(%q<bundler>, [">= 0"])
|
83
92
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
84
93
|
s.add_dependency(%q<rspec>, [">= 0"])
|
@@ -86,6 +95,9 @@ Gem::Specification.new do |s|
|
|
86
95
|
s.add_dependency(%q<autotest-standalone>, [">= 0"])
|
87
96
|
s.add_dependency(%q<autotest-notification>, [">= 0"])
|
88
97
|
s.add_dependency(%q<ZenTest>, [">= 0"])
|
98
|
+
s.add_dependency(%q<activemodel>, [">= 0"])
|
99
|
+
s.add_dependency(%q<activerecord>, [">= 0"])
|
100
|
+
s.add_dependency(%q<sqlite3>, [">= 0"])
|
89
101
|
end
|
90
102
|
else
|
91
103
|
s.add_dependency(%q<rest-client>, [">= 0"])
|
@@ -93,7 +105,7 @@ Gem::Specification.new do |s|
|
|
93
105
|
s.add_dependency(%q<activesupport>, [">= 0"])
|
94
106
|
s.add_dependency(%q<json>, [">= 0"])
|
95
107
|
s.add_dependency(%q<highline>, [">= 0"])
|
96
|
-
s.add_dependency(%q<fluentd>, ["
|
108
|
+
s.add_dependency(%q<fluentd>, ["= 0.10.35"])
|
97
109
|
s.add_dependency(%q<bundler>, [">= 0"])
|
98
110
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
99
111
|
s.add_dependency(%q<rspec>, [">= 0"])
|
@@ -101,6 +113,9 @@ Gem::Specification.new do |s|
|
|
101
113
|
s.add_dependency(%q<autotest-standalone>, [">= 0"])
|
102
114
|
s.add_dependency(%q<autotest-notification>, [">= 0"])
|
103
115
|
s.add_dependency(%q<ZenTest>, [">= 0"])
|
116
|
+
s.add_dependency(%q<activemodel>, [">= 0"])
|
117
|
+
s.add_dependency(%q<activerecord>, [">= 0"])
|
118
|
+
s.add_dependency(%q<sqlite3>, [">= 0"])
|
104
119
|
end
|
105
120
|
end
|
106
121
|
|
data/lib/flydata.rb
CHANGED
@@ -0,0 +1,150 @@
|
|
1
|
+
module Flydata
|
2
|
+
module Heroku
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
if defined? ActiveModel
|
7
|
+
# Reopen ActiveModel::Serialization to add flydata support
|
8
|
+
module ActiveModel::Serialization
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
include Flydata::Heroku::InstanceMethods
|
11
|
+
include Flydata::Heroku::ConfigurationMethods
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
# Puts a JSON string that represents args to $stdout
|
18
|
+
#
|
19
|
+
# @example
|
20
|
+
# send_to('table_name', { key: 'value' })
|
21
|
+
# send_to('table_name', [{ key: 'value' }, { key: 'value' ])
|
22
|
+
#
|
23
|
+
# @example
|
24
|
+
# send_to(:table_name, { key: 'value' })
|
25
|
+
# send_to(:table_name', [{ key: 'value' }, { key: 'value' ])
|
26
|
+
#
|
27
|
+
# @example
|
28
|
+
# send_to(active_record)
|
29
|
+
# send_to(active_record, active_record)
|
30
|
+
#
|
31
|
+
# @example
|
32
|
+
# send_to([user, user])
|
33
|
+
#
|
34
|
+
# @param [String, Symbol] table name
|
35
|
+
# @param [Hash] values
|
36
|
+
# @param [Array<Hash>] array of value
|
37
|
+
# @param [ActiveRecord::Base] record
|
38
|
+
# @param [ActiveModel::Serialization] model
|
39
|
+
# @param [Array<ActiveRecord::Base>] array of record
|
40
|
+
# @param [Array<ActiveModel::Serialization>] array of model
|
41
|
+
def send_to(*args)
|
42
|
+
if args[0].nil?
|
43
|
+
raise ArgumentError, 'The argument of send_to must be non-nil'
|
44
|
+
end
|
45
|
+
|
46
|
+
if args[0].respond_to?(:empty?) && args[0].empty?
|
47
|
+
raise ArgumentError, 'The 1st argument of send_to must not be empty'
|
48
|
+
end
|
49
|
+
|
50
|
+
if (args[0].kind_of?(String) || args[0].kind_of?(Symbol))
|
51
|
+
unless structured_data?(args[1])
|
52
|
+
raise ArgumentError, 'The 2nd argument of send_to must be an Array or Hash'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
obj = case args[0]
|
57
|
+
when String
|
58
|
+
structured_data_as_flydata(args[0], args[1])
|
59
|
+
when Symbol
|
60
|
+
structured_data_as_flydata(args[0].to_s, args[1])
|
61
|
+
when Array
|
62
|
+
ancestors = args[0][0].class.ancestors
|
63
|
+
if defined?(ActiveModel) && ancestors.include?(ActiveModel::Serialization)
|
64
|
+
active_models_as_flydata(args[0])
|
65
|
+
end
|
66
|
+
else
|
67
|
+
ancestors = args[0].class.ancestors
|
68
|
+
if defined?(ActiveModel) && ancestors.include?(ActiveModel::Serialization)
|
69
|
+
multiple_active_models_as_flydata(args)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
$stdout.puts(obj.to_json) if obj
|
73
|
+
end
|
74
|
+
|
75
|
+
# Formats a Time object for Redshift
|
76
|
+
#
|
77
|
+
# @param [#strftime]
|
78
|
+
# @return [String, Objct]
|
79
|
+
def format_time_for_redshift(time)
|
80
|
+
time.respond_to?(:strftime) ? time.strftime('%Y-%m-%d %H:%M:%S') : time
|
81
|
+
end
|
82
|
+
|
83
|
+
# Formats a Time object for Redshift
|
84
|
+
#
|
85
|
+
# @param [#strftime]
|
86
|
+
# @return [String, Objct]
|
87
|
+
def format_date_for_redshift(time)
|
88
|
+
time.respond_to?(:strftime) ? time.strftime('%Y-%m-%d') : time
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
# @param [String]
|
94
|
+
# @param [Hash, Array]
|
95
|
+
# @return [Hash]
|
96
|
+
def structured_data_as_flydata(table_name, values)
|
97
|
+
{ table_name => format_for_flydata(values) }
|
98
|
+
end
|
99
|
+
|
100
|
+
# @param [Object]
|
101
|
+
# @return [Object]
|
102
|
+
def format_for_flydata(obj)
|
103
|
+
case obj
|
104
|
+
when Hash
|
105
|
+
obj.each { |k, v| obj[k] = format_for_flydata(v) }
|
106
|
+
when Array
|
107
|
+
obj.map { |item| item.kind_of?(Hash) ? format_for_flydata(item) : item }
|
108
|
+
when Time
|
109
|
+
format_time_for_redshift(obj)
|
110
|
+
when DateTime
|
111
|
+
format_time_for_redshift(obj)
|
112
|
+
when Date
|
113
|
+
format_date_for_redshift(obj)
|
114
|
+
else
|
115
|
+
obj
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# @param [Object]
|
120
|
+
# @return [Boolean]
|
121
|
+
def structured_data?(value)
|
122
|
+
value.kind_of?(Array) || value.kind_of?(Hash)
|
123
|
+
end
|
124
|
+
|
125
|
+
if defined?(ActiveModel)
|
126
|
+
# @param [Array<ActiveModel::Serialization>]
|
127
|
+
# @return [Hash]
|
128
|
+
def active_models_as_flydata(models)
|
129
|
+
table_name = models[0].class.flydata_table_name
|
130
|
+
{ table_name => models.map(&:as_flydata) }
|
131
|
+
end
|
132
|
+
|
133
|
+
# @param [Array<ActiveModel::Serialization>]
|
134
|
+
# @return [Hash]
|
135
|
+
def multiple_active_models_as_flydata(models)
|
136
|
+
hash = {}
|
137
|
+
models.group_by { |record| record.class.flydata_table_name }.each do |table_name, models|
|
138
|
+
hash[table_name] = if models.size == 1
|
139
|
+
models[0].as_flydata
|
140
|
+
else
|
141
|
+
models.map(&:as_flydata)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
hash
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Flydata
|
2
|
+
module Heroku
|
3
|
+
module ConfigurationMethods
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
if respond_to?(:class_attribute)
|
8
|
+
class_attribute :_flydata_table_name
|
9
|
+
class_attribute :_flydata_attributes
|
10
|
+
else
|
11
|
+
class_inheritable_accessor :_flydata_table_name
|
12
|
+
class_inheritable_accessor :_flydata_attributes
|
13
|
+
end
|
14
|
+
self._flydata_table_name = nil
|
15
|
+
self._flydata_attributes = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
# @example
|
20
|
+
# class User < ActiveRecord::Base
|
21
|
+
# flydata_attr :id, :name
|
22
|
+
# end
|
23
|
+
def flydata_attr(*attributes)
|
24
|
+
raise "flydata_attr attributes cannot be blank" if attributes.empty?
|
25
|
+
self._flydata_attributes = attributes.map(&:to_sym)
|
26
|
+
end
|
27
|
+
|
28
|
+
# @example
|
29
|
+
# class User < ActiveRecord::Base
|
30
|
+
# flydata_table :other_table
|
31
|
+
# end
|
32
|
+
def flydata_table(table_name)
|
33
|
+
self._flydata_table_name = table_name
|
34
|
+
end
|
35
|
+
|
36
|
+
# @return [String]
|
37
|
+
def flydata_table_name
|
38
|
+
self._flydata_table_name ||= if self.ancestors.include?(ActiveRecord::Base)
|
39
|
+
self.table_name
|
40
|
+
else
|
41
|
+
self.name.tableize
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Flydata
|
2
|
+
module Heroku
|
3
|
+
module InstanceMethods
|
4
|
+
# @return [Hash]
|
5
|
+
def as_flydata
|
6
|
+
# Logic borrowed from activemodel/lib/active_model/serialization.rb
|
7
|
+
options = { :root => nil }
|
8
|
+
attribute_names = self.class._flydata_attributes || attributes.keys.sort
|
9
|
+
hash = {}
|
10
|
+
attribute_names.each do |n|
|
11
|
+
value = read_attribute_for_serialization(n)
|
12
|
+
hash[n] = case value
|
13
|
+
when Time
|
14
|
+
Flydata.format_time_for_redshift(value)
|
15
|
+
when DateTime
|
16
|
+
Flydata.format_time_for_redshift(value)
|
17
|
+
when Date
|
18
|
+
Flydata.format_date_for_redshift(value)
|
19
|
+
else
|
20
|
+
value
|
21
|
+
end
|
22
|
+
end
|
23
|
+
method_names = Array.wrap(options[:methods]).select { |n| respond_to?(n) }
|
24
|
+
method_names.each { |n| hash[n] = send(n) }
|
25
|
+
|
26
|
+
serializable_add_includes(options) do |association, records, opts|
|
27
|
+
hash[association] = if records.is_a?(Enumerable)
|
28
|
+
records.map { |a| a.serializable_hash(opts) }
|
29
|
+
else
|
30
|
+
records.serializable_hash(opts)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
hash
|
35
|
+
end
|
36
|
+
|
37
|
+
def send_to_flydata
|
38
|
+
$stdout.puts({ self.class.flydata_table_name => as_flydata }.to_json)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|