dm-is-reflective 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a4a92f58af6a1c63b6bb445e06fdc573239ef558
4
+ data.tar.gz: 4577c3ed73a122c4ddd09e62c8c0e64802e49540
5
+ SHA512:
6
+ metadata.gz: f271c3864848cfb098e7f7b32887831700617668c001a56f25f0be1a0497d0e488db5f8970ad7e96ee9ab9aecb4fd333b4fa71c70de48afd435929c266751f5c
7
+ data.tar.gz: a139f550d6b69b36ddb824eec2ca59b4ec157d1289d39cdcc31f268a5d50a7abb90abcb1b48a05f7cdb0784edfb31b28440078adaef7f3b721ccb82d5f7e1944
@@ -0,0 +1,15 @@
1
+ before_install:
2
+ - 'git submodule update --init'
3
+ - mysql -e 'create database myapp_test;'
4
+ - psql -c 'create database myapp_test;' -U postgres
5
+
6
+ script: 'ruby -r bundler/setup -S rake test'
7
+
8
+ env:
9
+ - 'RBXOPT=-X19'
10
+
11
+ rvm:
12
+ - 1.9.3
13
+ - 2.0.0
14
+ - rbx-head
15
+ - jruby-head
data/CHANGES.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # CHANGES
2
2
 
3
+ ## dm-is-reflective 1.2.0, 2013-05-14
4
+
5
+ * We got a bunch of internal renaming.
6
+ * Added DataMapper::Resource#to_source.
7
+ * Added an executable which generates sources for you.
8
+ * Fixed MySQL issues with setting up with a hash rather than URI.
9
+ * Fixed SQLite issues without loading dm-migrations.
10
+
3
11
  ## dm-is-reflective 1.1.0, 2013-01-11
4
12
 
5
13
  * The need for dm-migrations is now removed.
data/Gemfile CHANGED
@@ -1,3 +1,7 @@
1
1
 
2
- source 'http://rubygems.org'
2
+ source 'https://rubygems.org'
3
+
3
4
  gemspec
5
+
6
+ gem 'rake'
7
+ gem 'bacon'
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # dm-is-reflective
1
+ # dm-is-reflective [![Build Status](https://secure.travis-ci.org/godfat/dm-is-reflective.png?branch=master)](http://travis-ci.org/godfat/dm-is-reflective)
2
2
 
