squealer 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ pkg/
data/.watchr ADDED
@@ -0,0 +1,27 @@
1
+ # ~/.vim/ftdetect/watchr.vim
2
+ #
3
+ # This should have only the following line in it:
4
+ #
5
+ # autocmd BufNewFile,BufRead *.watchr setf ruby
6
+ #
7
+ # This will enable vim to recognize this file as ruby code should you wish to
8
+ # edit it.
9
+ def run(cmd)
10
+ puts cmd
11
+ system cmd
12
+ end
13
+
14
+ def spec(file)
15
+ run "spec -O spec/spec.opts #{file}"
16
+ end
17
+
18
+ watch("spec/.*/*_spec\.rb") do |match|
19
+ p match[0]
20
+ spec(match[0])
21
+ end
22
+
23
+ watch("lib/(.*/.*)\.rb") do |match|
24
+ p match[1]
25
+ spec("spec/#{match[1]}_spec.rb")
26
+ end
27
+
data/README.md ADDED
@@ -0,0 +1,13 @@
1
+ # Squealer
2
+
3
+ For now, this is specifically for MongoDB exporting to mySQL with the assumption that the data will be heavily denormalized.
4
+
5
+ The target SQL database must have no foreign keys.
6
+
7
+ The target SQL database must use a primary key of char(16) with value of the MongoDB id.
8
+
9
+ It is assumed no indexes are present in the target database table.
10
+
11
+ The target row is inserted, or updated if present. We are using MySQL INSERT ... UPDATE ON DUPLICATE KEY extended syntax to achieve this for now. This allows an event-driven update of exported data as well as a bulk batch process.
12
+
13
+
data/Rakefile ADDED
@@ -0,0 +1,27 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require 'rake'
5
+ require 'spec/rake/spectask'
6
+ require 'rake/rdoctask'
7
+
8
+ task :default => [:spec]
9
+ Rake::Task[:default].clear
10
+
11
+ begin
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gemspec|
14
+ gemspec.name = "squealer"
15
+ gemspec.summary = "Document-oriented to Relational database exporter"
16
+ gemspec.description = "Exports mongodb to mysql. More later."
17
+ gemspec.email = "joshua.graham@grahamis.com"
18
+ gemspec.homepage = "http://github.com/delitescere/squealer/"
19
+ gemspec.authors = ["Josh Graham", "Durran Jordan"]
20
+ gemspec.add_dependency('mysql', '>= 2.8.1')
21
+ gemspec.add_dependency('mongo', '>= 0.18.3')
22
+ end
23
+ Jeweler::GemcutterTasks.new
24
+ rescue LoadError
25
+ puts "Jeweler not available. Install it with: gem install jeweler"
26
+ end
27
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,38 @@
1
+ require 'squealer'
2
+
3
+ import('localhost', 27017, 'development')
4
+ export('localhost', 'root', '', 'reporting_export')
5
+
6
+ import.collection("users").find({}).each do |user|
7
+ target(:user, user._id) do # insert or update on user where id is primary key column name
8
+ assign(:name) { user.first_name + " " + user.last_name.upcase }
9
+ assign(:dob) { user.dob }
10
+
11
+ user.activities.each do |activity|
12
+ target(:activity, activity._id) do
13
+ assign(:user_id) { user._id }
14
+ assign(:name) { activity.name }
15
+ end
16
+
17
+ activity.tasks.each do |task|
18
+ target(:task, task._id) do
19
+ assign(:user_id) { user._id }
20
+ assign(:activity_id) { activity._id }
21
+ assign(:date) { task.date }
22
+ end
23
+ end #activity.tasks
24
+ end #user.activities
25
+ end
26
+ end #collection("users")
27
+
28
+ import.collection("organization").find({}).each do |organization|
29
+ if organization.disabled
30
+ import.collection("users").find({ :organization_id => organization.id }) do |user|
31
+ target(:user, user.id) do
32
+ assign(:disabled) { true }
33
+ end
34
+ end
35
+ else
36
+ # something else
37
+ end
38
+ end
@@ -0,0 +1,26 @@
1
+ require 'mysql'
2
+ require 'mongo'
3
+ require 'singleton'
4
+
5
+ module Squealer
6
+ class Database
7
+ include Singleton
8
+
9
+ def import_from(host, port, name)
10
+ @import_dbc = Mongo::Connection.new(host, port, :slave_ok => true).db(name)
11
+ end
12
+
13
+ def export_to(host, username, password, name)
14
+ @export_dbc = Mysql.connect(host, username, password, name)
15
+ end
16
+
17
+ def import
18
+ @import_dbc
19
+ end
20
+
21
+ def export
22
+ @export_dbc
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,6 @@
1
+ class Hash
2
+ def method_missing(name, *args, &block)
3
+ super if args.size > 0 || block_given?
4
+ self[name.to_s]
5
+ end
6
+ end
@@ -0,0 +1,33 @@
1
+ class Object
2
+
3
+ def target(table_name, row_id, &block)
4
+ Squealer::Target.new(Squealer::Database.instance.export, table_name, row_id, &block)
5
+ end
6
+
7
+ def assign(column_name, &block)
8
+ Squealer::Target.current.assign(column_name, &block)
9
+ end
10
+
11
+ def import(*args)
12
+ if args.length > 0
13
+ Squealer::Database.instance.import_from(*args)
14
+ else
15
+ Squealer::Database.instance.import
16
+ end
17
+ end
18
+
19
+ def export(*args)
20
+ if args.length > 0
21
+ Squealer::Database.instance.export_to(*args)
22
+ else
23
+ Squealer::Database.instance.export
24
+ end
25
+ end
26
+
27
+ end
28
+
29
+ class NilClass
30
+ def each
31
+ []
32
+ end
33
+ end
@@ -0,0 +1,106 @@
1
+ require 'delegate'
2
+ require 'singleton'
3
+
4
+ module Squealer
5
+ class Target
6
+
7
+ def self.current
8
+ Queue.instance.current
9
+ end
10
+
11
+ def initialize(database_connection, table_name, row_id, &block)
12
+ throw "Block must be given to target (otherwise, there's no work to do)" unless block_given?
13
+
14
+ @table_name = table_name.to_s
15
+ @row_id = row_id
16
+ @column_names = []
17
+ @column_values = []
18
+ @sql = ''
19
+
20
+ target(&block)
21
+ end
22
+
23
+ def sql
24
+ @sql
25
+ end
26
+
27
+ def assign(column_name, &block)
28
+ @column_names << column_name
29
+ @column_values << block.call
30
+ end
31
+
32
+
33
+ private
34
+
35
+ def target(&block)
36
+ Queue.instance.push(self)
37
+
38
+ yield self
39
+
40
+ @sql = "INSERT #{@table_name}"
41
+ @sql << " (#{pk_name}#{column_names}) VALUES (?#{column_value_markers})"
42
+ @sql << " ON DUPLICATE KEY UPDATE #{column_markers}"
43
+
44
+ execute_sql(@sql)
45
+
46
+ Queue.instance.pop
47
+ end
48
+
49
+ def self.targets
50
+ @@targets
51
+ end
52
+
53
+ def targets
54
+ @@targets
55
+ end
56
+
57
+ def execute_sql(sql)
58
+ statement = Database.instance.export.prepare(sql)
59
+ values = [*column_values] + [*column_values] #array expando
60
+ statement.send(:execute, @row_id, *values) #expand values into distinct arguments
61
+ end
62
+
63
+ def pk_name
64
+ 'id'
65
+ end
66
+
67
+ def column_names
68
+ return if @column_names.size == 0
69
+ ",#{@column_names.join(',')}"
70
+ end
71
+
72
+ def column_values
73
+ @column_values
74
+ end
75
+
76
+ def column_value_markers
77
+ return if @column_names.size == 0
78
+ result = ""
79
+ @column_names.size.times { result << ',?'}
80
+ result
81
+ end
82
+
83
+ def column_markers
84
+ return if @column_names.size == 0
85
+ result = ""
86
+ @column_names.each {|k| result << "#{k}=?," }
87
+ result.chop
88
+ end
89
+
90
+ class Queue < DelegateClass(Array)
91
+ include Singleton
92
+
93
+ def current
94
+ last
95
+ end
96
+
97
+ protected
98
+
99
+ def initialize
100
+ super([])
101
+ end
102
+
103
+ end
104
+
105
+ end
106
+ end
@@ -0,0 +1,5 @@
1
+ class Time
2
+ def to_s
3
+ self.strftime("%Y-%m-%d %H:%M:%S %Z")
4
+ end
5
+ end
data/lib/squealer.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'squealer/object'
2
+ require 'squealer/hash'
3
+ require 'squealer/time'
4
+
5
+ require 'squealer/target'
6
+ require 'squealer/database'
@@ -0,0 +1,15 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |gemspec|
4
+ gemspec.name = "squealer"
5
+ gemspec.summary = "Document-oriented to Relational database exporter"
6
+ gemspec.description = "Exports mongodb to mysql. More later."
7
+ gemspec.email = "joshua.graham@grahamis.com"
8
+ gemspec.homepage = "http://github.com/deltiscere/squealer/"
9
+ gemspec.authors = ["Josh Graham", "Durran Jordan"]
10
+ gem.add_dependency('mysql', '>= 2.8.1')
11
+ gem.add_dependency('mongo', '>= 0.18.3')
12
+ end
13
+ rescue LoadError
14
+ puts "Jeweler not available. Install it with: gem install jeweler"
15
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,3 @@
1
+ --colour
2
+ --format nested
3
+ --drb
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ require 'spork'
3
+
4
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+
7
+ require 'squealer'
@@ -0,0 +1,41 @@
1
+ require 'mysql'
2
+ require 'mongo'
3
+ require 'spec_helper'
4
+
5
+ describe Squealer::Database do
6
+
7
+ before(:all) do
8
+ @db_name = "test_export_#{object_id}"
9
+ create_test_db(@db_name)
10
+ end
11
+
12
+ after(:all) do
13
+ drop_test_db(@db_name)
14
+ end
15
+
16
+ it "is a singleton" do
17
+ Squealer::Database.respond_to?(:instance).should be_true
18
+ end
19
+
20
+ it "takes an import database" do
21
+ Squealer::Database.instance.import_from('localhost', 27017, @db_name)
22
+ Squealer::Database.instance.import.should be_a_kind_of(Mongo::DB)
23
+ end
24
+
25
+ it "takes an export database" do
26
+ Squealer::Database.instance.export_to('localhost', 'root', '', @db_name)
27
+ Squealer::Database.instance.export.should be_a_kind_of(Mysql)
28
+ end
29
+
30
+ private
31
+
32
+ def create_test_db(name)
33
+ @my = Mysql.connect('localhost', 'root')
34
+ @my.query("create database #{name}")
35
+ end
36
+
37
+ def drop_test_db(name)
38
+ @my.query("drop database #{name}")
39
+ @my.close
40
+ end
41
+ end
@@ -0,0 +1,28 @@
1
+ require "spec_helper"
2
+
3
+ describe Hash do
4
+
5
+ describe "#method_missing" do
6
+
7
+ it "treats it as a hash key lookup" do
8
+ { "name" => "Josh" }.name.should == "Josh"
9
+ end
10
+
11
+ context "with args" do
12
+
13
+ it "treats it normally" do
14
+ lambda { { "name" => "Josh" }.name(nil) }.should raise_error(NoMethodError)
15
+ end
16
+
17
+ end
18
+
19
+ context "with block" do
20
+
21
+ it "treats it normally" do
22
+ lambda { { "name" => "Josh" }.name {nil} }.should raise_error(NoMethodError)
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,113 @@
1
+ require 'spec_helper'
2
+
3
+ describe NilClass do
4
+
5
+ describe "#each" do
6
+ it "returns an empty array" do
7
+ nil.each.should == [] # because mongo is schema-less
8
+ end
9
+ end
10
+ end
11
+
12
+ describe Object do
13
+
14
+ describe "#target" do
15
+
16
+ it "has been defined" do
17
+ Object.new.respond_to?(:target).should be_true
18
+ end
19
+
20
+ it "invokes Squealer::Target.new" do
21
+ Squealer::Target.should_receive(:new)
22
+ target(:test_table, 1) { nil }
23
+ end
24
+
25
+ it "uses the export database connection" do
26
+ mock_mysql
27
+ target(:test_table, 1) { nil }
28
+ end
29
+
30
+ end
31
+
32
+ describe "#assign" do
33
+
34
+ it "has been defined" do
35
+ Object.new.respond_to?(:assign).should be_true
36
+ end
37
+
38
+ it "invokes assign on the target it is immediately nested within" do
39
+ mock_mysql
40
+ target(:test_table, 1) do |target1|
41
+ target1.should_receive(:assign)
42
+ assign(:colA) { 42 }
43
+
44
+ target(:test_table_2, 1) do |target2|
45
+ target2.should_receive(:assign)
46
+ assign(:colspeak) { 1984 }
47
+ end
48
+ end
49
+ end
50
+
51
+ end
52
+
53
+ describe "#import" do
54
+
55
+ it "has been defined" do
56
+ Object.new.respond_to?(:import).should be_true
57
+ end
58
+
59
+ context "with a single argument" do
60
+
61
+ it "invokes Database.import_from" do
62
+ Squealer::Database.instance.should_receive(:import_from)
63
+ import('test_import')
64
+ end
65
+
66
+ end
67
+
68
+ context "with no argment" do
69
+
70
+ it "invokes Database.import" do
71
+ Squealer::Database.instance.should_receive(:import)
72
+ import
73
+ end
74
+
75
+ end
76
+
77
+ end
78
+
79
+ describe "#export" do
80
+
81
+ it "has been defined" do
82
+ Object.new.respond_to?(:export).should be_true
83
+ end
84
+
85
+ context "with a single argument" do
86
+
87
+ it "invokes Database.export_to" do
88
+ Squealer::Database.instance.should_receive(:export_to)
89
+ export('test_export')
90
+ end
91
+
92
+ end
93
+
94
+ context "with no argment" do
95
+
96
+ it "invokes Database.export" do
97
+ Squealer::Database.instance.should_receive(:export)
98
+ export
99
+ end
100
+
101
+ end
102
+
103
+ end
104
+
105
+ def mock_mysql
106
+ my = mock(Mysql)
107
+ st = mock(Mysql::Stmt)
108
+ Squealer::Database.instance.should_receive(:export).at_least(:once).and_return(my)
109
+ my.should_receive(:prepare).at_least(:once).and_return(st)
110
+ st.should_receive(:execute).at_least(:once)
111
+ end
112
+
113
+ end
@@ -0,0 +1,135 @@
1
+ require 'spec_helper'
2
+
3
+ describe Squealer::Target do
4
+ let(:export_dbc) { mock(Mysql) }
5
+ let(:table_name) { :test_table }
6
+ let(:row_id) { 0 }
7
+
8
+ before(:each) do
9
+ Squealer::Database.instance.should_receive(:export).at_least(:once).and_return(export_dbc)
10
+ st = mock(Mysql::Stmt)
11
+ export_dbc.should_receive(:prepare).at_least(:once).and_return(st)
12
+ st.should_receive(:execute).at_least(:once)
13
+ end
14
+
15
+ it "sends the sql to the export database" do
16
+ Squealer::Target.new(export_dbc, table_name, row_id) { nil }
17
+ end
18
+
19
+ describe "#target" do
20
+
21
+ it "pushes itself onto the targets stack when starting" do
22
+ @target1 = nil
23
+ @target2 = nil
24
+ target1 = Squealer::Target.new(export_dbc, table_name, row_id) do
25
+ @target1 = Squealer::Target.current
26
+ Squealer::Target.new(export_dbc, "#{table_name}_2", row_id) do
27
+ @target2 = Squealer::Target.current
28
+ @target2.should_not == @target1
29
+ end
30
+ end
31
+ target1.should === @target1
32
+ end
33
+
34
+ it "pops itself off the targets stack when finished" do
35
+ Squealer::Target.new(export_dbc, table_name, row_id) { nil }
36
+ Squealer::Target.current.should be_nil
37
+ end
38
+
39
+ context "generates SQL command strings" do
40
+
41
+ let(:target) { Squealer::Target.new(export_dbc, table_name, row_id) { nil } }
42
+
43
+ it "targets the table" do
44
+ target.sql.should =~ /^INSERT #{table_name} /
45
+ end
46
+
47
+ it "uses an INSERT ... ON DUPLICATE KEY UPDATE statement" do
48
+ target.sql.should =~ /^INSERT .* ON DUPLICATE KEY UPDATE /
49
+ end
50
+
51
+ it "includes the primary key name in the INSERT" do
52
+ target.sql.should =~ / \(id\) VALUES/
53
+ end
54
+
55
+ it "includes the primary key value in the INSERT" do
56
+ # target.sql.should =~ / VALUES \('#{row_id}'\) /
57
+ target.sql.should =~ / VALUES \(\?\) /
58
+ end
59
+
60
+ end
61
+
62
+ context "with inner block" do
63
+
64
+ it "yields inner blocks" do
65
+ block_done = false
66
+ target = Squealer::Target.new(export_dbc, table_name, row_id) { block_done = true }
67
+ block_done.should be_true
68
+ end
69
+
70
+ it "yields inner blocks first" do
71
+ Squealer::Target.new(export_dbc, table_name, row_id) { Squealer::Target.current.sql.should be_empty }
72
+ end
73
+
74
+ it "yields inner blocks first and they can assign to this target" do
75
+ target = Squealer::Target.new(export_dbc, table_name, row_id) { Squealer::Target.current.assign(:colA) { 42 } }
76
+ target.sql.should =~ /colA/
77
+ # target.sql.should =~ /42/
78
+ target.sql.should =~ /\?/
79
+ end
80
+
81
+ context "with 2 columns" do
82
+
83
+ let(:value_1) { 42 }
84
+ let(:target) do
85
+ Squealer::Target.new(export_dbc, table_name, row_id) { Squealer::Target.current.assign(:colA) { value_1 } }
86
+ end
87
+
88
+ it "includes the column name in the INSERT" do
89
+ target.sql.should =~ /\(id,colA\) VALUES/
90
+ end
91
+
92
+ it "includes the column value in the INSERT" do
93
+ # target.sql.should =~ /VALUES \('#{row_id}','#{value_1}'\)/
94
+ target.sql.should =~ /VALUES \(\?,\?\)/
95
+ end
96
+
97
+ it "includes the column name and value in the UPDATE" do
98
+ # target.sql.should =~ /UPDATE colA='#{value_1}'/
99
+ target.sql.should =~ /UPDATE colA=\?/
100
+ end
101
+
102
+ end
103
+
104
+ context "with 3 columns" do
105
+
106
+ let(:value_1) { 42 }
107
+ let(:value_2) { 'foobar' }
108
+ let(:target) do
109
+ Squealer::Target.new(export_dbc, table_name, row_id) do
110
+ Squealer::Target.current.assign(:colA) { value_1 }
111
+ Squealer::Target.current.assign(:colB) { value_2 }
112
+ end
113
+ end
114
+
115
+ it "includes the column names in the INSERT" do
116
+ target.sql.should =~ /\(id,colA,colB\) VALUES/
117
+ end
118
+
119
+ it "includes the column values in the INSERT" do
120
+ # target.sql.should =~ /VALUES \('#{row_id}','#{value_1}','#{value_2}'\)/
121
+ target.sql.should =~ /VALUES \(\?,\?,\?\)/
122
+ end
123
+
124
+ it "includes the column names and values in the UPDATE" do
125
+ # target.sql.should =~ /UPDATE colA='#{value_1}',colB='#{value_2}'/
126
+ target.sql.should =~ /UPDATE colA=\?,colB=\?/
127
+ end
128
+
129
+ end
130
+
131
+ end
132
+
133
+ end
134
+
135
+ end
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ describe Time do
4
+
5
+ describe "#to_s" do
6
+ it "uses a MySQL compliant format" do
7
+ Time.gm(2000,"Jan",31).to_s.should == "2000-01-31 00:00:00 UTC"
8
+ end
9
+ end
10
+ end
data/squealer.gemspec ADDED
@@ -0,0 +1,71 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{squealer}
8
+ s.version = "1.0.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Josh Graham", "Durran Jordan"]
12
+ s.date = %q{2010-03-23}
13
+ s.description = %q{Exports mongodb to mysql. More later.}
14
+ s.email = %q{joshua.graham@grahamis.com}
15
+ s.extra_rdoc_files = [
16
+ "README.md"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ ".watchr",
21
+ "README.md",
22
+ "Rakefile",
23
+ "VERSION",
24
+ "lib/example_squeal.rb",
25
+ "lib/squealer.rb",
26
+ "lib/squealer/database.rb",
27
+ "lib/squealer/hash.rb",
28
+ "lib/squealer/object.rb",
29
+ "lib/squealer/target.rb",
30
+ "lib/squealer/time.rb",
31
+ "lib/tasks/jeweler.rake",
32
+ "spec/spec.opts",
33
+ "spec/spec_helper.rb",
34
+ "spec/squealer/database_spec.rb",
35
+ "spec/squealer/hash_spec.rb",
36
+ "spec/squealer/object_spec.rb",
37
+ "spec/squealer/target_spec.rb",
38
+ "spec/squealer/time_spec.rb",
39
+ "squealer.gemspec"
40
+ ]
41
+ s.homepage = %q{http://github.com/delitescere/squealer/}
42
+ s.rdoc_options = ["--charset=UTF-8"]
43
+ s.require_paths = ["lib"]
44
+ s.rubygems_version = %q{1.3.6}
45
+ s.summary = %q{Document-oriented to Relational database exporter}
46
+ s.test_files = [
47
+ "spec/spec_helper.rb",
48
+ "spec/squealer/database_spec.rb",
49
+ "spec/squealer/hash_spec.rb",
50
+ "spec/squealer/object_spec.rb",
51
+ "spec/squealer/target_spec.rb",
52
+ "spec/squealer/time_spec.rb"
53
+ ]
54
+
55
+ if s.respond_to? :specification_version then
56
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
57
+ s.specification_version = 3
58
+
59
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
60
+ s.add_runtime_dependency(%q<mysql>, [">= 2.8.1"])
61
+ s.add_runtime_dependency(%q<mongo>, [">= 0.18.3"])
62
+ else
63
+ s.add_dependency(%q<mysql>, [">= 2.8.1"])
64
+ s.add_dependency(%q<mongo>, [">= 0.18.3"])
65
+ end
66
+ else
67
+ s.add_dependency(%q<mysql>, [">= 2.8.1"])
68
+ s.add_dependency(%q<mongo>, [">= 0.18.3"])
69
+ end
70
+ end
71
+
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: squealer
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 0
8
+ - 0
9
+ version: 1.0.0
10
+ platform: ruby
11
+ authors:
12
+ - Josh Graham
13
+ - Durran Jordan
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-03-23 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: mysql
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 2
30
+ - 8
31
+ - 1
32
+ version: 2.8.1
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: mongo
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ segments:
43
+ - 0
44
+ - 18
45
+ - 3
46
+ version: 0.18.3
47
+ type: :runtime
48
+ version_requirements: *id002
49
+ description: Exports mongodb to mysql. More later.
50
+ email: joshua.graham@grahamis.com
51
+ executables: []
52
+
53
+ extensions: []
54
+
55
+ extra_rdoc_files:
56
+ - README.md
57
+ files:
58
+ - .gitignore
59
+ - .watchr
60
+ - README.md
61
+ - Rakefile
62
+ - VERSION
63
+ - lib/example_squeal.rb
64
+ - lib/squealer.rb
65
+ - lib/squealer/database.rb
66
+ - lib/squealer/hash.rb
67
+ - lib/squealer/object.rb
68
+ - lib/squealer/target.rb
69
+ - lib/squealer/time.rb
70
+ - lib/tasks/jeweler.rake
71
+ - spec/spec.opts
72
+ - spec/spec_helper.rb
73
+ - spec/squealer/database_spec.rb
74
+ - spec/squealer/hash_spec.rb
75
+ - spec/squealer/object_spec.rb
76
+ - spec/squealer/target_spec.rb
77
+ - spec/squealer/time_spec.rb
78
+ - squealer.gemspec
79
+ has_rdoc: true
80
+ homepage: http://github.com/delitescere/squealer/
81
+ licenses: []
82
+
83
+ post_install_message:
84
+ rdoc_options:
85
+ - --charset=UTF-8
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ segments:
93
+ - 0
94
+ version: "0"
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ segments:
100
+ - 0
101
+ version: "0"
102
+ requirements: []
103
+
104
+ rubyforge_project:
105
+ rubygems_version: 1.3.6
106
+ signing_key:
107
+ specification_version: 3
108
+ summary: Document-oriented to Relational database exporter
109
+ test_files:
110
+ - spec/spec_helper.rb
111
+ - spec/squealer/database_spec.rb
112
+ - spec/squealer/hash_spec.rb
113
+ - spec/squealer/object_spec.rb
114
+ - spec/squealer/target_spec.rb
115
+ - spec/squealer/time_spec.rb