takenoko 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +32 -0
- data/lib/generators/takenoko/config_generator.rb +13 -0
- data/lib/generators/takenoko/templates/takenoko.rb +4 -0
- data/lib/google_drive/google_drive.rb +63 -0
- data/lib/takenoko.rb +112 -0
- data/lib/takenoko/exporter.rb +45 -0
- data/lib/takenoko/google_client.rb +49 -0
- data/lib/takenoko/version.rb +3 -0
- data/lib/tasks/takenoko.rake +11 -0
- data/test/takenoko_test.rb +7 -0
- data/test/test_helper.rb +15 -0
- metadata +113 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6c6846bb822d84f908f35ea7e6737e87b20f5c17
|
4
|
+
data.tar.gz: 9c1533aaa9e1d993f7beb2f5ae8265f59a4fb697
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9d2627e910529f9c04a3b57477e46e4e738115a3cf8224f7c7e92151d471ac84c790265fa90a3c1e7688ea7e705fcb03ccbfd1885287d332b174c94a3be0cf6b
|
7
|
+
data.tar.gz: a700a1f350e7214fb1a1cb4d688d87ac0494531c7f50f7ee60ccfd4b77cc23cc3e4209bca8f3a8ba2f0a1186c326493c54699220d5e2d35da4d556b6985dad32
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2016 YOURNAME
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'Takenoko'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.rdoc')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
Bundler::GemHelper.install_tasks
|
21
|
+
|
22
|
+
require 'rake/testtask'
|
23
|
+
|
24
|
+
Rake::TestTask.new(:test) do |t|
|
25
|
+
t.libs << 'lib'
|
26
|
+
t.libs << 'test'
|
27
|
+
t.pattern = 'test/**/*_test.rb'
|
28
|
+
t.verbose = false
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
task default: :test
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Takenoko
|
2
|
+
module Generators
|
3
|
+
class ConfigGenerator < Rails::Generators::Base
|
4
|
+
source_root File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
|
5
|
+
|
6
|
+
desc 'takenoko_config.rb'
|
7
|
+
|
8
|
+
def copy_config_file
|
9
|
+
template 'takenoko.rb', 'config/initializers/takenoko.rb'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require "google_drive"
|
2
|
+
|
3
|
+
module GoogleDrive
|
4
|
+
class Worksheet
|
5
|
+
define_method "header" do
|
6
|
+
rows.first
|
7
|
+
end
|
8
|
+
|
9
|
+
define_method "append_row" do |offset=0|
|
10
|
+
row_num = self.num_rows + offset + 1
|
11
|
+
return GoogleDrive::Alias::Row.new(row_num, [], rows.first, self)
|
12
|
+
end
|
13
|
+
|
14
|
+
define_method "populated_rows" do
|
15
|
+
header = nil
|
16
|
+
populated = []
|
17
|
+
|
18
|
+
rows.each_with_index do |row,index|
|
19
|
+
unless header then
|
20
|
+
header = row
|
21
|
+
next
|
22
|
+
end
|
23
|
+
|
24
|
+
populated.push GoogleDrive::Alias::Row.new(index + 1, row, header, self)
|
25
|
+
end
|
26
|
+
|
27
|
+
populated
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
module GoogleDrive
|
33
|
+
module Alias
|
34
|
+
class Row
|
35
|
+
attr_reader :row_num
|
36
|
+
|
37
|
+
def initialize(row_num, row, header, ws)
|
38
|
+
@row_num = row_num
|
39
|
+
@row = row
|
40
|
+
@header = header
|
41
|
+
@ws = ws
|
42
|
+
end
|
43
|
+
|
44
|
+
def method_missing(name,value=nil)
|
45
|
+
test = name.to_s.gsub(/=$/,'')
|
46
|
+
|
47
|
+
if @header.include?(test) then
|
48
|
+
col_num = @header.find_index(test)
|
49
|
+
super unless col_num
|
50
|
+
|
51
|
+
col_num += 1
|
52
|
+
if name.match(/=$/) then
|
53
|
+
@ws[@row_num,col_num] = value
|
54
|
+
else
|
55
|
+
return @ws[@row_num,col_num]
|
56
|
+
end
|
57
|
+
else
|
58
|
+
super
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/takenoko.rb
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'rails'
|
2
|
+
require 'google_drive'
|
3
|
+
require 'google_drive/google_drive'
|
4
|
+
|
5
|
+
module Takenoko
|
6
|
+
extend self
|
7
|
+
mattr_accessor :google_cridential_file
|
8
|
+
@@google_cridential_file = nil
|
9
|
+
|
10
|
+
mattr_accessor :mapping_file
|
11
|
+
@@mapping_file = false
|
12
|
+
|
13
|
+
@@google_client = nil
|
14
|
+
@@mapping_config = nil
|
15
|
+
|
16
|
+
mattr_accessor :file_extension
|
17
|
+
@@file_extension = :csv
|
18
|
+
SUPPORTED_FILE_EXT = [:csv,:yaml,:json]
|
19
|
+
|
20
|
+
mattr_accessor :export_file_location
|
21
|
+
@@export_file_location = "db/spreadsheet"
|
22
|
+
|
23
|
+
mattr_accessor :truncate_all_data
|
24
|
+
@@truncate_all_data = false
|
25
|
+
|
26
|
+
mattr_accessor :allow_overwrite
|
27
|
+
@@allow_overwrite = true
|
28
|
+
|
29
|
+
require 'takenoko/exporter'
|
30
|
+
require 'takenoko/google_client'
|
31
|
+
|
32
|
+
def config
|
33
|
+
yield self
|
34
|
+
end
|
35
|
+
|
36
|
+
def import
|
37
|
+
check_config
|
38
|
+
end
|
39
|
+
|
40
|
+
def google_client
|
41
|
+
@@google_client ||= GoogleClient.new(@@google_cridential_file)
|
42
|
+
return @@google_client
|
43
|
+
end
|
44
|
+
|
45
|
+
def check_config
|
46
|
+
raise "google_cridential_file setting cannot be nil" unless @@google_cridential_file
|
47
|
+
raise "file not found:#{@@google_cridential_file}" unless ::File.exist?(@@google_cridential_file)
|
48
|
+
raise "mapping_file cannot be nil" unless @@mapping_file
|
49
|
+
raise "file not found:#{@@mapping_file}" unless ::File.exist?(@@mapping_file)
|
50
|
+
return true
|
51
|
+
end
|
52
|
+
|
53
|
+
def mapping_config
|
54
|
+
return @@mapping_config if @@mapping_config
|
55
|
+
conf = YAML.load_file(@@mapping_file).with_indifferent_access
|
56
|
+
raise "tables not exists" if conf[:tables].blank?
|
57
|
+
conf[:tables].each do |t, v|
|
58
|
+
table = conf[:tables][t]
|
59
|
+
raise "Table config cannot be nil" unless table
|
60
|
+
[:sheet_id, :worksheet_id, :columns_mapping].each do |f|
|
61
|
+
raise "#{f} cannot be blank" if table[f].blank?
|
62
|
+
end
|
63
|
+
table[:find_column] = table[:find_column] || :id
|
64
|
+
table_name = table[:table_name] = t if table[:table_name].blank?
|
65
|
+
table[:class_name] = table[:class_name] || (table_name && table_name.singularize.camelize) || table[:table_name].singularize.camelize
|
66
|
+
unless table[:columns_mapping].key?(table[:find_column])
|
67
|
+
if(table[:find_column] == :id)
|
68
|
+
table[:columns_mapping] = {id: nil}.merge!(table[:columns_mapping])
|
69
|
+
else
|
70
|
+
table[:columns_mapping][table[:find_column]] = nil
|
71
|
+
end
|
72
|
+
end
|
73
|
+
table[:columns_mapping].each do |s_col,db_col|
|
74
|
+
table[:columns_mapping][s_col] = s_col unless db_col
|
75
|
+
end
|
76
|
+
|
77
|
+
table[:header] = table[:columns_mapping].keys
|
78
|
+
[:allow_overwrite,:truncate_all_data, :file_extension, :export_file_location].each do |f|
|
79
|
+
table[f] = class_variable_get("@@" + f.to_s) unless table.key?(f)
|
80
|
+
end
|
81
|
+
|
82
|
+
raise "Not support file extension: #{table[:file_extension]}" unless SUPPORTED_FILE_EXT.include?(table[:file_extension])
|
83
|
+
end
|
84
|
+
@@mapping_config = conf
|
85
|
+
end
|
86
|
+
|
87
|
+
def table_config(table_name)
|
88
|
+
raise "#{table_name} config not exists" unless conf = mapping_config[:tables][table_name]
|
89
|
+
return conf
|
90
|
+
end
|
91
|
+
|
92
|
+
(SUPPORTED_FILE_EXT.clone << :db).each do |output|
|
93
|
+
define_method "table_to_#{output}" do | table_name |
|
94
|
+
data = google_client.get_table(table_name)
|
95
|
+
Exporter.public_send("table_to_#{output}",data)
|
96
|
+
end
|
97
|
+
|
98
|
+
define_method "all_to_#{output}" do
|
99
|
+
mapping_config[:tables].each do |table,conf|
|
100
|
+
Takenoko.public_send("table_to_#{output}",table)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
class Railtie < Rails::Railtie
|
106
|
+
railtie_name :takenoko
|
107
|
+
|
108
|
+
rake_tasks do
|
109
|
+
load "tasks/takenoko.rake"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require "takenoko"
|
2
|
+
require "csv"
|
3
|
+
module Takenoko
|
4
|
+
module Exporter
|
5
|
+
extend self
|
6
|
+
def table_to_db(table)
|
7
|
+
tb_class = Object.const_get("::"+table[:class_name])
|
8
|
+
raise "Class not found:#{table[:class_name]}" unless tb_class <= ActiveRecord::Base
|
9
|
+
tb_class.destroy_all if table[:truncate_all_data]
|
10
|
+
table[:rows].each do |r|
|
11
|
+
if db_r = tb_class.find_by(table[:find_column] => r[table[:find_column]])
|
12
|
+
db_r.update(r) if table[:allow_overwrite]
|
13
|
+
else
|
14
|
+
tb_class.new(r).save!
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
SUPPORTED_FILE_EXT.each do |fx|
|
20
|
+
define_method "table_to_#{fx}" do |table|
|
21
|
+
dir = table[:export_file_location]
|
22
|
+
FileUtils.mkdir(dir) unless File.directory?(dir)
|
23
|
+
File.open("#{dir}/#{table[:table_name]}.#{fx}","w") do |f|
|
24
|
+
f.write public_send("convert_to_#{fx}",table)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def convert_to_csv(table)
|
30
|
+
CSV.generate do |csv|
|
31
|
+
csv << table[:header]
|
32
|
+
table[:rows].each do |row|
|
33
|
+
csv << table[:header].map {|col| row[col]}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
[:yaml,:json].each do |output|
|
39
|
+
define_method "convert_to_#{output}" do |table|
|
40
|
+
table[:rows].public_send("to_#{output}")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Takenoko
|
2
|
+
class GoogleClient
|
3
|
+
def initialize(cridential_file)
|
4
|
+
@cridential = JSON.parse(File.read(cridential_file)).with_indifferent_access
|
5
|
+
end
|
6
|
+
|
7
|
+
def get_table(table_name)
|
8
|
+
table = Takenoko.table_config(table_name)
|
9
|
+
raise "GoogleDrive: Sheet not found" unless sheet = session.spreadsheet_by_key(table['sheet_id'])
|
10
|
+
raise "GoogleDrive: Worksheet not found: worksheet_id #{table['worksheet_id']}" unless worksheet = sheet.worksheet_by_gid(table['worksheet_id'])
|
11
|
+
header = worksheet.header.select {|h| table[:columns_mapping].keys.include?(h)}
|
12
|
+
rows = worksheet.populated_rows.map do |r|
|
13
|
+
hash = HashWithIndifferentAccess.new
|
14
|
+
table['columns_mapping'].each do |key,val|
|
15
|
+
begin
|
16
|
+
hash[key] = r.public_send(val)
|
17
|
+
rescue Exception => e
|
18
|
+
if key == 'id'
|
19
|
+
hash[key] = r.row_num - 1
|
20
|
+
else
|
21
|
+
hash[key] = nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
hash
|
26
|
+
end
|
27
|
+
table[:rows] = rows
|
28
|
+
return table
|
29
|
+
end
|
30
|
+
|
31
|
+
def session
|
32
|
+
key = OpenSSL::PKey::RSA.new(@cridential['private_key'])
|
33
|
+
auth = Signet::OAuth2::Client.new(
|
34
|
+
token_credential_uri: @cridential['token_uri'],
|
35
|
+
audience: @cridential['token_uri'],
|
36
|
+
scope: %w(
|
37
|
+
https://www.googleapis.com/auth/drive
|
38
|
+
https://spreadsheets.google.com/feeds/
|
39
|
+
),
|
40
|
+
issuer: @cridential['client_email'],
|
41
|
+
signing_key: key
|
42
|
+
)
|
43
|
+
|
44
|
+
auth.fetch_access_token!
|
45
|
+
session = GoogleDrive.login_with_oauth(auth.access_token)
|
46
|
+
return session
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
namespace :takenoko do
|
2
|
+
(Takenoko::SUPPORTED_FILE_EXT.clone << :db ).each do |output|
|
3
|
+
task "all_to_#{output}".to_sym => :environment do
|
4
|
+
Takenoko.public_send("all_to_#{output}")
|
5
|
+
end
|
6
|
+
|
7
|
+
task "table_to_#{output}".to_sym, [:table] => :environment do |t, args|
|
8
|
+
Takenoko.public_send("table_to_#{output}",args[:table])
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# Configure Rails Environment
|
2
|
+
ENV["RAILS_ENV"] = "test"
|
3
|
+
|
4
|
+
require File.expand_path("../dummy/config/environment.rb", __FILE__)
|
5
|
+
require "rails/test_help"
|
6
|
+
|
7
|
+
Rails.backtrace_cleaner.remove_silencers!
|
8
|
+
|
9
|
+
# Load support files
|
10
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
11
|
+
|
12
|
+
# Load fixtures from the engine
|
13
|
+
if ActiveSupport::TestCase.method_defined?(:fixture_path=)
|
14
|
+
ActiveSupport::TestCase.fixture_path = File.expand_path("../fixtures", __FILE__)
|
15
|
+
end
|
metadata
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: takenoko
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- KhiemNS
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-09-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 4.0.13
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 4.0.13
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: google-api-client
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.7.1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.7.1
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: google_drive
|
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: sqlite3
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: Import data from google spreadsheet to database or files
|
70
|
+
email:
|
71
|
+
- khiemns54@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- MIT-LICENSE
|
77
|
+
- Rakefile
|
78
|
+
- lib/generators/takenoko/config_generator.rb
|
79
|
+
- lib/generators/takenoko/templates/takenoko.rb
|
80
|
+
- lib/google_drive/google_drive.rb
|
81
|
+
- lib/takenoko.rb
|
82
|
+
- lib/takenoko/exporter.rb
|
83
|
+
- lib/takenoko/google_client.rb
|
84
|
+
- lib/takenoko/version.rb
|
85
|
+
- lib/tasks/takenoko.rake
|
86
|
+
- test/takenoko_test.rb
|
87
|
+
- test/test_helper.rb
|
88
|
+
homepage: https://github.com/khiemns54/takenoko
|
89
|
+
licenses: []
|
90
|
+
metadata: {}
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
requirements: []
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 2.5.1
|
108
|
+
signing_key:
|
109
|
+
specification_version: 4
|
110
|
+
summary: Import data from google spreadsheet to database or files
|
111
|
+
test_files:
|
112
|
+
- test/takenoko_test.rb
|
113
|
+
- test/test_helper.rb
|