dm-is-reflective 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.md +9 -0
- data/dm-is-reflective.gemspec +2 -2
- data/lib/dm-is-reflective/adapters/data_objects_adapter.rb +2 -2
- data/lib/dm-is-reflective/adapters/mysql_adapter.rb +55 -16
- data/lib/dm-is-reflective/adapters/postgres_adapter.rb +48 -18
- data/lib/dm-is-reflective/adapters/sqlite_adapter.rb +50 -5
- data/lib/dm-is-reflective/reflective.rb +23 -9
- data/lib/dm-is-reflective/test.rb +73 -38
- data/lib/dm-is-reflective/version.rb +1 -1
- data/test/test_mysql.rb +1 -0
- data/test/test_postgres.rb +1 -0
- data/test/test_sqlite.rb +1 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9e05d37577ac7449933ee4680893d496c6ca138f
|
4
|
+
data.tar.gz: ff50451f50e9b1094db71272cbda92bb7476015a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eb614bb45b425c7d5cbdbeb9cbaa8b8acb34ff4492af861c277cdfb60c116ec5560504dd10402dbb492dfa7f5adbc441588f40e0bd3fd59fef29e7535c47d858
|
7
|
+
data.tar.gz: 9bc150a2c0da4b77af03cca23f2f7c8148d7196689e714c4e8544e6fb38d506c2257dc5f5b25fca74b620e20893c4192eadbc8d2430f1f40ab0f2f8ecccbf5bd
|
data/CHANGES.md
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
# CHANGES
|
2
2
|
|
3
|
+
## dm-is-reflective 1.3.0, 2013-05-20
|
4
|
+
|
5
|
+
* Warn instead of raising a TypeError if a datatype cannot be found.
|
6
|
+
We fallback to use String.
|
7
|
+
* Now it works for multiple composite keys.
|
8
|
+
* If there's no key defined, it would pick the first unique index as the key.
|
9
|
+
* If a field name is conflicted, it would try to resolve it by appending a
|
10
|
+
underscore to the field name.
|
11
|
+
|
3
12
|
## dm-is-reflective 1.2.0, 2013-05-14
|
4
13
|
|
5
14
|
* We got a bunch of internal renaming.
|
data/dm-is-reflective.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = "dm-is-reflective"
|
5
|
-
s.version = "1.
|
5
|
+
s.version = "1.3.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-05-
|
9
|
+
s.date = "2013-05-20"
|
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
12
|
s.executables = ["dm-is-reflective"]
|
@@ -114,12 +114,12 @@ module DmIsReflective::DataObjectsAdapter
|
|
114
114
|
model.storage_names[:default] = storage
|
115
115
|
scope.const_set(Inflector.classify(storage), model)
|
116
116
|
model.__send__(:reflect, /.*/)
|
117
|
-
model.finalize if model.respond_to?(:finalize)
|
118
117
|
model
|
119
118
|
end
|
120
119
|
|
121
120
|
def reflective_lookup_primitive primitive
|
122
|
-
|
121
|
+
warn "#{primitive} not found for #{self.class}: #{caller.inspect}"
|
122
|
+
String # falling back to the universal interface
|
123
123
|
end
|
124
124
|
|
125
125
|
def reflective_auto_load_adapter_extension
|
@@ -9,18 +9,50 @@ module DmIsReflective::MysqlAdapter
|
|
9
9
|
private
|
10
10
|
# construct needed table metadata
|
11
11
|
def reflective_query_storage storage
|
12
|
-
|
13
|
-
SELECT column_name,
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
sql_indices = <<-SQL
|
13
|
+
SELECT column_name, index_name, non_unique
|
14
|
+
FROM `information_schema`.`statistics`
|
15
|
+
WHERE table_schema = ? AND table_name = ?
|
16
|
+
SQL
|
17
|
+
|
18
|
+
sql_columns = <<-SQL
|
19
|
+
SELECT column_name, column_key, column_default, is_nullable,
|
20
|
+
data_type, character_maximum_length, extra, table_name
|
21
|
+
FROM `information_schema`.`columns`
|
22
|
+
WHERE table_schema = ? AND table_name = ?
|
17
23
|
SQL
|
18
24
|
|
19
25
|
# TODO: can we fix this shit in dm-mysql-adapter?
|
20
|
-
path = options[:path] || options['path'] ||
|
21
|
-
|
26
|
+
path = (options[:path] || options['path'] ||
|
27
|
+
options[:database] || options['database']).sub('/', '')
|
28
|
+
|
29
|
+
indices =
|
30
|
+
select(Ext::String.compress_lines(sql_indices), path, storage).
|
31
|
+
group_by(&:column_name)
|
22
32
|
|
23
|
-
select(Ext::String.compress_lines(
|
33
|
+
select(Ext::String.compress_lines(sql_columns), path, storage).
|
34
|
+
map do |column|
|
35
|
+
if idx = indices[column.column_name]
|
36
|
+
idx_uni, idx_com = idx.partition{ |i| i.non_unique == 0 }.map{ |i|
|
37
|
+
if i.empty?
|
38
|
+
nil
|
39
|
+
elsif i.size == 1
|
40
|
+
i.first.index_name.to_sym
|
41
|
+
else
|
42
|
+
i.map{ |ii| ii.index_name.to_sym }
|
43
|
+
end
|
44
|
+
}
|
45
|
+
else
|
46
|
+
idx_uni, idx_com = nil
|
47
|
+
end
|
48
|
+
|
49
|
+
column.instance_eval <<-RUBY
|
50
|
+
def unique_index; #{idx_uni.inspect}; end
|
51
|
+
def index ; #{idx_com.inspect}; end
|
52
|
+
RUBY
|
53
|
+
|
54
|
+
column
|
55
|
+
end
|
24
56
|
end
|
25
57
|
|
26
58
|
def reflective_field_name field
|
@@ -32,17 +64,24 @@ module DmIsReflective::MysqlAdapter
|
|
32
64
|
end
|
33
65
|
|
34
66
|
def reflective_attributes field, attrs = {}
|
35
|
-
|
36
|
-
|
67
|
+
attrs[:serial] = true if field.extra == 'auto_increment'
|
68
|
+
|
69
|
+
if field.column_key == 'PRI'
|
70
|
+
attrs[:key] = true
|
71
|
+
attrs[:unique_index] = :"#{field.table_name}_pkey"
|
72
|
+
else
|
73
|
+
attrs[:unique_index] = field.unique_index if field.unique_index
|
74
|
+
attrs[ :index] = field. index if field. index
|
75
|
+
end
|
37
76
|
|
38
|
-
|
39
|
-
|
40
|
-
|
77
|
+
attrs[:allow_nil] = field.is_nullable == 'YES'
|
78
|
+
attrs[:default] = field.column_default if
|
79
|
+
field.column_default
|
41
80
|
|
42
|
-
|
43
|
-
|
81
|
+
attrs[:length] = field.character_maximum_length if
|
82
|
+
field.character_maximum_length
|
44
83
|
|
45
|
-
|
84
|
+
attrs
|
46
85
|
end
|
47
86
|
|
48
87
|
def reflective_lookup_primitive primitive
|
@@ -13,28 +13,53 @@ module DmIsReflective::PostgresAdapter
|
|
13
13
|
|
14
14
|
private
|
15
15
|
def reflective_query_storage storage
|
16
|
-
|
17
|
-
SELECT
|
18
|
-
|
16
|
+
sql_indices = <<-SQL
|
17
|
+
SELECT a.attname, i.relname, ix.indisprimary, ix.indisunique
|
18
|
+
FROM pg_class t, pg_class i, pg_index ix, pg_attribute a
|
19
|
+
WHERE t.oid = ix.indrelid
|
20
|
+
AND i.oid = ix.indexrelid
|
21
|
+
AND a.attrelid = t.oid
|
22
|
+
AND a.attnum = ANY(ix.indkey)
|
23
|
+
AND t.relkind = 'r'
|
24
|
+
AND t.relname = ?
|
19
25
|
SQL
|
20
26
|
|
21
|
-
|
22
|
-
|
23
|
-
sql = <<-SQL
|
27
|
+
sql_columns = <<-SQL
|
24
28
|
SELECT column_name, column_default, is_nullable,
|
25
29
|
character_maximum_length, udt_name
|
26
|
-
FROM
|
27
|
-
WHERE
|
30
|
+
FROM "information_schema"."columns"
|
31
|
+
WHERE table_schema = current_schema() AND table_name = ?
|
28
32
|
SQL
|
29
33
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
34
|
+
indices =
|
35
|
+
select(Ext::String.compress_lines(sql_indices), storage).
|
36
|
+
group_by(&:attname)
|
37
|
+
|
38
|
+
select(Ext::String.compress_lines(sql_columns), storage).map do |column|
|
39
|
+
if idx = indices[column.column_name]
|
40
|
+
is_key = !!idx.find{ |i| i.indisprimary }
|
41
|
+
idx_uni, idx_com = idx.partition{ |i| i.indisunique }.map{ |i|
|
42
|
+
if i.empty?
|
43
|
+
nil
|
44
|
+
elsif i.size == 1
|
45
|
+
i.first.relname.to_sym
|
46
|
+
else
|
47
|
+
i.map{ |ii| ii.relname.to_sym }
|
48
|
+
end
|
49
|
+
}
|
50
|
+
else
|
51
|
+
is_key = false
|
52
|
+
idx_uni, idx_com = nil
|
53
|
+
end
|
54
|
+
|
55
|
+
column.instance_eval <<-RUBY
|
56
|
+
def key? ; #{is_key} ; end
|
57
|
+
def unique_index; #{idx_uni.inspect}; end
|
58
|
+
def index ; #{idx_com.inspect}; end
|
35
59
|
RUBY
|
36
|
-
|
37
|
-
|
60
|
+
|
61
|
+
column
|
62
|
+
end
|
38
63
|
end
|
39
64
|
|
40
65
|
def reflective_field_name field
|
@@ -47,11 +72,16 @@ module DmIsReflective::PostgresAdapter
|
|
47
72
|
|
48
73
|
def reflective_attributes field, attrs = {}
|
49
74
|
# strip data type
|
50
|
-
field.column_default
|
51
|
-
field.column_default
|
75
|
+
if field.column_default
|
76
|
+
field.column_default.gsub!(/(.*?)::[\w\s]*/, '\1')
|
77
|
+
end
|
52
78
|
|
53
79
|
attrs[:serial] = true if field.column_default =~ /nextval\('\w+'\)/
|
54
|
-
attrs[:key]
|
80
|
+
attrs[:key] = true if field.key?
|
81
|
+
|
82
|
+
attrs[:unique_index] = field.unique_index if field.unique_index
|
83
|
+
attrs[ :index] = field. index if field. index
|
84
|
+
|
55
85
|
attrs[:allow_nil] = field.is_nullable == 'YES'
|
56
86
|
# strip string quotation
|
57
87
|
attrs[:default] = field.column_default.gsub(/^'(.*?)'$/, '\1') if
|
@@ -4,8 +4,7 @@ module DmIsReflective::SqliteAdapter
|
|
4
4
|
|
5
5
|
def storages
|
6
6
|
sql = <<-SQL
|
7
|
-
SELECT name
|
8
|
-
FROM sqlite_master
|
7
|
+
SELECT name FROM sqlite_master
|
9
8
|
WHERE type = 'table' AND NOT name = 'sqlite_sequence'
|
10
9
|
SQL
|
11
10
|
|
@@ -14,7 +13,48 @@ module DmIsReflective::SqliteAdapter
|
|
14
13
|
|
15
14
|
private
|
16
15
|
def reflective_query_storage storage
|
17
|
-
|
16
|
+
sql_indices = <<-SQL
|
17
|
+
SELECT name, sql FROM sqlite_master
|
18
|
+
WHERE type = 'index' AND tbl_name = ?
|
19
|
+
SQL
|
20
|
+
|
21
|
+
indices = select(sql_indices, storage).inject({}){ |r, field|
|
22
|
+
columns = field.sql[/\(.+\)/].scan(/\w+/)
|
23
|
+
uniqueness = !!field.sql[/CREATE UNIQUE INDEX/]
|
24
|
+
|
25
|
+
columns.each{ |c|
|
26
|
+
type = if uniqueness then :unique_index else :index end
|
27
|
+
r[c] ||= {:unique_index => [], :index => []}
|
28
|
+
r[c][type] << field.name
|
29
|
+
}
|
30
|
+
|
31
|
+
r
|
32
|
+
}
|
33
|
+
|
34
|
+
select('PRAGMA table_info(?)', storage).map{ |field|
|
35
|
+
if idx = indices[field.name]
|
36
|
+
idx_uni, idx_com = [:unique_index, :index].map{ |type|
|
37
|
+
i = idx[type]
|
38
|
+
if i.empty?
|
39
|
+
nil
|
40
|
+
elsif i.size == 1
|
41
|
+
i.first.to_sym
|
42
|
+
else
|
43
|
+
i.map(&:to_sym)
|
44
|
+
end
|
45
|
+
}
|
46
|
+
else
|
47
|
+
idx_uni, idx_com = nil
|
48
|
+
end
|
49
|
+
|
50
|
+
field.instance_eval <<-RUBY
|
51
|
+
def table_name ; '#{storage}' ; end
|
52
|
+
def index ; #{idx_com.inspect}; end
|
53
|
+
def unique_index; #{idx_uni.inspect}; end
|
54
|
+
RUBY
|
55
|
+
|
56
|
+
field
|
57
|
+
}
|
18
58
|
end
|
19
59
|
|
20
60
|
def reflective_field_name field
|
@@ -27,9 +67,14 @@ module DmIsReflective::SqliteAdapter
|
|
27
67
|
|
28
68
|
def reflective_attributes field, attrs = {}
|
29
69
|
if field.pk != 0
|
30
|
-
attrs[:key]
|
31
|
-
attrs[:serial]
|
70
|
+
attrs[:key] = true
|
71
|
+
attrs[:serial] = true
|
72
|
+
attrs[:unique_index] = :"#{field.table_name}_pkey"
|
32
73
|
end
|
74
|
+
|
75
|
+
attrs[:unique_index] = field.unique_index if field.unique_index
|
76
|
+
attrs[ :index] = field. index if field. index
|
77
|
+
|
33
78
|
attrs[:allow_nil] = field.notnull == 0
|
34
79
|
attrs[:default] = field.dflt_value[1..-2] if field.dflt_value
|
35
80
|
|
@@ -55,27 +55,41 @@ module DmIsReflective
|
|
55
55
|
|
56
56
|
reflected = targets.each{ |target|
|
57
57
|
case target
|
58
|
-
|
59
|
-
|
58
|
+
when Regexp;
|
59
|
+
break name if name.to_s =~ target
|
60
60
|
|
61
|
-
|
62
|
-
|
61
|
+
when Symbol, String;
|
62
|
+
break name if name == target.to_sym
|
63
63
|
|
64
|
-
|
65
|
-
|
64
|
+
when Class;
|
65
|
+
break name if type == target
|
66
66
|
|
67
|
-
|
68
|
-
|
67
|
+
else
|
68
|
+
raise ArgumentError.new("invalid argument: #{target.inspect}")
|
69
69
|
end
|
70
70
|
}
|
71
71
|
|
72
|
-
|
72
|
+
reflect_property(reflected, type, attrs) if
|
73
|
+
reflected.kind_of?(Symbol)
|
73
74
|
}.compact
|
74
75
|
|
76
|
+
if key.empty? && k = properties.find{ |p| p.unique_index }
|
77
|
+
property k.name, k.primitive, :key => true
|
78
|
+
end
|
79
|
+
|
75
80
|
finalize if respond_to?(:finalize)
|
76
81
|
result
|
77
82
|
end
|
78
83
|
|
84
|
+
def reflect_property reflected, type, attrs
|
85
|
+
property reflected, type, attrs
|
86
|
+
rescue ArgumentError => e
|
87
|
+
if e.message =~ /cannot be used as a property name/
|
88
|
+
reflect_property "#{reflected}_", type,
|
89
|
+
{:field => reflected.to_s}.merge(attrs)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
79
93
|
def to_source scope=nil
|
80
94
|
<<-RUBY
|
81
95
|
class #{scope}::#{name} < #{superclass}
|
@@ -7,6 +7,32 @@ require 'dm-migrations'
|
|
7
7
|
require 'dm-is-reflective'
|
8
8
|
|
9
9
|
module Abstract
|
10
|
+
class Cat
|
11
|
+
include DataMapper::Resource
|
12
|
+
property :id, Serial
|
13
|
+
|
14
|
+
belongs_to :user
|
15
|
+
belongs_to :super_user
|
16
|
+
|
17
|
+
property :user_id , Integer,
|
18
|
+
:unique_index => [:usu, :u]
|
19
|
+
property :super_user_id, Integer,
|
20
|
+
:unique_index => [:usu],
|
21
|
+
:index => [:su]
|
22
|
+
end
|
23
|
+
|
24
|
+
class Comment
|
25
|
+
include DataMapper::Resource
|
26
|
+
belongs_to :user, :required => false
|
27
|
+
|
28
|
+
property :id, Serial
|
29
|
+
property :title, String, :length => 50, :default => 'default title',
|
30
|
+
:allow_nil => false
|
31
|
+
property :body, Text
|
32
|
+
|
33
|
+
is :reflective
|
34
|
+
end
|
35
|
+
|
10
36
|
class User
|
11
37
|
include DataMapper::Resource
|
12
38
|
has n, :comments
|
@@ -27,19 +53,8 @@ module Abstract
|
|
27
53
|
is :reflective
|
28
54
|
end
|
29
55
|
|
30
|
-
|
31
|
-
|
32
|
-
belongs_to :user, :required => false
|
33
|
-
|
34
|
-
property :id, Serial
|
35
|
-
property :title, String, :length => 50, :default => 'default title',
|
36
|
-
:allow_nil => false
|
37
|
-
property :body, Text
|
38
|
-
|
39
|
-
is :reflective
|
40
|
-
end
|
41
|
-
|
42
|
-
Tables = ['abstract_comments', 'abstract_super_users', 'abstract_users']
|
56
|
+
Tables = %w[abstract_cats abstract_comments
|
57
|
+
abstract_super_users abstract_users]
|
43
58
|
|
44
59
|
AttrCommon = {:allow_nil => true}
|
45
60
|
AttrCommonPK = {:serial => true, :key => true, :allow_nil => false}
|
@@ -54,40 +69,58 @@ end
|
|
54
69
|
include Abstract
|
55
70
|
|
56
71
|
shared :reflective do
|
72
|
+
def cat_fields
|
73
|
+
@cat_fields ||=
|
74
|
+
[[:id, DataMapper::Property::Serial,
|
75
|
+
{:unique_index => :abstract_cats_pkey}.merge(AttrCommonPK)],
|
76
|
+
[:super_user_id, Integer,
|
77
|
+
{:unique_index => :unique_abstract_cats_usu,
|
78
|
+
:index => :index_abstract_cats_su }.merge(AttrCommon)],
|
79
|
+
[:user_id , Integer,
|
80
|
+
{:unique_index => [:unique_abstract_cats_usu,
|
81
|
+
:unique_abstract_cats_u]}.merge(AttrCommon)]]
|
82
|
+
end
|
83
|
+
|
84
|
+
def comment_fields
|
85
|
+
@comment_fields ||= begin
|
86
|
+
[[:body , DataMapper::Property::Text , AttrText],
|
87
|
+
[:id , DataMapper::Property::Serial,
|
88
|
+
{:unique_index => :abstract_comments_pkey}.merge(AttrCommonPK)],
|
89
|
+
|
90
|
+
[:title , String ,
|
91
|
+
{:length => 50, :default => 'default title', :allow_nil => false}],
|
92
|
+
|
93
|
+
[:user_id, Integer ,
|
94
|
+
{:index => :index_abstract_comments_user}.merge(AttrCommon)]]
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
57
98
|
def user_fields
|
99
|
+
@user_fields ||=
|
58
100
|
[[:created_at, DateTime, AttrCommon],
|
59
|
-
[:id, DataMapper::Property::Serial,
|
101
|
+
[:id, DataMapper::Property::Serial,
|
102
|
+
{:unique_index => :abstract_users_pkey}.merge(AttrCommonPK)],
|
60
103
|
[:login, String, {:length => 70}.merge(AttrCommon)],
|
61
104
|
[:sig, DataMapper::Property::Text, AttrText]]
|
62
105
|
end
|
63
106
|
|
64
|
-
def comment_fields
|
65
|
-
[[:body, DataMapper::Property::Text, AttrText],
|
66
|
-
[:id, DataMapper::Property::Serial, AttrCommonPK],
|
67
|
-
[:title, String, {:length => 50, :default => 'default title',
|
68
|
-
:allow_nil => false}],
|
69
|
-
[:user_id, Integer, AttrCommon]]
|
70
|
-
end
|
71
|
-
|
72
|
-
# there's differences between adapters
|
73
107
|
def super_user_fields
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
[:id, DataMapper::Property::Serial, AttrCommonPK]]
|
108
|
+
@super_user_fields ||= begin
|
109
|
+
type = case DataMapper.repository.adapter.class.name
|
110
|
+
when 'DataMapper::Adapters::MysqlAdapter'
|
111
|
+
Integer
|
112
|
+
else
|
113
|
+
DataMapper::Property::Boolean
|
114
|
+
end
|
115
|
+
[[:bool, type, AttrCommon],
|
116
|
+
[:id , DataMapper::Property::Serial,
|
117
|
+
{:unique_index => :abstract_super_users_pkey}.merge(AttrCommonPK)]]
|
85
118
|
end
|
86
119
|
end
|
87
120
|
|
88
121
|
before do
|
89
122
|
@dm = setup_data_mapper
|
90
|
-
[
|
123
|
+
[Cat, Comment, User, SuperUser].each(&:auto_migrate!)
|
91
124
|
end
|
92
125
|
|
93
126
|
def sort_fields fields
|
@@ -167,8 +200,9 @@ shared :reflective do
|
|
167
200
|
key, value = i
|
168
201
|
r[key] = value.sort_by{ |v| v.first.to_s }
|
169
202
|
r
|
170
|
-
}.should.eq('
|
171
|
-
'abstract_comments' =>
|
203
|
+
}.should.eq('abstract_cats' => cat_fields,
|
204
|
+
'abstract_comments' => comment_fields,
|
205
|
+
'abstract_users' => user_fields,
|
172
206
|
'abstract_super_users' => super_user_fields)
|
173
207
|
end
|
174
208
|
|
@@ -215,7 +249,8 @@ shared :reflective do
|
|
215
249
|
should 'auto_genclasses' do
|
216
250
|
scope = new_scope
|
217
251
|
@dm.auto_genclass!(:scope => scope).map(&:to_s).sort.should.eq \
|
218
|
-
["#{scope}::
|
252
|
+
["#{scope}::AbstractCat" ,
|
253
|
+
"#{scope}::AbstractComment" ,
|
219
254
|
"#{scope}::AbstractSuperUser",
|
220
255
|
"#{scope}::AbstractUser"]
|
221
256
|
|
data/test/test_mysql.rb
CHANGED
data/test/test_postgres.rb
CHANGED
data/test/test_sqlite.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dm-is-reflective
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lin Jen-Shin (godfat)
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-05-
|
11
|
+
date: 2013-05-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dm-core
|