mode 0.0.18 → 0.0.19

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ba4667740570363fcc09c91a5ab6306678f54731
4
- data.tar.gz: 9d1e27811b305bd7f81da09fdb0794583852744e
3
+ metadata.gz: f79719aeee1b231678a845b20822da9d23adfa88
4
+ data.tar.gz: 923422856ba88ce2e6b4a0c0036848982f1615d5
5
5
  SHA512:
6
- metadata.gz: 6a820c70b52f95e12f71c7a50a37975038986ebe83cdd7769c778f6ee6d60159187d6d42ad78005ef01f045133217203540e63f99edcb7e4fcc28c913b854f76
7
- data.tar.gz: dfd181018bf5f35d3b5c5f1f41dc8713daa8b1291f4fcd75fc2609e41796b38fa4dfd2e8c208dbaea1c731e9430fa106595816e629a4116170058a0b9408ca14
6
+ metadata.gz: 4f26aa68bd1871d9d9483dd9a48cdd3cdc064f5cfa8e9bb8cd46c5d3eb63ac09fa5933f2bc3680c07fbd20b4817f3819ca10b771fe55d0aab7f74238f5ad3374
7
+ data.tar.gz: 8a2a26041037d95ba48d6ab6f9077d5960364f7f21aa7c2a6e6f7f57d03134f1bfe1f8f2ab5c94f7e72bbd7b954568f64d214f35e304e4bbd73aeffa9d763dbc
data/.gitignore CHANGED
@@ -11,8 +11,6 @@ coverage
11
11
  lib/bundler/man
12
12
  pkg
13
13
  rdoc
14
- spec/reports
15
- test/tmp
16
- test/version_tmp
17
14
  tmp
