mongify 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/.gitignore +20 -0
  2. data/CHANGELOG.rdoc +22 -0
  3. data/Gemfile +4 -0
  4. data/Gemfile.lock +68 -0
  5. data/LICENSE +20 -0
  6. data/README.rdoc +86 -0
  7. data/Rakefile +73 -0
  8. data/bin/mongify +14 -0
  9. data/features/options.feature +46 -0
  10. data/features/print.feature +10 -0
  11. data/features/process.feature +19 -0
  12. data/features/step_definitions/mongify_steps.rb +42 -0
  13. data/features/step_definitions/mongo_steps.rb +7 -0
  14. data/features/support/env.rb +28 -0
  15. data/lib/mongify.rb +22 -0
  16. data/lib/mongify/cli.rb +8 -0
  17. data/lib/mongify/cli/application.rb +43 -0
  18. data/lib/mongify/cli/help_command.rb +16 -0
  19. data/lib/mongify/cli/options.rb +94 -0
  20. data/lib/mongify/cli/report.rb +11 -0
  21. data/lib/mongify/cli/version_command.rb +18 -0
  22. data/lib/mongify/cli/worker_command.rb +93 -0
  23. data/lib/mongify/configuration.rb +46 -0
  24. data/lib/mongify/database.rb +5 -0
  25. data/lib/mongify/database/base_connection.rb +78 -0
  26. data/lib/mongify/database/column.rb +81 -0
  27. data/lib/mongify/database/no_sql_connection.rb +62 -0
  28. data/lib/mongify/database/sql_connection.rb +61 -0
  29. data/lib/mongify/database/table.rb +74 -0
  30. data/lib/mongify/exceptions.rb +13 -0
  31. data/lib/mongify/translation.rb +55 -0
  32. data/lib/mongify/translation/printer.rb +20 -0
  33. data/lib/mongify/translation/process.rb +61 -0
  34. data/lib/mongify/ui.rb +45 -0
  35. data/lib/mongify/version.rb +3 -0
  36. data/mongify.gemspec +42 -0
  37. data/spec/default.watch +199 -0
  38. data/spec/files/base_configuration.rb +9 -0
  39. data/spec/files/empty_translation.rb +0 -0
  40. data/spec/files/simple_translation.rb +26 -0
  41. data/spec/mongify/cli/application_spec.rb +19 -0
  42. data/spec/mongify/cli/help_command_spec.rb +18 -0
  43. data/spec/mongify/cli/options_spec.rb +62 -0
  44. data/spec/mongify/cli/version_command_spec.rb +24 -0
  45. data/spec/mongify/cli/worker_command_spec.rb +115 -0
  46. data/spec/mongify/configuration_spec.rb +25 -0
  47. data/spec/mongify/database/base_connection_spec.rb +59 -0
  48. data/spec/mongify/database/column_spec.rb +103 -0
  49. data/spec/mongify/database/no_sql_connection_spec.rb +131 -0
  50. data/spec/mongify/database/sql_connection_spec.rb +91 -0
  51. data/spec/mongify/database/table_spec.rb +120 -0
  52. data/spec/mongify/translation/printer_spec.rb +34 -0
  53. data/spec/mongify/translation/process_spec.rb +68 -0
  54. data/spec/mongify/translation_spec.rb +59 -0
  55. data/spec/mongify/ui_spec.rb +73 -0
  56. data/spec/mongify_spec.rb +15 -0
  57. data/spec/spec.opts +1 -0
  58. data/spec/spec_helper.rb +22 -0
  59. data/spec/support/config_reader.rb +21 -0
  60. data/spec/support/database.example +17 -0
  61. data/spec/support/database_output.txt +27 -0
  62. data/spec/support/generate_database.rb +91 -0
  63. metadata +370 -0