3
3
  by Lin Jen-Shin ([godfat](http://godfat.org))
4
4
 
@@ -21,99 +21,116 @@ It creates mappings between existing columns and model's properties.
21
21
  ## INSTALLATION:
22
22
 
23
23
  ``` shell
24
- gem install dm-is-reflective
24
+ gem install dm-is-reflective
25
25
  ```
26
26
 
27
27
  ``` ruby
28
- gem 'dm-is-reflective',
29
- :git => 'git://github.com/godfat/dm-is-reflective.git',
30
- :submodules => true
28
+ gem 'dm-is-reflective',
29
+ :git => 'git://github.com/godfat/dm-is-reflective.git',
30
+ :submodules => true
31
31
  ```
32
32
 
33
33
  ## SYNOPSIS:
34
34
 
35
+ ### Generating sources from a DATABASE_URI
36
+
37
+ We also have an executable to generate sources for you.
38
+
39
+ ```
40
+ Usage: dm-is-reflective DATABASE_URI
41
+ -s, --scope SCOPE SCOPE where the models should go (default: Object)
42
+ -o, --output DIRECTORY DIRECTORY where the output goes (default: dm-is-reflective)
43
+ -h, --help Print this message
44
+ -v, --version Print the version
45
+ ```
46
+
47
+ ### API
48
+
35
49
  ``` ruby
36
- require 'dm-is-reflective' # this would require 'dm-core'
37
- dm = DataMapper.setup :default, 'sqlite:db/dev.sqlite3'
38
-
39
- class User
40
- include DataMapper::Resource
41
- is :reflective
42
-
43
- # map all, returning an array of properties indicating fields it mapped
44
- reflect /.*/ # e.g. => [#<Property:#<Class:0x18f89b8>:id>,
45
- # #<Property:#<Class:0x18f89b8>:title>,
46
- # #<Property:#<Class:0x18f89b8>:body>,
47
- # #<Property:#<Class:0x18f89b8>:user_id>]
48
-
49
- # map all (with no argument at all)
50
- reflect
51
-
52
- # mapping for field name ended with _at, and started with salt_
53
- reflect /_at$/, /^salt_/
54
-
55
- # mapping id and email
56
- reflect :id, :email
57
-
58
- # mapping all fields with type String, and id
59
- reflect String, :id
60
-
61
- # mapping login, and all fields with type Integer
62
- reflect :login, Integer
63
- end
64
-
65
- # there's no guarantee of the order in storages array
66
- dm.storages
67
- # => ['users']
68
-
69
- # there's no guarantee of the order in fields array
70
- User.fields
71
- # => [[:created_at, DateTime, {:required => false}],
72
- [:email, String, {:required => false, :length => 255,
73
- :default => 'nospam@nospam.tw'}],
74
- [:id, Serial, {:required => true, :serial => true,
75
- :key => true}],
76
- [:salt_first, String, {:required => false, :length => 50}],
77
- [:salt_second, String, {:required => false, :length => 50}]]
78
-
79
- dm.fields('users').sort_by{ |field| field.first.to_s } ==
80
- User.fields.sort_by{ |field| field.first.to_s }
81
- # => true
82
-
83
- dm.storages_and_fields
84
- # => {'users' => [[:id, Serial, {:required => true,
85
- :serial => true,
86
- :key => true}],
87
- [:email, String, {:required => false,
88
- :default =>
89
- 'nospam@nospam.tw'}],
90
- [:created_at, DateTime, {:required => false}],
91
- [:salt_first, String, {:required => false,
92
- :length => 50}],
93
- [:salt_second, String, {:required => false,
94
- :length => 50}]]}
95
-
96
- # there's no guarantee of the order in returned array
97
- dm.auto_genclass!
98
- # => [DataMapper::Is::Reflective::User,
99
- DataMapper::Is::Reflective::SchemaInfo,
100
- DataMapper::Is::Reflective::Session]
101
-
102
- # you can change the scope of generated models:
103
- dm.auto_genclass! :scope => Object
104
- # => [User, SchemaInfo, Session]
105
-
106
- # you can generate classes for tables you specified only:
107
- dm.auto_genclass! :scope => Object, :storages => /^phpbb_/
108
- # => [PhpbbUser, PhpbbPost, PhpbbConfig]
109
-
110
- # you can generate classes with String too:
111
- dm.auto_genclass! :storages => ['users', 'config'], :scope => Object
112
- # => [User, Config]
113
-
114
- # you can generate a class only:
115
- dm.auto_genclass! :storages => 'users'
116
- # => [DataMapper::Is::Reflective::User]
50
+ require 'dm-is-reflective' # this would require 'dm-core'
51
+ dm = DataMapper.setup :default, 'sqlite::memory:'
52
+
53
+ class User
54
+ include DataMapper::Resource
55
+ is :reflective
56
+
57
+ # map all, returning an array of properties indicating fields it mapped
58
+ reflect /.*/ # e.g. => [#<Property:#<Class:0x18f89b8>:id>,
59
+ # #<Property:#<Class:0x18f89b8>:title>,
60
+ # #<Property:#<Class:0x18f89b8>:body>,
61
+ # #<Property:#<Class:0x18f89b8>:user_id>]
62
+
63
+ # map all (with no argument at all)
64
+ reflect
65
+
66
+ # mapping for field name ended with _at, and started with salt_
67
+ reflect /_at$/, /^salt_/
68
+
69
+ # mapping id and email
70
+ reflect :id, :email
71
+
72
+ # mapping all fields with type String, and id
73
+ reflect String, :id
74
+
75
+ # mapping login, and all fields with type Integer
76
+ reflect :login, Integer
77
+ end
78
+
79
+ # there's no guarantee of the order in storages array
80
+ dm.storages
81
+ # => ['users']
82
+
83
+ # there's no guarantee of the order in fields array
84
+ User.fields
85
+ # => [[:created_at, DateTime, {:required => false}],
86
+ [:email, String, {:required => false, :length => 255,
87
+ :default => 'nospam@nospam.tw'}],
88
+ [:id, Serial, {:required => true, :serial => true,
89
+ :key => true}],
90
+ [:salt_first, String, {:required => false, :length => 50}],
91
+ [:salt_second, String, {:required => false, :length => 50}]]
92
+
93
+ dm.fields('users').sort_by{ |field| field.first.to_s } ==
94
+ User.fields.sort_by{ |field| field.first.to_s }
95
+ # => true
96
+
97
+ dm.storages_and_fields
98
+ # => {'users' => [[:id, Serial, {:required => true,
99
+ :serial => true,
100
+ :key => true}],
101
+ [:email, String, {:required => false,
102
+ :default =>
103
+ 'nospam@nospam.tw'}],
104
+ [:created_at, DateTime, {:required => false}],
105
+ [:salt_first, String, {:required => false,
106
+ :length => 50}],
107
+ [:salt_second, String, {:required => false,
108
+ :length => 50}]]}
109
+
110
+ # there's no guarantee of the order in returned array
111
+ dm.auto_genclass!
112
+ # => [DataMapper::Is::Reflective::User,
113
+ DataMapper::Is::Reflective::SchemaInfo,
114
+ DataMapper::Is::Reflective::Session]
115
+
116
+ # you can change the scope of generated models:
117
+ dm.auto_genclass! :scope => Object
118
+ # => [User, SchemaInfo, Session]
119
+
120
+ # you can generate classes for tables you specified only:
121
+ dm.auto_genclass! :scope => Object, :storages => /^phpbb_/
122
+ # => [PhpbbUser, PhpbbPost, PhpbbConfig]
123
+
124
+ # you can generate classes with String too:
125
+ dm.auto_genclass! :storages => ['users', 'config'], :scope => Object
126
+ # => [User, Config]
127
+
128
+ # you can generate a class only:
129
+ dm.auto_genclass! :storages => 'users'
130
+ # => [DataMapper::Is::Reflective::User]
131
+
132
+ # you can also generate the source from models:
133
+ puts User.to_source
117
134
  ```
118
135
 
119
136
  ## CONTRIBUTORS:
data/Rakefile CHANGED
@@ -15,7 +15,7 @@ task 'gem:spec' do
15
15
  Gemgem.spec = Gemgem.create do |s|
16
16
  require 'dm-is-reflective/version'
17
17
  s.name = 'dm-is-reflective'
18
- s.version = DataMapper::Is::Reflective::VERSION
18
+ s.version = DmIsReflective::VERSION
19
19
 
20
20
  %w[dm-core dm-do-adapter].each{ |g| s.add_runtime_dependency(g) }
21
21
  %w[dm-migrations
@@ -26,16 +26,3 @@ task 'gem:spec' do
26
26
 
27
27
  Gemgem.write
28
28
  end
29
-
30
- desc 'auto_migrate database'
31
- task 'auto_migrate' do
32
- require 'dm-migrations'
33
- require './test/abstract'
34
- require './test/test_dm-is-reflective'
35
- include Abstract
36
- [:SqliteTest, :PostgresTest, :MysqlTest].each do |db|
37
- next unless Object.const_defined?(db)
38
- Object.const_get(db).setup_data_mapper
39
- [User, Comment, SuperUser].each(&:auto_migrate!)
40
- end
41
- end
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'dm-is-reflective/runner'
4
+ DmIsReflective::Runner.run
@@ -2,43 +2,55 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "dm-is-reflective"
5
- s.version = "1.1.0"
5
+ s.version = "1.2.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Lin Jen-Shin (godfat)"]
9
- s.date = "2013-01-11"
9
+ s.date = "2013-05-14"
10
10
  s.description = "DataMapper plugin that helps you manipulate an existing database.\nIt creates mappings between existing columns and model's properties."
11
11
  s.email = ["godfat (XD) godfat.org"]
12
+ s.executables = ["dm-is-reflective"]
12
13
  s.files = [
13
14
  ".gitignore",
14
15
  ".gitmodules",
16
+ ".travis.yml",
15
17
  "CHANGES.md",
16
18
  "Gemfile",
17
19
  "LICENSE",
18
20
  "README.md",
19
21
  "Rakefile",
20
22
  "TODO.md",
23
+ "bin/dm-is-reflective",
21
24
  "dm-is-reflective.gemspec",
22
25
  "lib/dm-is-reflective.rb",
23
- "lib/dm-is-reflective/is/adapters/data_objects_adapter.rb",
24
- "lib/dm-is-reflective/is/adapters/mysql_adapter.rb",
25
- "lib/dm-is-reflective/is/adapters/postgres_adapter.rb",
26
- "lib/dm-is-reflective/is/adapters/sqlite_adapter.rb",
27
- "lib/dm-is-reflective/is/reflective.rb",
26
+ "lib/dm-is-reflective/adapters/data_objects_adapter.rb",
27
+ "lib/dm-is-reflective/adapters/mysql_adapter.rb",
28
+ "lib/dm-is-reflective/adapters/postgres_adapter.rb",
29
+ "lib/dm-is-reflective/adapters/sqlite_adapter.rb",
30
+ "lib/dm-is-reflective/reflective.rb",
31
+ "lib/dm-is-reflective/runner.rb",
32
+ "lib/dm-is-reflective/test.rb",
28
33
  "lib/dm-is-reflective/version.rb",
29
34
  "task/.gitignore",
30
35
  "task/gemgem.rb",
31
- "test/abstract.rb",
32
36
  "test/setup_db.sh",
33
- "test/test_dm-is-reflective.rb"]
37
+ "test/test_mysql.rb",
38
+ "test/test_postgres.rb",
39
+ "test/test_sqlite.rb",
40
+ "test/test_to_source.rb"]
34
41
  s.homepage = "https://github.com/godfat/dm-is-reflective"
42
+ s.licenses = ["Apache License 2.0"]
35
43
  s.require_paths = ["lib"]
36
- s.rubygems_version = "1.8.23"
44
+ s.rubygems_version = "2.0.3"
37
45
  s.summary = "DataMapper plugin that helps you manipulate an existing database."
38
- s.test_files = ["test/test_dm-is-reflective.rb"]
46
+ s.test_files = [
47
+ "test/test_mysql.rb",
48
+ "test/test_postgres.rb",
49
+ "test/test_sqlite.rb",
50
+ "test/test_to_source.rb"]
39
51
 
40
52
  if s.respond_to? :specification_version then
41
- s.specification_version = 3
53
+ s.specification_version = 4
42
54
 
43
55
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
44
56
  s.add_runtime_dependency(%q<dm-core>, [">= 0"])
@@ -1,12 +1,11 @@
1
1
 
2
- gem 'dm-core', '>=1.0.0'
3
2
  require 'dm-core'
4
3
  require 'dm-do-adapter'
5
4
 
6
- require 'dm-is-reflective/is/reflective'
7
- require 'dm-is-reflective/is/adapters/data_objects_adapter'
5
+ require 'dm-is-reflective/reflective'
6
+ require 'dm-is-reflective/adapters/data_objects_adapter'
8
7
 
9
- DataMapper::Model.append_extensions(DataMapper::Is::Reflective)
8
+ DataMapper::Model.append_extensions(DmIsReflective)
10
9
 
11
10
  DataMapper::Adapters::DataObjectsAdapter.__send__(:include,
12
- DataMapper::Is::Reflective::DataObjectsAdapter)
11
+ DmIsReflective::DataObjectsAdapter)
@@ -0,0 +1,136 @@
1
+
2
+ module DmIsReflective::DataObjectsAdapter
3
+ include DataMapper
4
+
5
+ # returns all tables' name in the repository.
6
+ # e.g.
7
+ # ['comments', 'users']
8
+ def storages
9
+ reflective_auto_load_adapter_extension
10
+ storages # call the overrided method
11
+ end
12
+
13
+ # returns all fields, with format [[name, type, attrs]]
14
+ # e.g.
15
+ # [[:created_at, DateTime, {:required => false}],
16
+ # [:email, String, {:required => false, :size => 255,
17
+ # :default => 'nospam@nospam.tw'}],
18
+ # [:id, DataMapper::Property::Serial, {:required => true, :serial => true,
19
+ # :key => true}],
20
+ # [:salt_first, String, {:required => false, :size => 50}],
21
+ # [:salt_second, String, {:required => false, :size => 50}]]
22
+ def fields storage
23
+ reflective_query_storage(storage).map{ |field|
24
+ attr = reflective_attributes(field)
25
+ type = reflective_lookup_primitive(reflective_primitive(field))
26
+ pick = if attr[:serial] && type == Integer
27
+ Property::Serial
28
+ else
29
+ type
30
+ end
31
+ [reflective_field_name(field).to_sym, pick, attr]
32
+ }
33
+ end
34
+
35
+ # returns a hash with storage names in keys and
36
+ # corresponded fields in values. e.g.
37
+ # {'users' => [[:id, Integer, {:required => true,
38
+ # :serial => true,
39
+ # :key => true}],
40
+ # [:email, String, {:required => false,
41
+ # :default => 'nospam@nospam.tw'}],
42
+ # [:created_at, DateTime, {:required => false}],
43
+ # [:salt_first, String, {:required => false, :size => 50}],
44
+ # [:salt_second, String, {:required => false, :size => 50}]]}
45
+ # see AbstractAdapter#storages and AbstractAdapter#fields for detail
46
+ def storages_and_fields
47
+ storages.inject({}){ |result, storage|
48
+ result[storage] = fields(storage)
49
+ result
50
+ }
51
+ end
52
+
53
+ # automaticly generate model class(es) and reflect
54
+ # all fields with reflect /.*/ for you.
55
+ # e.g.
56
+ # dm.auto_genclass!
57
+ # # => [DataMapper::Is::Reflective::User,
58
+ # # DataMapper::Is::Reflective::SchemaInfo,
59
+ # # DataMapper::Is::Reflective::Session]
60
+ #
61
+ # you can change the scope of generated models:
62
+ # e.g.
63
+ # dm.auto_genclass! :scope => Object
64
+ # # => [User, SchemaInfo, Session]
65
+ #
66
+ # you can generate classes for tables you specified only:
67
+ # e.g.
68
+ # dm.auto_genclass! :scope => Object, :storages => /^phpbb_/
69
+ # # => [PhpbbUser, PhpbbPost, PhpbbConfig]
70
+ #
71
+ # you can generate classes with String too:
72
+ # e.g.
73
+ # dm.auto_genclass! :storages => ['users', 'config'], :scope => Object
74
+ # # => [User, Config]
75
+ #
76
+ # you can generate a class only:
77
+ # e.g.
78
+ # dm.auto_genclass! :storages => 'users'
79
+ # # => [DataMapper::Is::Reflective::User]
80
+ def auto_genclass! opts = {}
81
+ opts[:scope] ||= DmIsReflective
82
+ opts[:storages] ||= /.*/
83
+ opts[:storages] = [opts[:storages]].flatten
84
+
85
+ storages.map{ |storage|
86
+
87
+ mapped = opts[:storages].each{ |target|
88
+ case target
89
+ when Regexp;
90
+ break storage if storage =~ target
91
+
92
+ when Symbol, String;
93
+ break storage if storage == target.to_s
94
+
95
+ else
96
+ raise ArgumentError.new("invalid argument: #{target.inspect}")
97
+ end
98
+ }
99
+
100
+ reflective_genclass(mapped, opts[:scope]) if mapped.kind_of?(String)
101
+ }.compact
102
+ end
103
+
104
+ private
105
+ def reflective_query_storage storage
106
+ reflective_auto_load_adapter_extension
107
+ reflective_query_storage(storage) # call the overrided method
108
+ end
109
+
110
+ def reflective_genclass storage, scope
111
+ model = Class.new
112
+ model.__send__(:include, Resource)
113
+ model.is(:reflective)
114
+ model.storage_names[:default] = storage
115
+ scope.const_set(Inflector.classify(storage), model)
116
+ model.__send__(:reflect, /.*/)
117
+ model.finalize if model.respond_to?(:finalize)
118
+ model
119
+ end
120
+
121
+ def reflective_lookup_primitive primitive
122
+ raise TypeError.new("#{primitive} not found for #{self.class}")
123
+ end
124
+
125
+ def reflective_auto_load_adapter_extension
126
+ # TODO: can we fix this shit in dm-mysql-adapter?
127
+ name = options[:adapter] || options['adapter']
128
+ # TODO: can we fix this adapter name in dm-sqlite-adapter?
129
+ adapter = name.sub(/\Asqlite3\Z/, 'sqlite')
130
+
131
+ require "dm-is-reflective/adapters/#{adapter}_adapter"
132
+ class_name = "#{Inflector.camelize(adapter)}Adapter"
133
+ Adapters.const_get(class_name).__send__(:include,
134
+ DmIsReflective.const_get(class_name))
135
+ end
136
+ end