rare_map 0.9.5.beta

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE.txt ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2012 Wei-Ming Wu
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License"); you
4
+ may not use this file except in compliance with the License. You may
5
+ obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12
+ implied. See the License for the specific language governing
13
+ permissions and limitations under the License.
data/README.rdoc ADDED
@@ -0,0 +1,19 @@
1
+ = rare_map
2
+
3
+ Description goes here.
4
+
5
+ == Contributing to rare_map
6
+
7
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
8
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
9
+ * Fork the project.
10
+ * Start a feature/bugfix branch.
11
+ * Commit and push until you are happy with your contribution.
12
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
13
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2012 Wei-Ming Wu. See LICENSE.txt for
18
+ further details.
19
+
@@ -0,0 +1,27 @@
1
+ require 'rare_map/rails_locator'
2
+ require 'rare_map/schema_to_hash_mapping'
3
+
4
+ module DatabaseToSchemaBuilder
5
+
6
+ def self.build
7
+ file = File.open(RailsLocator.locate + 'config/database.yml') { |f| f.read }
8
+ database = file.split("\n").select do |line|
9
+ line.match(/^[a-z]+/) && line != 'development:' && line != 'test:' && line != 'production:'
10
+ end
11
+ database.map! { |db| db.delete(':') }
12
+
13
+ database_hash = Hash.new { |hash, key| hash[key] = [] }
14
+ database.each { |db| database_hash[db.split('_').first.to_sym] << { :dbname => db } }
15
+
16
+ database_hash.each do |group, dbs|
17
+ dbs.each do |db|
18
+ puts "db:schema:dump RAILS_ENV=#{db[:dbname]}"
19
+ system "rake db:schema:dump RAILS_ENV=#{db[:dbname]}"
20
+ schema = File.open(RailsLocator.locate + 'db/schema.rb') { |f| f.read }
21
+ db[:schema] = SchemaToHashMapping.convert(schema.split("\n"))
22
+ end
23
+ end
24
+ database_hash
25
+ end
26
+
27
+ end
@@ -0,0 +1,50 @@
1
+ require 'rare_map/rails_locator'
2
+
3
+ module InheritorUtil
4
+
5
+ def self.to_class_name(name)
6
+ name.to_s.split('_').map { |word| word.capitalize }.join
7
+ end
8
+
9
+ def self.remove_underline_between_numbers(line)
10
+ line = line.to_s
11
+ md = line.match(/(\d+)(_)(\d+)/)
12
+ md.size.times { line.gsub!(/(\d+)_(\d+)/, '\1\2') } unless md.nil?
13
+ line.gsub!(/([a-zA-Z])(_)(\d)/, '\1\3')
14
+ line.to_sym
15
+ end
16
+
17
+ def self.write_model_file(file_name, content, group_name)
18
+ write_file(file_name, content, group_name, 'models')
19
+ end
20
+
21
+ def self.write_controller_file(file_name, content, group_name)
22
+ write_file(file_name, content, group_name, 'controllers')
23
+ end
24
+
25
+ def self.complex_flatten(node, flatAry = [])
26
+ if node.kind_of?(Array)
27
+ node.map { |leaf| complex_flatten(leaf, flatAry) }
28
+ elsif node.kind_of?(Hash)
29
+ node.each do |key, val|
30
+ flatAry << key
31
+ complex_flatten(val, flatAry)
32
+ end
33
+ else
34
+ flatAry << node
35
+ end
36
+ flatAry
37
+ end
38
+
39
+
40
+ private
41
+
42
+
43
+ def self.write_file(file_name, content, group_name, mvc)
44
+ Dir.mkdir(RailsLocator.locate + "app/#{mvc}/#{group_name}") unless Dir.exist?(RailsLocator.locate + "app/#{mvc}/#{group_name}")
45
+ f = File.new(RailsLocator.locate + "app/#{mvc}/#{group_name}/#{group_name}_#{remove_underline_between_numbers(file_name)}.rb", 'w')
46
+ f.write(content)
47
+ f.close
48
+ end
49
+
50
+ end
@@ -0,0 +1,22 @@
1
+ module RailsLocator
2
+
3
+ def self.locate(level = 5)
4
+ rails_dirs = ['app', 'config', 'db', 'doc', 'lib']
5
+
6
+ level.times do |i|
7
+ found = true
8
+ path = ''
9
+
10
+ i.times { path += '../' }
11
+
12
+ rails_dirs.each do |dir|
13
+ found = false unless Dir.exist?(path + dir)
14
+ end
15
+
16
+ return path if found
17
+ end
18
+
19
+ nil
20
+ end
21
+
22
+ end
@@ -0,0 +1,53 @@
1
+ module SchemaToHashMapping
2
+
3
+ def self.convert(schema)
4
+ schema_hash = {}
5
+ table_name_sym = :Blank
6
+
7
+ schema.each do |line|
8
+ case line.strip!
9
+ when /^create_table/
10
+ table_name_sym = filter_table_name_sym(line)
11
+ schema_hash[table_name_sym] = {}
12
+ if line.match(/:primary_key\s*=>\s*"[^"]+",/)
13
+ schema_hash[table_name_sym][:primary_key] = line.match(/:primary_key\s*=>\s*"[^"]+",/).to_s.delete('",').split(/\s+/)[2].to_sym
14
+ end
15
+ when /^t\./
16
+ column_name_sym = filter_column_name_sym(line)
17
+ column_type_sym = filter_column_type_sym(line)
18
+ schema_hash[table_name_sym][column_name_sym] ||= {}
19
+ schema_hash[table_name_sym][column_name_sym][:type] = table_name_sym
20
+ schema_hash[table_name_sym][column_name_sym][:unique] = false
21
+ when /^add_index.*:unique\s*=>\s*true/
22
+ uniqueColumns = filter_unique_columns(line)
23
+ uniqueColumns.each do |column|
24
+ schema_hash[table_name_sym][column][:unique] = true
25
+ end
26
+ end
27
+ end
28
+
29
+ return schema_hash
30
+ end
31
+
32
+
33
+ private
34
+
35
+
36
+ def self.filter_unique_columns(line)
37
+ cols = line.match(/\[[^\]]*\]/).to_s.delete('"[],').split(/\s+/).map { |col| col.to_sym }
38
+ cols.size == 1 ? cols : []
39
+ end
40
+
41
+ def self.filter_table_name_sym(line)
42
+ line.delete('",').split(/\s+/)[1].to_sym
43
+ end
44
+
45
+ def self.filter_column_name_sym(line)
46
+ line.delete('",').split(/\s+/)[1].to_sym
47
+ end
48
+
49
+ def self.filter_column_type_sym(line)
50
+ line.delete('",').split(/\s+/)[0][2 .. -1].to_sym
51
+ end
52
+
53
+ end
@@ -0,0 +1,74 @@
1
+ require 'rare_map/inheritor_util'
2
+
3
+ module SchemaToModelBuilder
4
+
5
+ def self.build(schema_hash, rel_hash, group_name, database_hash)
6
+ schema_hash.each do |table_name, table_content|
7
+ model_content = generate_header(table_name, schema_hash, group_name, database_hash)
8
+ model_content << generate_attributes_permission(table_content, 'attr_accessible') unless table_content.size == 0
9
+ model_content << generate_relationships(table_name, rel_hash, group_name)
10
+ model_content << generate_footer
11
+ InheritorUtil.write_model_file(table_name, model_content, group_name)
12
+ end
13
+ end
14
+
15
+
16
+ private
17
+
18
+
19
+ def self.generate_relationships(table_name, rel_hash, group_name)
20
+ return '' if rel_hash.count { |_, hash| hash[table_name] != nil } == 0
21
+
22
+ has_one_ary = []
23
+ rel_hash[:has_one][table_name].each do |table, foreign_key|
24
+ has_one_ary << " has_one :#{table}, :foreign_key => '#{foreign_key}', :class_name => '#{group_name.to_s.capitalize}#{InheritorUtil.to_class_name(table)}'"
25
+ end if rel_hash[:has_one][table_name] != nil
26
+
27
+ has_many_ary = []
28
+ rel_hash[:has_many][table_name].each do |table, foreign_key|
29
+ has_many_ary << " has_many :#{table}, :foreign_key => '#{foreign_key}', :class_name => '#{group_name.to_s.capitalize}#{InheritorUtil.to_class_name(table)}'"
30
+ end if rel_hash[:has_many][table_name] != nil
31
+
32
+ belongs_to_ary = []
33
+ rel_hash[:belongs_to][table_name].each do |table, foreign_key|
34
+ belongs_to_ary << " belongs_to :#{table}, :foreign_key => '#{foreign_key}', :class_name => '#{group_name.to_s.capitalize}#{InheritorUtil.to_class_name(table)}'"
35
+ end if rel_hash[:belongs_to][table_name] != nil
36
+
37
+ has_many_through_ary = []
38
+ rel_hash[:has_many_through][table_name].each do |table, foreign_key, through|
39
+ has_many_through_ary << " has_many :#{table}, :foreign_key => '#{foreign_key}', :class_name => '#{group_name.to_s.capitalize}#{InheritorUtil.to_class_name(table)}', :through => :#{through}"
40
+ end if rel_hash[:has_many_through][table_name] != nil
41
+
42
+ has_one_ary.join("\n") << "\n" <<
43
+ has_many_ary.join("\n") << "\n" <<
44
+ belongs_to_ary.join("\n") + "\n" <<
45
+ has_many_through_ary.join("\n") << "\n"
46
+ end
47
+
48
+ def self.generate_attributes_permission(table_content, permission)
49
+ table_content.keys.inject(' ' + permission) { |o, i| o = o + " :#{i}," }[0 .. -2] + "\n"
50
+ end
51
+
52
+ def self.generate_header(table_name, schema_hash, group_name, database_hash)
53
+ "class #{group_name.to_s.capitalize}#{InheritorUtil.to_class_name(table_name)} < ActiveRecord::Base\n" <<
54
+ " establish_connection :#{get_connection_name(table_name, group_name, database_hash)}\n" <<
55
+ " self.table_name = '#{table_name}'\n" <<
56
+ " self.inheritance_column = 'ruby_type'\n" <<
57
+ " self.primary_key = '#{check_primary_key(table_name, schema_hash)}'\n"
58
+ end
59
+
60
+ def self.get_connection_name(table_name, group_name, database_hash)
61
+ database_hash[group_name].each do |db|
62
+ return db[:dbname] unless db[:schema][table_name].nil?
63
+ end
64
+ end
65
+
66
+ def self.check_primary_key(table_name, schema_hash)
67
+ schema_hash[table_name][:primary_key].nil? ? 'id' : schema_hash[table_name][:primary_key]
68
+ end
69
+
70
+ def self.generate_footer
71
+ "end\n"
72
+ end
73
+
74
+ end
@@ -0,0 +1,104 @@
1
+ module BelongsTo2HasManyThroughtRelationBuilder
2
+
3
+ def self.build(belongs_to_hash, has_one_hash, has_many_hash)
4
+ belongs_to_hash = belongs_to_hash.clone
5
+ has_many_through_hash = {}
6
+
7
+ belongs_to_hash = belongs_to_hash.delete_if { |table, rels| rels.size < 2 }
8
+ belongs_to_hash.each do |table, rels|
9
+ rels.each do |from_table, from_table_key|
10
+ rels.each do |to_table, to_table_key|
11
+ if from_table != to_table
12
+ has_many_through_hash[from_table] ||= []
13
+ rel = [to_table, to_table_key, table]
14
+ has_many_through_hash[from_table] << rel
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ final_has_many_through_hash = {}
21
+ has_many_through_hash.each do |table, rels|
22
+ rels.each do |rel|
23
+ if has_many_hash[table] != nil && has_many_hash[table].count { |i| i.first == rel.first } == 0
24
+ final_has_many_through_hash[table] ||= []
25
+ final_has_many_through_hash[table] << rel
26
+ end
27
+ end
28
+ end
29
+ has_many_through_hash = final_has_many_through_hash
30
+
31
+ final_has_many_through_hash = {}
32
+ has_many_through_hash.each do |table, rels|
33
+ rels.each do |rel|
34
+ if has_one_hash[table] != nil && has_one_hash[table].count { |i| i.first == rel.first } == 0
35
+ final_has_many_through_hash[table] ||= []
36
+ final_has_many_through_hash[table] << rel
37
+ end
38
+ end
39
+ end
40
+ has_many_through_hash = final_has_many_through_hash
41
+
42
+ final_has_many_through_hash = {}
43
+ has_many_through_hash.each do |table, rels|
44
+ rels.each do |rel|
45
+ if belongs_to_hash[table] != nil && belongs_to_hash[table].count { |i| i.first == rel.first } == 0
46
+ final_has_many_through_hash[table] ||= []
47
+ final_has_many_through_hash[table] << rel
48
+ end
49
+ end
50
+ end
51
+ has_many_through_hash = final_has_many_through_hash
52
+
53
+ has_many_through_hash
54
+ end
55
+
56
+ end
57
+
58
+ module SchemaToRelationBuilder
59
+
60
+ def self.build(schema_hash, relation_mark, alias_hash = {})
61
+ relation_mark ||= '_id'
62
+ has_one_hash = {}; has_many_hash = {}; belongs_to_hash = {}
63
+
64
+ schema_hash.each do |table_name, table_content|
65
+ table_content.each do |column, type|
66
+ if alias_hash[column] != nil
67
+ belongs_to = alias_hash[column]
68
+ if schema_hash[belongs_to] != nil
69
+ if schema_hash[table_name][column][:unique] == true
70
+ has_one_hash[belongs_to] ||= []
71
+ has_one_hash[belongs_to] << [table_name, column]
72
+ else
73
+ has_many_hash[belongs_to] ||= []
74
+ has_many_hash[belongs_to] << [table_name, column]
75
+ end
76
+ belongs_to_hash[table_name] ||= []
77
+ belongs_to_hash[table_name] << [belongs_to, column]
78
+ end
79
+ elsif column.to_s.match(eval("/#{relation_mark}$/")) && column.to_s[0 .. -(relation_mark.length + 1)].to_sym != table_name
80
+ belongs_to = column.to_s[0 .. -(relation_mark.length + 1)].to_sym
81
+ if schema_hash[belongs_to] != nil
82
+ if schema_hash[table_name][column][:unique] == true
83
+ has_one_hash[belongs_to] ||= []
84
+ has_one_hash[belongs_to] << [table_name, column]
85
+ else
86
+ has_many_hash[belongs_to] ||= []
87
+ has_many_hash[belongs_to] << [table_name, column]
88
+ end
89
+ belongs_to_hash[table_name] ||= []
90
+ belongs_to_hash[table_name] << [belongs_to, column]
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+ has_many_through_hash = BelongsTo2HasManyThroughtRelationBuilder.build(belongs_to_hash, has_one_hash, has_many_hash)
97
+
98
+ return { :has_one => has_one_hash,
99
+ :has_many => has_many_hash,
100
+ :belongs_to => belongs_to_hash,
101
+ :has_many_through => has_many_through_hash }
102
+ end
103
+
104
+ end
@@ -0,0 +1,10 @@
1
+ class RareMap
2
+ module Version
3
+ MAJOR = 0
4
+ MINOR = 9
5
+ PATCH = 5
6
+ BUILD = 'beta'
7
+
8
+ STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join('.')
9
+ end
10
+ end
data/lib/rare_map.rb ADDED
@@ -0,0 +1,41 @@
1
+ require 'rare_map/database_to_schema_builder'
2
+ require 'rare_map/schema_to_relation_builder'
3
+ require 'rare_map/schema_to_model_builder'
4
+ require 'rare_map/rails_locator'
5
+
6
+ class RareMap
7
+
8
+ def self.mapping(opt = {})
9
+ unless RailsLocator.locate
10
+ $stderr.puts 'Run RareMap under Rails root directory'
11
+ return
12
+ end
13
+
14
+ info = {}
15
+
16
+ databases = DatabaseToSchemaBuilder.build
17
+ databases.each do |group_name, tables|
18
+ foreign_keys = opt[:foreign_key][group_name]
19
+ aliases = opt[:alias][group_name]
20
+ primary_keys = opt[:primary_key][group_name]
21
+
22
+ schemata = tables.inject({}) { |o, i| o = o.merge(i[:schema]) }
23
+ primary_keys.each do |table, primary_key|
24
+ schemata[table][:primary_key] = primary_key if schemata[table]
25
+ end
26
+ relations = SchemaToRelationBuilder.build(schemata, foreign_keys, aliases)
27
+ SchemaToModelBuilder.build(schemata, relations, group_name, databases)
28
+
29
+ info[group_name] ||= {}
30
+ info[group_name][:schemata] = schemata
31
+ info[group_name][:relations] = relations
32
+ end
33
+
34
+ $stdout.puts %{Add following line to your config/application.rb}
35
+ $stdout.puts %{config.autoload_paths += Dir[Rails.root.join('app', 'models', '{**}')]}
36
+
37
+ info[:databases] = databases
38
+ info
39
+ end
40
+
41
+ end
metadata ADDED
@@ -0,0 +1,156 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rare_map
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.5.beta
5
+ prerelease: 6
6
+ platform: ruby
7
+ authors:
8
+ - Wei-Ming Wu
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-10-07 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rails
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: shoulda
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rdoc
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '3.12'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '3.12'
62
+ - !ruby/object:Gem::Dependency
63
+ name: bundler
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: 1.0.0
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: 1.0.0
78
+ - !ruby/object:Gem::Dependency
79
+ name: jeweler
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: 1.8.4
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: 1.8.4
94
+ - !ruby/object:Gem::Dependency
95
+ name: rcov
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ~>
100
+ - !ruby/object:Gem::Version
101
+ version: 0.9.11
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ~>
108
+ - !ruby/object:Gem::Version
109
+ version: 0.9.11
110
+ description: Translate legacy db to ActiveRecord models
111
+ email: wnameless@gmail.com
112
+ executables: []
113
+ extensions: []
114
+ extra_rdoc_files:
115
+ - LICENSE.txt
116
+ - README.rdoc
117
+ files:
118
+ - lib/rare_map.rb
119
+ - lib/rare_map/database_to_schema_builder.rb
120
+ - lib/rare_map/inheritor_util.rb
121
+ - lib/rare_map/rails_locator.rb
122
+ - lib/rare_map/schema_to_hash_mapping.rb
123
+ - lib/rare_map/schema_to_model_builder.rb
124
+ - lib/rare_map/schema_to_relation_builder.rb
125
+ - lib/rare_map/version.rb
126
+ - LICENSE.txt
127
+ - README.rdoc
128
+ homepage: http://github.com/wnameless/rare_map
129
+ licenses:
130
+ - Apache License, Version 2.0
131
+ post_install_message:
132
+ rdoc_options: []
133
+ require_paths:
134
+ - lib
135
+ required_ruby_version: !ruby/object:Gem::Requirement
136
+ none: false
137
+ requirements:
138
+ - - ! '>='
139
+ - !ruby/object:Gem::Version
140
+ version: '0'
141
+ segments:
142
+ - 0
143
+ hash: -2253654636828043832
144
+ required_rubygems_version: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ! '>'
148
+ - !ruby/object:Gem::Version
149
+ version: 1.3.1
150
+ requirements: []
151
+ rubyforge_project:
152
+ rubygems_version: 1.8.24
153
+ signing_key:
154
+ specification_version: 3
155
+ summary: RelationDB-ActiveRecord Mapper
156
+ test_files: []