@@ -0,0 +1,28 @@
1
+ $:.unshift 'lib'
2
+
3
+ require 'rubygems'
4
+ require 'tempfile'
5
+ require 'fileutils'
6
+ require 'mongify/cli/application'
7
+ require 'mongify'
8
+ require 'spec/support/generate_database'
9
+ require 'spec/support/config_reader'
10
+
11
+ ::CONNECTION_CONFIG = ConfigReader.new(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__)))) + '/spec/support/database.yml')
12
+ ::DATABASE_PRINT = File.read(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__)))) + '/spec/support/database_output.txt')
13
+
14
+ module MongifyWorld
15
+ def run(cmd)
16
+ stderr_file = Tempfile.new('mongify-world')
17
+ stderr_file.close
18
+ @last_stdout = `#{cmd} 2> #{stderr_file.path}`
19
+ @last_exit_status = $?.exitstatus
20
+ @last_stderr = IO.read(stderr_file.path)
21
+ end
22
+
23
+ def mongify(args)
24
+ run("ruby -Ilib -rubygems bin/mongify #{args}")
25
+ end
26
+ end
27
+
28
+ World(MongifyWorld)
@@ -0,0 +1,22 @@
1
+ #
2
+ # Mongify's core functionality
3
+ #
4
+ require 'active_support/core_ext'
5
+
6
+ require 'mongify/ui'
7
+ require 'mongify/exceptions'
8
+ require 'mongify/translation'
9
+ require 'mongify/configuration'
10
+ require 'mongify/database'
11
+
12
+ module Mongify
13
+ class << self
14
+ def root=(value)
15
+ @root = value
16
+ end
17
+ def root
18
+ raise RootMissing, "Root not configured" if @root.nil?
19
+ @root
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,8 @@
1
+ require 'mongify'
2
+
3
+ require 'mongify/cli/options'
4
+ require 'mongify/cli/report'
5
+ require 'mongify/cli/version_command'
6
+ require 'mongify/cli/help_command'
7
+ require 'mongify/cli/worker_command'
8
+ require 'mongify/cli/application'
@@ -0,0 +1,43 @@
1
+ module Mongify
2
+ module CLI
3
+ #
4
+ # Represents an instance of a Mongify application.
5
+ # This is the entry point for all invocations of Mongify from the
6
+ # command line.
7
+ #
8
+ class Application
9
+
10
+ STATUS_SUCCESS = 0
11
+ STATUS_ERROR = 1
12
+
13
+ def initialize(arguments=["--help"], stdin=$stdin, stdout=$stdout)
14
+ @options = Options.new(arguments)
15
+ @status = STATUS_SUCCESS
16
+ Mongify::Configuration.in_stream = stdin
17
+ Mongify::Configuration.out_stream = stdout
18
+ end
19
+
20
+ def execute!
21
+ begin
22
+ cmd = @options.parse
23
+ cmd.execute(self)
24
+ rescue Exception => error
25
+ $stderr.puts "Error: #{error}"
26
+ report_error
27
+ end
28
+ return @status
29
+ end
30
+
31
+ def output(message)
32
+ UI.puts(message)
33
+ end
34
+
35
+ def report_success
36
+ @status = STATUS_SUCCESS
37
+ end
38
+ def report_error
39
+ @status = STATUS_ERROR
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,16 @@
1
+ module Mongify
2
+ module CLI
3
+ #
4
+ # A command to display usage information for this application.
5
+ #
6
+ class HelpCommand
7
+ def initialize(parser)
8
+ @parser = parser
9
+ end
10
+ def execute(view)
11
+ view.output(@parser.to_s)
12
+ view.report_success
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,94 @@
1
+ require 'optparse'
2
+ module Mongify
3
+ module CLI
4
+ #
5
+ # Used to parse the options for an application
6
+ #
7
+ class Options
8
+ def initialize(argv)
9
+ @parsed = false
10
+ @argv = argv
11
+ @parser = OptionParser.new
12
+ @report_class = VerboseReport
13
+ #@command_class = ReekCommand
14
+ set_options
15
+
16
+ end
17
+
18
+ def banner
19
+ progname = @parser.program_name
20
+ return <<EOB
21
+ Usage: #{progname} command [database_translation.rb] [-c database.config]
22
+
23
+ Commands:
24
+ #{Mongify::CLI::WorkerCommand.list_commands.join("\n")}
25
+
26
+ Examples:
27
+
28
+ #{progname} translate -c datbase.config
29
+ #{progname} tr -c database.config
30
+ #{progname} check -c database.config
31
+ #{progname} process database_translation.rb -c database.config
32
+
33
+ See http://github.com/anlek/mongify for more details
34
+
35
+ EOB
36
+ end
37
+
38
+
39
+ def set_options
40
+ @parser.banner = banner
41
+ @parser.separator "Common options:"
42
+ @parser.on("-h", "--help", "Show this message") do
43
+ @command_class = HelpCommand
44
+ end
45
+ @parser.on("-v", "--version", "Show version") do
46
+ @command_class = VersionCommand
47
+ end
48
+ @parser.on('-c', '--config FILE', "Configuration File to use") do |file|
49
+ @config_file = file
50
+ end
51
+
52
+ @parser.separator "\nReport formatting:"
53
+ @parser.on("-q", "--[no-]quiet", "Suppress extra output") do |opt|
54
+ @report_class = opt ? QuietReport : VerboseReport
55
+ end
56
+ end
57
+
58
+ def parse
59
+ parse_options
60
+
61
+ if @command_class == HelpCommand
62
+ HelpCommand.new(@parser)
63
+ elsif @command_class == VersionCommand
64
+ VersionCommand.new(@parser.program_name)
65
+ else
66
+ raise ConfigurationFileNotFound unless @config_file
67
+ #TODO: In the future, request sql_connection and nosql_connection from user input
68
+ config = Configuration.parse(@config_file)
69
+
70
+ WorkerCommand.new(action, config, translation_file, @parser)
71
+ end
72
+ end
73
+
74
+ private
75
+
76
+ def translation_file(argv=@argv)
77
+ parse_options
78
+ return nil if argv.length < 2
79
+ argv[1]
80
+ end
81
+
82
+ def action(argv=@argv)
83
+ parse_options
84
+ @argv.try(:[],0) || ''
85
+ end
86
+
87
+ def parse_options
88
+ @parsed = true && @parser.parse!(@argv) unless @parsed
89
+ end
90
+
91
+
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,11 @@
1
+ module Mongify
2
+ module CLI
3
+ class QuietReport
4
+
5
+ end
6
+
7
+ class VerboseReport
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ require 'mongify/version'
2
+ module Mongify
3
+ module CLI
4
+
5
+ #
6
+ # A command to report the application's current version number.
7
+ #
8
+ class VersionCommand
9
+ def initialize(progname)
10
+ @progname = progname
11
+ end
12
+ def execute(view)
13
+ view.output("#{@progname} #{Mongify::VERSION}\n")
14
+ view.report_success
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,93 @@
1
+ module Mongify
2
+ module CLI
3
+
4
+ #
5
+ # A command to run the different commands in the application (related to Mongifying).
6
+ #
7
+ class WorkerCommand
8
+ attr_accessor :view
9
+
10
+ AVAILABLE_COMMANDS = {
11
+ :check => {:commands => ['check', 'ck'], :description => "Checks connection for sql and no_sql databases", :required => [:configuration_file]},
12
+ :translate => {:commands => ['translate', 'tr'], :description => "Spits out translation from a sql connection", :required => [:configuration_file]},
13
+ :process => {:commands => ['process', 'pr'], :description => "Takes a translation and process it to mongodb", :required => [:configuration_file, :translation_file]}
14
+ }
15
+ def self.list_commands
16
+ [].tap do |commands|
17
+ AVAILABLE_COMMANDS.each do |key, obj|
18
+ commands << "#{obj[:commands].map{|w| %["#{w}"]}.to_sentence(:two_words_connector => ' or ', :last_word_connector => ', or ').ljust(25)} >> #{obj[:description]}#{ " [#{obj[:required].join(', ')}]" if obj[:required]}"
19
+ end
20
+ end.sort
21
+ end
22
+
23
+ def self.find_command(command)
24
+ AVAILABLE_COMMANDS.each do |key, options|
25
+ return [key, options] if(options[:commands].include?(command.to_s.downcase))
26
+ end
27
+ 'unknown'
28
+ end
29
+
30
+ def initialize(command, config=nil, translation_file=nil, parser="")
31
+ @command = command.to_s.downcase
32
+ @config = config
33
+ @translation_file = translation_file
34
+ @parser = parser
35
+ end
36
+
37
+ def execute(view)
38
+ self.view = view
39
+
40
+ current_command, command_options = find_command
41
+
42
+ if command_options
43
+ #FIXME: Should parse configuration file in this action, (when I know it's required)
44
+ raise ConfigurationFileNotFound, "Configuration file is required" if command_options[:required] && command_options[:required].include?(:configuration_file) && @config.nil?
45
+ if command_options[:required] && command_options[:required].include?(:translation_file)
46
+ raise TranslationFileNotFound, "Translation file is required for command '#{current_command}'" unless @translation_file
47
+ raise TranslationFileNotFound, "Unable to find Translation File at #{@translation_file}" unless File.exists?(@translation_file)
48
+ @translation = Translation.parse(@translation_file)
49
+ end
50
+ end
51
+
52
+ case current_command
53
+ when :translate
54
+ check_connections
55
+ view.output(Mongify::Translation.load(@config.sql_connection).print)
56
+ when :check
57
+ view.output("SQL connection works") if check_sql_connection
58
+ view.output("NoSQL connection works") if check_nosql_connection
59
+ when :process
60
+ check_connections
61
+ @translation.process(@config.sql_connection, @config.no_sql_connection)
62
+ else
63
+ view.output("Unknown action #{@command}\n\n#{@parser}")
64
+ view.report_error
65
+ return
66
+ end
67
+ view.report_success
68
+ end
69
+
70
+ def find_command(command=@command)
71
+ self.class.find_command(command)
72
+ end
73
+
74
+ #######
75
+ private
76
+ #######
77
+
78
+ def check_connections(sql_only = false)
79
+ check_sql_connection && (sql_only || check_nosql_connection)
80
+ end
81
+
82
+ def check_sql_connection
83
+ @config.sql_connection.valid? && @config.sql_connection.has_connection?
84
+ end
85
+
86
+ def check_nosql_connection
87
+ @config.no_sql_connection.valid? && @config.no_sql_connection.has_connection?
88
+ end
89
+
90
+
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,46 @@
1
+ module Mongify
2
+ #
3
+ # This extracts the configuration for sql and no sql
4
+ #
5
+ class Configuration
6
+ class << self
7
+ attr_accessor :in_stream, :out_stream
8
+
9
+ def parse_translation(file_name)
10
+ raise Mongify::TranslationFileNotFound, "File #{file_name} is missing" unless File.exists?(file_name)
11
+ Mongify::Translation.parse(file_name)
12
+ end
13
+
14
+ def parse_configuration(file_name)
15
+ raise Mongify::ConfigurationFileNotFound, "File #{file_name} is missing" unless File.exists?(file_name)
16
+ Mongify::Configuration.parse(file_name)
17
+ end
18
+
19
+ def parse(file_name)
20
+ config = self.new
21
+ config.instance_eval(File.read(file_name))
22
+ config
23
+ end
24
+
25
+ end #self
26
+
27
+ def mongodb_connection(options={}, &block)
28
+ options.stringify_keys!
29
+ options['adapter'] ||= 'mongodb'
30
+ no_sql_connection(options, &block)
31
+ end
32
+
33
+ def sql_connection(options={}, &block)
34
+ @sql_connection ||= Mongify::Database::SqlConnection.new(options)
35
+ @sql_connection.instance_exec(&block) if block_given?
36
+ @sql_connection
37
+ end
38
+
39
+ def no_sql_connection(options={}, &block)
40
+ @no_sql_connection ||= Mongify::Database::NoSqlConnection.new(options)
41
+ @no_sql_connection.instance_exec(&block) if block_given?
42
+ @no_sql_connection
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,5 @@
1
+ require 'mongify/database/base_connection'
2
+ require 'mongify/database/no_sql_connection'
3
+ require 'mongify/database/sql_connection'
4
+ require 'mongify/database/table'
5
+ require 'mongify/database/column'
@@ -0,0 +1,78 @@
1
+ require 'active_record'
2
+
3
+ module Mongify
4
+ module Database
5
+ #
6
+ # Basic configuration for any sql or non sql database
7
+ #
8
+ class BaseConnection
9
+
10
+ REQUIRED_FIELDS = %w{host}
11
+ AVAILABLE_FIELDS = %w{adapter host username password database socket port}
12
+
13
+ def initialize(options=nil)
14
+ if options
15
+ options.stringify_keys!
16
+ options.each do |key, value|
17
+ instance_variable_set "@#{key}", value
18
+ end
19
+ end
20
+ end
21
+
22
+ def to_hash
23
+ hash = {}
24
+ instance_variables.each do |variable|
25
+ value = self.instance_variable_get variable
26
+ hash[variable.gsub('@','').to_sym] = value unless value.nil?
27
+ end
28
+ hash
29
+ end
30
+
31
+ def valid?
32
+ REQUIRED_FIELDS.each do |require_field|
33
+ return false unless instance_variables.include?("@#{require_field}") and
34
+ !instance_variable_get("@#{require_field}").to_s.empty?
35
+ end
36
+ true
37
+ end
38
+
39
+
40
+ def setup_connection_adapter
41
+ raise NotImplementedError
42
+ end
43
+
44
+ def has_connection?
45
+ raise NotImplementedError
46
+ end
47
+
48
+ def adapter(value=nil)
49
+ @adapter = value.to_s unless value.nil?
50
+ @adapter
51
+ end
52
+
53
+
54
+ def respond_to?(method, *args)
55
+ return true if AVAILABLE_FIELDS.include?(method.to_s)
56
+ super(method)
57
+ end
58
+
59
+ def method_missing(method, *args)
60
+ method_name = method.to_s #.gsub("=", '')
61
+ if AVAILABLE_FIELDS.include?(method_name.to_s)
62
+ class_eval <<-EOF
63
+ def #{method_name}(value=nil)
64
+ @#{method_name} = value unless value.nil?
65
+ @#{method_name}
66
+ end
67
+ EOF
68
+ value = args.first if args.size > 0
69
+ send(method,value)
70
+ else
71
+ super(method, args)
72
+ end
73
+
74
+ end
75
+
76
+ end
77
+ end
78
+ end