flydata 0.0.4.4 → 0.0.5.0
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.
- 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
|