18
- data_packages/*
15
+ mode-ruby.jar
16
+ media/*
data/bin/mode CHANGED
@@ -5,4 +5,6 @@ require 'rubygems'
5
5
  require 'mode'
6
6
  require 'mode/cli'
7
7
 
8
+ # Set the default task
9
+
8
10
  Mode::CLI::Base.start(ARGV)
@@ -21,4 +21,4 @@ trap("TERM") do
21
21
  daemon.stop
22
22
  end
23
23
 
24
- daemon.start
24
+ daemon.start
@@ -1,7 +1,5 @@
1
1
  require 'thor'
2
2
  require 'faraday'
3
- require 'data_kit'
4
- require 'data_package'
5
3
 
6
4
  require 'mode/version'
7
5
 
@@ -58,7 +56,4 @@ require 'mode/connector/daemonizer'
58
56
  require 'mode/commands/helpers'
59
57
 
60
58
  require 'mode/commands/login'
61
- require 'mode/commands/import'
62
59
  require 'mode/commands/connect'
63
- require 'mode/commands/analyze_field'
64
- require 'mode/commands/analyze_schema'
@@ -1,7 +1,3 @@
1
- require 'mode/cli/helpers'
2
-
3
1
  require 'mode/cli/base'
4
2
  require 'mode/cli/login'
5
- require 'mode/cli/analyze'
6
- require 'mode/cli/import'
7
- require 'mode/cli/connect'
3
+ require 'mode/cli/connect'
@@ -1,3 +1,5 @@
1
+ require 'sinatra/base'
2
+
1
3
  module Mode
2
4
  module CLI
3
5
  class Base < Thor
@@ -12,9 +14,10 @@ module Mode
12
14
  say "Mode CLI Version #{Mode::VERSION}"
13
15
  end
14
16
 
15
- private
16
-
17
- include Mode::CLI::Helpers
17
+ desc "serve", "Daemonize admin server"
18
+ def serve
19
+ Mode::Connector::Daemon.new(:max_jobs => 4).start
20
+ end
18
21
  end
19
22
  end
20
- end
23
+ end
@@ -24,4 +24,6 @@ module Mode
24
24
  end
25
25
  end
26
26
  end
27
- end
27
+ end
28
+
29
+ # Swap all these out into their own commands start, stop, restart, etc.
@@ -46,7 +46,7 @@ module Mode
46
46
  def configure_credentials
47
47
  say "Enter your Mode credentials:"
48
48
  username = ask "Username:"
49
- password = ask "Password:", :echo => false
49
+ password = ask "Password:"#, :echo => false
50
50
 
51
51
  # go ahead and configure API
52
52
  configure_api(username, password)
@@ -153,7 +153,7 @@ module Mode
153
153
  end
154
154
  end
155
155
 
156
- def update_configuration(environment, username, access_token)
156
+ def update_configuration(environment, username, access_token)
157
157
  config = find_or_create_config
158
158
 
159
159
  config.username = username
@@ -179,4 +179,4 @@ module Mode
179
179
  end
180
180
  end
181
181
  end
182
- end
182
+ end
@@ -37,9 +37,14 @@ module Mode
37
37
 
38
38
  def start
39
39
  abort "Mode connector already running" if alive?
40
- abort "Insufficient permissions to start Mode connector" unless File.executable?(executable)
41
40
 
42
- if pid = Spoon.spawnp(executable, *args.collect(&:to_s))
41
+ if RUBY_PLATFORM == 'java' && jar_file
42
+ pid = Spoon.spawnp("java", "-jar", jar_file, "serve")
43
+ else
44
+ pid = Spoon.spawnp(executable, *args.collect(&:to_s))
45
+ end
46
+
47
+ if pid
43
48
  create_pid(pid)
44
49
  STDOUT.puts "Mode connector running with pid #{pid}"
45
50
  else
@@ -91,6 +96,10 @@ module Mode
91
96
  exit!
92
97
  end
93
98
 
99
+ def jar_file
100
+ File.dirname(__FILE__).match(/\/([\w\d\-\.]+)!/).to_a.last
101
+ end
102
+
94
103
  def default_pid_file
95
104
  File.join(Mode::Config.default_dir, 'connect.pid')
96
105
  end
@@ -104,4 +113,4 @@ module Mode
104
113
  end
105
114
  end
106
115
  end
107
- end
116
+ end
@@ -25,14 +25,14 @@ module Mode
25
25
 
26
26
  scheduler.interval('15m') { register }
27
27
  scheduler.interval('5s') { process_messages }
28
- scheduler.join
28
+ scheduler.join # don't join if we're running from inside sinatra
29
29
  end
30
30
 
31
31
  def stop!
32
32
  stopper = Thread.new {
33
33
  scheduler.stop # Stop polling
34
34
  }
35
-
35
+
36
36
  stopper.join # wait for jobs to finish
37
37
  end
38
38
 
@@ -73,4 +73,4 @@ module Mode
73
73
  end
74
74
  end
75
75
  end
76
- end
76
+ end
@@ -1,3 +1,3 @@
1
1
  module Mode
2
- VERSION = "0.0.18"
2
+ VERSION = "0.0.19"
3
3
  end
@@ -22,14 +22,14 @@ Gem::Specification.new do |spec|
22
22
  spec.add_runtime_dependency "thor"
23
23
  spec.add_runtime_dependency "terminal-table"
24
24
 
25
- # Data Packaging (In Development)
26
- spec.add_runtime_dependency "data_kit"
27
- spec.add_runtime_dependency "data_package"
25
+ # Web UI
26
+ spec.add_runtime_dependency "sinatra"
28
27
 
29
28
  # HTTP
30
- spec.add_runtime_dependency "faraday"
31
- spec.add_runtime_dependency "faraday_middleware"
32
29
  spec.add_runtime_dependency "uri_template"
30
+ spec.add_runtime_dependency "faraday", '~> 0.8.9'
31
+ spec.add_runtime_dependency "multipart-post", '~> 1.2.0'
32
+ spec.add_runtime_dependency "faraday_middleware", '~> 0.9.0'
33
33
 
34
34
  # Connectivity
35
35
  spec.add_runtime_dependency "sequel"
@@ -37,7 +37,7 @@ Gem::Specification.new do |spec|
37
37
  # Concurrency & Processes
38
38
  spec.add_runtime_dependency "spoon"
39
39
  spec.add_runtime_dependency "rufus-scheduler"
40
-
40
+
41
41
  # Web Management
42
42
  # spec.add_runtime_dependency "launchy"
43
43
 
@@ -49,4 +49,4 @@ Gem::Specification.new do |spec|
49
49
  spec.add_development_dependency "simplecov"
50
50
  spec.add_development_dependency "pry"
51
51
  spec.add_development_dependency "warbler"
52
- end
52
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mode
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.18
4
+ version: 0.0.19
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mode Analytics
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-03-24 00:00:00.000000000 Z
11
+ date: 2014-03-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -39,7 +39,7 @@ dependencies:
39
39
  prerelease: false
40
40
  type: :runtime
41
41
  - !ruby/object:Gem::Dependency
42
- name: data_kit
42
+ name: sinatra
43
43
  version_requirements: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - '>='
@@ -53,7 +53,7 @@ dependencies:
53
53
  prerelease: false
54
54
  type: :runtime
55
55
  - !ruby/object:Gem::Dependency
56
- name: data_package
56
+ name: uri_template
57
57
  version_requirements: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - '>='
@@ -70,42 +70,42 @@ dependencies:
70
70
  name: faraday
71
71
  version_requirements: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - '>='
73
+ - - ~>
74
74
  - !ruby/object:Gem::Version
75
- version: '0'
75
+ version: 0.8.9
76
76
  requirement: !ruby/object:Gem::Requirement
77
77
  requirements:
78
- - - '>='
78
+ - - ~>
79
79
  - !ruby/object:Gem::Version
80
- version: '0'
80
+ version: 0.8.9
81
81
  prerelease: false
82
82
  type: :runtime
83
83
  - !ruby/object:Gem::Dependency
84
- name: faraday_middleware
84
+ name: multipart-post
85
85
  version_requirements: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - '>='
87
+ - - ~>
88
88
  - !ruby/object:Gem::Version
89
- version: '0'
89
+ version: 1.2.0
90
90
  requirement: !ruby/object:Gem::Requirement
91
91
  requirements:
92
- - - '>='
92
+ - - ~>
93
93
  - !ruby/object:Gem::Version
94
- version: '0'
94
+ version: 1.2.0
95
95
  prerelease: false
96
96
  type: :runtime
97
97
  - !ruby/object:Gem::Dependency
98
- name: uri_template
98
+ name: faraday_middleware
99
99
  version_requirements: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - '>='
101
+ - - ~>
102
102
  - !ruby/object:Gem::Version
103
- version: '0'
103
+ version: 0.9.0
104
104
  requirement: !ruby/object:Gem::Requirement
105
105
  requirements:
106
- - - '>='
106
+ - - ~>
107
107
  - !ruby/object:Gem::Version
108
- version: '0'
108
+ version: 0.9.0
109
109
  prerelease: false
110
110
  type: :runtime
111
111
  - !ruby/object:Gem::Dependency
@@ -274,18 +274,11 @@ files:
274
274
  - lib/mode/api/resource.rb
275
275
  - lib/mode/auth/access_token.rb
276
276
  - lib/mode/cli.rb
277
- - lib/mode/cli/analyze.rb
278
277
  - lib/mode/cli/base.rb
279
278
  - lib/mode/cli/connect.rb
280
- - lib/mode/cli/helpers.rb
281
- - lib/mode/cli/import.rb
282
279
  - lib/mode/cli/login.rb
283
- - lib/mode/cli/package.rb
284
- - lib/mode/commands/analyze_field.rb
285
- - lib/mode/commands/analyze_schema.rb
286
280
  - lib/mode/commands/connect.rb
287
281
  - lib/mode/commands/helpers.rb
288
- - lib/mode/commands/import.rb
289
282
  - lib/mode/commands/login.rb
290
283
  - lib/mode/config.rb
291
284
  - lib/mode/connector/commands/select_report_run_dataset.rb
@@ -305,17 +298,15 @@ files:
305
298
  - lib/mode/logger.rb
306
299
  - lib/mode/version.rb
307
300
  - mode.gemspec
301
+ - releases/mode-ruby-0.0.18.jar
308
302
  - script/console.rb
309
303
  - spec/api/form_spec.rb
310
304
  - spec/api/link_spec.rb
311
305
  - spec/api/request_spec.rb
312
306
  - spec/api/resource_spec.rb
313
307
  - spec/auth/access_token_spec.rb
314
- - spec/commands/analyze_field_spec.rb
315
- - spec/commands/analyze_schema_spec.rb
316
308
  - spec/commands/connect_spec.rb
317
309
  - spec/commands/helpers_spec.rb
318
- - spec/commands/import_spec.rb
319
310
  - spec/commands/login_spec.rb
320
311
  - spec/config_spec.rb
321
312
  - spec/connector/commands/select_report_run_dataset_spec.rb
@@ -372,11 +363,8 @@ test_files:
372
363
  - spec/api/request_spec.rb
373
364
  - spec/api/resource_spec.rb
374
365
  - spec/auth/access_token_spec.rb
375
- - spec/commands/analyze_field_spec.rb
376
- - spec/commands/analyze_schema_spec.rb
377
366
  - spec/commands/connect_spec.rb
378
367
  - spec/commands/helpers_spec.rb
379
- - spec/commands/import_spec.rb
380
368
  - spec/commands/login_spec.rb
381
369
  - spec/config_spec.rb
382
370
  - spec/connector/commands/select_report_run_dataset_spec.rb
@@ -1,20 +0,0 @@
1
- module Mode
2
- module CLI
3
- class Base < Thor
4
- desc "analyze PATH [--field=POSITION] [--match-type=TYPE]", "Analyze a CSV file"
5
- option :sample, :banner => 'RATE', :desc => "Proportion of rows to inspect. Example: 0.5"
6
- option :field, :banner => 'POSITION', :desc => "Field positions begin at 0. Example: 10"
7
- option :match_type, :banner => 'TYPE', :desc => "One of the following: string, number, integer, datetime, boolean"
8
- # option :keys, :banner => 'POSITIONS (ex: 0,2)', :default => String.new
9
- def analyze(path = nil)
10
- #keys = options[:keys].split(',').collect(&:strip).collect(&:to_i)
11
-
12
- if field_pos = options[:field]
13
- Mode::Commands::AnalyzeField.new(path, field_pos, options).execute
14
- else
15
- Mode::Commands::AnalyzeSchema.new(path, options).execute
16
- end
17
- end
18
- end
19
- end
20
- end
@@ -1,13 +0,0 @@
1
- module Mode
2
- module CLI
3
- module Helpers
4
- def valid_file?(file)
5
- !file.nil? && File.exist?(file)
6
- end
7
-
8
- def valid_table?(table)
9
- table =~ /[\w\d\_\-]+\/[\w\d\_\-]+/
10
- end
11
- end
12
- end
13
- end
@@ -1,33 +0,0 @@
1
- module Mode
2
- module CLI
3
- class Base < Thor
4
- desc "import SOURCE ACCOUNT/TABLENAME [--replace]", "Import a flat file into the Mode data warehouse", :hide => true
5
- long_desc <<-LONGDESC
6
- The import commands allows you to create or replace tables
7
- in the Mode data warehouse with data from flat files and
8
- data packages. The default action is create with an optional
9
- flag to replace the table.
10
-
11
- Data can be imported from CSV files or data packages with the following command
12
-
13
- 1. CSV File
14
- \x5> $ mode import gdp_quarterly.csv besquared/gdp_quarterly
15
-
16
- 2. Data Package File
17
- \x5> $ mode import gdp/data/quarterly.json besqaured/quarterly_gdp
18
-
19
- LONGDESC
20
- option :replace, :type => :boolean
21
- option :primary_key, :banner => 'pos1[,pos2,...] (ex: 0,2)'
22
- def import(source, table)
23
- unless valid_table?(table)
24
- error "Error: Invalid account or table name given"
25
- return
26
- end
27
-
28
- account, table_name = *table.split('/')
29
- Mode::Commands::Import.new(source, account, table_name).execute
30
- end
31
- end
32
- end
33
- end
@@ -1,13 +0,0 @@
1
- module Mode
2
- module CLI
3
- class Base < Thor
4
- desc "package SOURCE PACKAGEPATH [--name=NAME] [--resource-name=NAME]", "Creates a new data package from a csv file"
5
- option :name, :desc => 'The name of the package'
6
- option :resource_name, :default => 'data', :desc => 'The name of the resource in package'
7
- def package(source, package_path)
8
- name = options[:name] || package_path.split(File::Separator).last
9
- Mode::Commands::Package.new(source, package_path, name, options[:resource_name]).execute
10
- end
11
- end
12
- end
13
- end
@@ -1,60 +0,0 @@
1
- require 'terminal-table'
2
-
3
- module Mode
4
- module Commands
5
- class AnalyzeField
6
- include Mode::Commands::Helpers
7
-
8
- attr_accessor :path
9
- attr_accessor :field_pos
10
- attr_accessor :options
11
-
12
- def initialize(path, field_pos, options = {})
13
- @path = path
14
- @field_pos = field_pos.to_i
15
- @options = options
16
- end
17
-
18
- def execute
19
- if path.nil? || !File.exist?(path)
20
- puts "Error: Couldn't find file at #{path}"
21
- return
22
- end
23
-
24
- csv = DataKit::CSV::Parser.new(path)
25
-
26
- puts "Analyzing field #{field_pos} at #{path || 'input'}"
27
-
28
- analysis, total_time = timer_block do
29
- DataKit::CSV::FieldAnalyzer.analyze(csv, field_pos, {
30
- :match_type => match_type, :sampling_rate => 1
31
- })
32
- end
33
-
34
- puts "Analyzed #{analysis.row_count} rows in #{'%.2f' % total_time} seconds\n"
35
-
36
- display(analysis)
37
- end
38
-
39
- private
40
-
41
- def display(analysis)
42
- table = Terminal::Table.new(:headings => [
43
- 'Row No.', 'Type', 'Value'
44
- ])
45
-
46
- analysis.types.each do |type, rows|
47
- rows.each do |row_num|
48
- table.add_row [row_num, type, analysis.value_at(row_num)]
49
- end
50
- end
51
-
52
- puts table
53
- end
54
-
55
- def match_type
56
- options[:match_type] ? options[:match_type].to_sym : :any
57
- end
58
- end
59
- end
60
- end
@@ -1,111 +0,0 @@
1
- require 'terminal-table'
2
-
3
- module Mode
4
- module Commands
5
- class AnalyzeSchema
6
- include Mode::Commands::Helpers
7
-
8
- attr_accessor :path
9
- attr_accessor :options
10
-
11
- def initialize(path, options = {})
12
- @path = path
13
- @options = options
14
- end
15
-
16
- def execute
17
- if path.nil? || !File.exist?(path)
18
- puts "Error: Couldn't find file at #{path}"
19
- return
20
- end
21
-
22
- csv = build_csv
23
- analysis = build_analysis(csv)
24
- display_analysis(analysis)
25
- end
26
-
27
- private
28
-
29
- def build_csv
30
- DataKit::CSV::Parser.new(path)
31
- end
32
-
33
- def build_analysis(csv)
34
- puts "Analyzing #{path || 'input'} (Sampling #{'%.2f' % (100 * sampling_rate)}%)..."
35
-
36
- analysis, total_time = timer_block do
37
- DataKit::CSV::SchemaAnalyzer.analyze(csv, :sampling_rate => sampling_rate)
38
- end
39
-
40
- puts "Analyzed #{analysis.sample_count} of #{analysis.row_count} rows in #{'%.2f' % total_time} seconds\n"
41
-
42
- analysis
43
- end
44
-
45
- def sampling_rate
46
- file_size = File.size(path)
47
- (options[:sample] || DataKit::CSV::SchemaAnalyzer.sampling_rate(file_size)).to_f
48
- end
49
-
50
- def display_analysis(analysis)
51
- table = build_table
52
- populate_table(analysis, table)
53
- puts table
54
- end
55
-
56
- def build_table
57
- Terminal::Table.new(:headings => [
58
- 'Field No.', 'Field', 'Type',
59
- 'String (%)', 'Integer (%)', 'Number (%)',
60
- 'Date/Time (%)', 'Boolean (%)', 'Empty (%)'
61
- ])
62
- end
63
-
64
- def populate_table(analysis, table)
65
- analysis.fields.each_with_index do |field_name, index|
66
- build_table_row(analysis, table, field_name, index)
67
- end
68
- end
69
-
70
- def build_table_row(analysis, table, field_name, index)
71
- row = [index, field_name]
72
-
73
- append_row_type(analysis, field_name, row)
74
- append_row_type_counts(analysis, field_name, row)
75
-
76
- table.add_row(row)
77
- end
78
-
79
- def append_row_type(analysis, field_name, row)
80
- field_type = analysis.type?(field_name)
81
-
82
- if analysis.has_single_type?(field_name)
83
- row << field_type
84
- elsif analysis.has_only_numeric_types?(field_name)
85
- row << field_type
86
- else
87
- row << '** ' + field_type.to_s
88
- end
89
- end
90
-
91
- def append_row_type_counts(analysis, field_name, row)
92
- DataKit::Dataset::Field::Types.each do |type|
93
- type_count = analysis.type_count(field_name, type)
94
- row << format_percentage_cell(type_count, analysis.sample_count)
95
- end
96
- end
97
-
98
- def format_percentage_cell(numerator, denominator)
99
- cell = { :alignment => :right }
100
-
101
- if numerator == 0
102
- cell[:value] = nil
103
- else
104
- cell[:value] = '%.2f' % (100 * (numerator / denominator.to_f)) + '%'
105
- end
106
-
107
- cell
108
- end
109
- end
110
- end
111
- end
@@ -1,224 +0,0 @@
1
- module Mode
2
- module Commands
3
- class Import
4
- include Mode::Commands::Helpers
5
-
6
- attr_reader :source
7
- attr_reader :account
8
- attr_reader :table_name
9
-
10
- def initialize(source, account, table_name)
11
- @source = source
12
- @account = account
13
- @table_name = table_name
14
- end
15
-
16
- def execute
17
- validate_config!
18
-
19
- package = make_package
20
- uploaded = upload_package(package)
21
- imported = import_package(uploaded)
22
- end
23
-
24
- def make_package
25
- find_or_build_package(source, :name => table_name)
26
- end
27
-
28
- def upload_package(package)
29
- resource = package.resources.first
30
- file_path = File.join(resource.base_path, resource.path)
31
-
32
- replace_resource_path!(resource)
33
-
34
- Mode::API::Request.post(upload_path, :package => {
35
- :contents => {
36
- 'datapackage.json' => package.to_json,
37
- resource.path => Faraday::UploadIO.new(file_path, 'application/octet-stream')
38
- }, :name => table_name
39
- })
40
- end
41
-
42
- def import_package(uploaded)
43
- resource = parse_uploaded_response(uploaded)
44
- submit_import_form(resource, { 'table_name' => table_name })
45
- end
46
-
47
- def target_resource_path(path)
48
- self.class.target_resource_path(path)
49
- end
50
-
51
- private
52
-
53
- def upload_path
54
- Mode::API::Request.packages_path
55
- end
56
-
57
- def find_or_build_package(source, options = {})
58
- self.class.find_or_build_package(source, options)
59
- end
60
-
61
- # We replace the resource path with the desired path on the remote end
62
- def replace_resource_path!(resource)
63
- resource.path = target_resource_path(resource.path)
64
- end
65
-
66
- def submit_import_form(resource, params)
67
- resource.forms('import').submit!(:import => params)
68
- end
69
-
70
- def parse_uploaded_response(content)
71
- resource = Mode::API::Resource.new(content)
72
- end
73
-
74
- class << self
75
- #
76
- # Utilities that can be useful elsewhere
77
- #
78
-
79
- def find_package(source, path = nil)
80
- path = path || search_path(source)
81
-
82
- if path =~ /\/data$/
83
- parent = parent_path(path)
84
- find_package(source, parent)
85
- elsif package_exists?(path)
86
- DataPackage::Package.open(path)
87
- else
88
- nil
89
- end
90
- end
91
-
92
- def build_package(source, options = {})
93
- name = options[:name] || 'data'
94
- dest = options[:dest] || tmpdir
95
-
96
- if File.exist?(source)
97
- converter = convert(source)
98
- DataPackage::Package.new(dest).tap do |package|
99
- package.name = name
100
- package.version = '0.0.1'
101
- package.resources << build_resource(converter)
102
- end
103
- else
104
- nil
105
- end
106
- end
107
-
108
- def find_or_build_package(source, options = {})
109
- package = find_package(source)
110
-
111
- if package.nil?
112
- build_opts = {
113
- :name => options[:name],
114
- :dest => options[:dest]
115
- }
116
- package = build_package(source, build_opts)
117
- else
118
- package = prune_package(source, package)
119
- end
120
-
121
- package
122
- end
123
-
124
- def target_resource_path(path = nil)
125
- "data/index#{path.nil? ? '.csv' : File.extname(path)}"
126
- end
127
-
128
- private
129
-
130
- #
131
- # Package Building
132
- #
133
-
134
- def build_resource(converter)
135
- DataPackage::Resource.new(tmpdir, {
136
- 'name' => 'index.csv',
137
- 'path' => target_resource_path,
138
- 'size' => File.size?(target),
139
- 'schema' => build_schema(converter)
140
- })
141
- end
142
-
143
- def build_schema(converter)
144
- {
145
- 'fields' => build_fields(converter),
146
- 'dialect' => DataPackage::Dialect.new
147
- }
148
- end
149
-
150
- def build_fields(converter)
151
- converter.field_types.inject([]) do |fields, (field_name, field_type)|
152
- fields << {'name' => field_name, 'type' => field_type.to_s}
153
- end
154
- end
155
-
156
- #
157
- # Data Conversion
158
- #
159
-
160
- def convert(source)
161
- csv = DataKit::CSV::Parser.new(source)
162
- analysis = DataKit::CSV::SchemaAnalyzer.analyze(csv, :sampling_rate => 1.0)
163
- DataKit::CSV::Converter.convert(csv, analysis, target)
164
- end
165
-
166
- def tmpdir
167
- @tmpdir ||= Dir.mktmpdir
168
- end
169
-
170
- def tmppath(path)
171
- File.join(tmpdir, path)
172
- end
173
-
174
- def target(path = 'data', name = 'index.csv')
175
- full_path = tmppath(path)
176
- FileUtils.mkdir_p(full_path)
177
- @target ||= File.join(full_path, name)
178
- end
179
-
180
- #
181
- # Checks and Validations
182
- #
183
-
184
- def search_path(source)
185
- File.file?(source) ? File.dirname(source) : source
186
- end
187
-
188
- def package_exists?(path)
189
- DataPackage::Package.exist?(path)
190
- end
191
-
192
- def parent_path(path)
193
- File.expand_path(File.join(path, '..'))
194
- end
195
-
196
- def resource_path(path)
197
- matched = path.match(/((data\/)?[^\/]+)$/)
198
- matched.nil? ? matched : matched.to_a.first
199
- end
200
-
201
- def first_resource(package)
202
- package.resources.find{ |r| not r.path.nil? }
203
- end
204
-
205
- def find_resource(package, path)
206
- package.resources.find{ |r| r.path == path }
207
- end
208
-
209
- def prune_package(source, package)
210
- if File.directory?(source)
211
- resource = first_resource(package)
212
- elsif File.file?(source)
213
- resource_path = resource_path(source)
214
- resource = find_resource(package, resource_path)
215
- end
216
-
217
- package.resources = []
218
- package.resources << resource
219
- package
220
- end
221
- end
222
- end
223
- end
224
- end
@@ -1,26 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Mode::Commands::AnalyzeField do
4
- let(:tmpdir) { Dir.mktmpdir }
5
-
6
- before do
7
- initialize_logger
8
- end
9
-
10
- it "should analyze a csv" do
11
- path = fixture_path('espn_draft.csv')
12
- command = Mode::Commands::AnalyzeField.new(path, 1)
13
-
14
- command.stub(:puts).and_return(true)
15
-
16
- command.execute
17
- end
18
-
19
- it "should error out if the csv file doesn't exist" do
20
- command = Mode::Commands::AnalyzeField.new("fake.yml", 1)
21
-
22
- command.should_receive(:puts)
23
-
24
- command.execute
25
- end
26
- end
@@ -1,26 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Mode::Commands::AnalyzeSchema do
4
- let(:tmpdir) { Dir.mktmpdir }
5
-
6
- before do
7
- initialize_logger
8
- end
9
-
10
- it "should analyze a csv" do
11
- path = fixture_path('espn_draft.csv')
12
- command = Mode::Commands::AnalyzeSchema.new(path)
13
-
14
- command.stub(:puts).and_return(true)
15
-
16
- command.execute
17
- end
18
-
19
- it "should error out if the csv file doesn't exist" do
20
- command = Mode::Commands::AnalyzeSchema.new("fake.yml", keys: [0,1])
21
-
22
- command.should_receive(:puts)
23
-
24
- command.execute
25
- end
26
- end
@@ -1,160 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Mode::Commands::Import do
4
- let(:tmpdir) { Dir.mktmpdir }
5
- let(:config) { Mode::Config.init(tmpdir) }
6
- let(:packages_path) { Mode::API::Request.packages_path }
7
-
8
- before do
9
- initialize_logger
10
- end
11
-
12
- it "generates target resource path with a csv extension" do
13
- source = fixture_path("espn_draft/data.csv")
14
- path = Mode::Commands::Import.send(:target_resource_path, source)
15
-
16
- path.should == "data/index.csv"
17
- end
18
-
19
- it "generates target resource path with a non-csv extension" do
20
- source = fixture_path("espn_draft.json")
21
- path = Mode::Commands::Import.send(:target_resource_path, source)
22
-
23
- path.should == "data/index.json"
24
- end
25
-
26
- describe 'finding a package from a source file' do
27
- it 'returns the package if the file is adjacent to datapackage.json' do
28
- source = fixture_path("espn_draft/data.csv")
29
- package = Mode::Commands::Import.find_package(source)
30
-
31
- package.base_path.should == fixture_path("espn_draft")
32
- end
33
-
34
- it 'returns the package if the file is inside of the data subdirectory' do
35
- source = fixture_path("country-codes/data/country-codes.csv")
36
- package = Mode::Commands::Import.find_package(source)
37
-
38
- package.base_path.should == fixture_path("country-codes")
39
- end
40
-
41
- it 'returns nil if a package is not found' do
42
- source = fixture_path("espn_draft.csv")
43
- Mode::Commands::Import.find_package(source).should == nil
44
- end
45
- end
46
-
47
- describe 'finding a package from a source directory' do
48
- it 'returns the package if it exists in the directory' do
49
- source = fixture_path("espn_draft")
50
- package = Mode::Commands::Import.find_package(source)
51
-
52
- package.base_path.should == fixture_path("espn_draft")
53
- end
54
-
55
- it 'returns nil if the package is not found in the directory' do
56
- source = fixture_path
57
-
58
- Mode::Commands::Import.find_package(source).should == nil
59
- end
60
- end
61
-
62
- describe 'building a package from a source file' do
63
- it 'build the package' do
64
- source = fixture_path("espn_draft.csv")
65
- package = Mode::Commands::Import.build_package(source, :dest => tmpdir)
66
-
67
- package.base_path.should == tmpdir
68
- end
69
-
70
- it 'returns nil if the file does not exist' do
71
- source = fixture_path('nope')
72
- Mode::Commands::Import.build_package(source).should == nil
73
- end
74
- end
75
-
76
- describe 'finding or building a package from a source file' do
77
- it 'returns the package and resource name for a file in a datapackage' do
78
- source = fixture_path("espn_draft/data.csv")
79
- package = Mode::Commands::Import.find_or_build_package(source)
80
-
81
- package.resources.first.path.should == 'data.csv'
82
- package.base_path.should == fixture_path("espn_draft")
83
- end
84
-
85
- it 'returns the package and resource name for a file outisde a datapackage' do
86
- source = fixture_path("espn_draft.csv")
87
- package = Mode::Commands::Import.find_or_build_package(source, :dest => tmpdir)
88
-
89
- package.base_path.should == tmpdir
90
- package.resources.first.path.should == 'data/index.csv'
91
- end
92
- end
93
-
94
- describe 'finding or building a package from a source directory' do
95
- it 'returns the package and resource name' do
96
- source = fixture_path("espn_draft")
97
- package = Mode::Commands::Import.find_or_build_package(source, :dest => tmpdir)
98
-
99
- package.resources.first.path.should == 'data.csv'
100
- package.base_path.should == fixture_path("espn_draft")
101
- end
102
- end
103
-
104
- describe 'uploading a package' do
105
- it 'uploads a package' do
106
- Mode::API::Request.should_receive(:post).and_return(true)
107
-
108
- source = fixture_path("espn_draft.csv")
109
- package = Mode::Commands::Import.find_or_build_package(source, :dest => tmpdir)
110
-
111
- import = Mode::Commands::Import.new(source, 'besquared', 'espn_draft')
112
-
113
- import.upload_package(package).should == true
114
- end
115
- end
116
-
117
- describe 'executing an import' do
118
- it 'finds and upload a package' do
119
- Mode::API::Request.should_receive(:post).with(packages_path, :package => {
120
- :contents => {
121
- 'datapackage.json' => an_instance_of(String),
122
- 'data/index.csv' => an_instance_of(Faraday::UploadIO)
123
- }, :name => 'espn_draft'
124
- }).and_return(:package)
125
-
126
- source = fixture_path("espn_draft/data.csv")
127
- import = Mode::Commands::Import.new(source, 'besquared', 'espn_draft')
128
-
129
- resource = double(:resource)
130
- import_params = { 'table_name' => 'espn_draft' }
131
- import.should_receive(:parse_uploaded_response).with(:package).and_return(resource)
132
- import.should_receive(:submit_import_form).with(resource, import_params).and_return(true)
133
-
134
- import.should_receive(:validate_config!).and_return(true)
135
-
136
- import.execute
137
- end
138
-
139
- it 'finds and uploads country codes package' do
140
- Mode::API::Request.should_receive(:post).with(packages_path, :package => {
141
- :contents => {
142
- 'datapackage.json' => an_instance_of(String),
143
- 'data/index.csv' => an_instance_of(Faraday::UploadIO)
144
- }, :name => 'country_codes'
145
- }).and_return(:package)
146
-
147
- source = fixture_path("country-codes/data/country-codes.csv")
148
- import = Mode::Commands::Import.new(source, 'besquared', 'country_codes')
149
-
150
- resource = double(:resource)
151
- import_params = { 'table_name' => 'country_codes' }
152
- import.should_receive(:parse_uploaded_response).with(:package).and_return(resource)
153
- import.should_receive(:submit_import_form).with(resource, import_params).and_return(true)
154
-
155
- import.should_receive(:validate_config!).and_return(true)
156
-
157
- import.execute
158
- end
159
- end
160
- end