dm-is-reflective 1.1.0 → 1.2.0

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.
@@ -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