dm-is-remixable 0.10.2 → 1.0.0.rc1
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.
- data/.gitignore +36 -0
- data/Gemfile +144 -0
- data/README.rdoc +3 -3
- data/Rakefile +4 -3
- data/VERSION +1 -1
- data/dm-is-remixable.gemspec +36 -14
- data/lib/dm-is-remixable/is/remixable.rb +55 -21
- data/lib/dm-is-remixable.rb +6 -6
- data/spec/data/billable.rb +1 -1
- data/spec/data/commentable.rb +1 -1
- data/spec/data/image.rb +11 -0
- data/spec/integration/remixable_spec.rb +14 -3
- data/spec/spec_helper.rb +7 -35
- data/tasks/local_gemfile.rake +18 -0
- data/tasks/spec.rake +0 -3
- metadata +79 -25
data/.gitignore
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
## MAC OS
|
2
|
+
.DS_Store
|
3
|
+
|
4
|
+
## TEXTMATE
|
5
|
+
*.tmproj
|
6
|
+
tmtags
|
7
|
+
|
8
|
+
## EMACS
|
9
|
+
*~
|
10
|
+
\#*
|
11
|
+
.\#*
|
12
|
+
|
13
|
+
## VIM
|
14
|
+
*.swp
|
15
|
+
|
16
|
+
## Rubinius
|
17
|
+
*.rbc
|
18
|
+
|
19
|
+
## PROJECT::GENERAL
|
20
|
+
*.gem
|
21
|
+
coverage
|
22
|
+
rdoc
|
23
|
+
pkg
|
24
|
+
tmp
|
25
|
+
doc
|
26
|
+
log
|
27
|
+
.yardoc
|
28
|
+
measurements
|
29
|
+
|
30
|
+
## BUNDLER
|
31
|
+
.bundle
|
32
|
+
Gemfile.local
|
33
|
+
Gemfile.lock
|
34
|
+
|
35
|
+
## PROJECT::SPECIFIC
|
36
|
+
spec/db/
|
data/Gemfile
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
# If you're working on more than one datamapper gem at a time, then it's
|
2
|
+
# recommended to create a local Gemfile and use this instead of the git
|
3
|
+
# sources. This will make sure that you are developing against your
|
4
|
+
# other local datamapper sources that you currently work on. Gemfile.local
|
5
|
+
# will behave identically to the standard Gemfile apart from the fact that
|
6
|
+
# it fetches the datamapper gems from local paths. This means that you can use
|
7
|
+
# the same environment variables, like ADAPTER(S) or PLUGIN(S) when running
|
8
|
+
# bundle commands. Gemfile.local is added to .gitignore, so you don't need to
|
9
|
+
# worry about accidentally checking local development paths into git.
|
10
|
+
# In order to create a local Gemfile, all you need to do is run:
|
11
|
+
#
|
12
|
+
# bundle exec rake local_gemfile
|
13
|
+
#
|
14
|
+
# This will give you a Gemfile.local file that points to your local clones of
|
15
|
+
# the various datamapper gems. It's assumed that all datamapper repo clones
|
16
|
+
# reside in the same directory. You can use the Gemfile.local like so for
|
17
|
+
# running any bundle command:
|
18
|
+
#
|
19
|
+
# BUNDLE_GEMFILE=Gemfile.local bundle foo
|
20
|
+
#
|
21
|
+
# You can also specify which adapter(s) should be part of the bundle by setting
|
22
|
+
# an environment variable. This of course also works when using the Gemfile.local
|
23
|
+
#
|
24
|
+
# bundle foo # dm-sqlite-adapter
|
25
|
+
# ADAPTER=mysql bundle foo # dm-mysql-adapter
|
26
|
+
# ADAPTERS=sqlite,mysql bundle foo # dm-sqlite-adapter and dm-mysql-adapter
|
27
|
+
#
|
28
|
+
# Of course you can also use the ADAPTER(S) variable when using the Gemfile.local
|
29
|
+
# and running specs against selected adapters.
|
30
|
+
#
|
31
|
+
# For easily working with adapters supported on your machine, it's recommended
|
32
|
+
# that you first install all adapters that you are planning to use or work on
|
33
|
+
# by doing something like
|
34
|
+
#
|
35
|
+
# ADAPTERS=sqlite,mysql,postgres bundle install
|
36
|
+
#
|
37
|
+
# This will clone the various repositories and make them available to bundler.
|
38
|
+
# Once you have them installed you can easily switch between adapters for the
|
39
|
+
# various development tasks. Running something like
|
40
|
+
#
|
41
|
+
# ADAPTER=mysql bundle exec rake spec
|
42
|
+
#
|
43
|
+
# will make sure that the dm-mysql-adapter is part of the bundle, and will be used
|
44
|
+
# when running the specs.
|
45
|
+
#
|
46
|
+
# You can also specify which plugin(s) should be part of the bundle by setting
|
47
|
+
# an environment variable. This also works when using the Gemfile.local
|
48
|
+
#
|
49
|
+
# bundle foo # dm-migrations
|
50
|
+
# PLUGINS=dm-validations bundle foo # dm-migrations and dm-validations
|
51
|
+
# PLUGINS=dm-validations,dm-types bundle foo # dm-migrations, dm-validations and dm-types
|
52
|
+
#
|
53
|
+
# Of course you can combine the PLUGIN(S) and ADAPTER(S) env vars to run specs
|
54
|
+
# for certain adapter/plugin combinations.
|
55
|
+
#
|
56
|
+
# Finally, to speed up running specs and other tasks, it's recommended to run
|
57
|
+
#
|
58
|
+
# bundle lock
|
59
|
+
#
|
60
|
+
# after running 'bundle install' for the first time. This will make 'bundle exec' run
|
61
|
+
# a lot faster compared to the unlocked version. With an unlocked bundle you would
|
62
|
+
# typically just run 'bundle install' from time to time to fetch the latest sources from
|
63
|
+
# upstream. When you locked your bundle, you need to run
|
64
|
+
#
|
65
|
+
# bundle install --relock
|
66
|
+
#
|
67
|
+
# to make sure to fetch the latest updates and then lock the bundle again. Gemfile.lock
|
68
|
+
# is added to the .gitignore file, so you don't need to worry about accidentally checking
|
69
|
+
# it into version control.
|
70
|
+
|
71
|
+
source 'http://rubygems.org'
|
72
|
+
|
73
|
+
DATAMAPPER = 'git://github.com/datamapper'
|
74
|
+
DM_VERSION = '~> 1.0.0.rc1'
|
75
|
+
|
76
|
+
group :runtime do # Runtime dependencies (as in the gemspec)
|
77
|
+
|
78
|
+
if ENV['EXTLIB']
|
79
|
+
gem 'extlib', '~> 0.9.15', :git => "#{DATAMAPPER}/extlib.git"
|
80
|
+
else
|
81
|
+
gem 'activesupport', '~> 3.0.0.beta3', :git => 'git://github.com/rails/rails.git', :require => nil
|
82
|
+
end
|
83
|
+
|
84
|
+
gem 'dm-core', DM_VERSION, :git => "#{DATAMAPPER}/dm-core.git"
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
group(:development) do # Development dependencies (as in the gemspec)
|
89
|
+
|
90
|
+
gem 'dm-validations', DM_VERSION, :git => "#{DATAMAPPER}/dm-validations.git"
|
91
|
+
gem 'dm-types', DM_VERSION, :git => "#{DATAMAPPER}/dm-types.git"
|
92
|
+
|
93
|
+
gem 'rake', '~> 0.8.7'
|
94
|
+
gem 'rspec', '~> 1.3'
|
95
|
+
gem 'jeweler', '~> 1.4'
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
group :quality do # These gems contain rake tasks that check the quality of the source code
|
100
|
+
|
101
|
+
gem 'metric_fu', '~> 1.3'
|
102
|
+
gem 'rcov', '~> 0.9.7'
|
103
|
+
gem 'reek', '~> 1.2.7'
|
104
|
+
gem 'roodi', '~> 2.1'
|
105
|
+
gem 'yard', '~> 0.5'
|
106
|
+
gem 'yardstick', '~> 0.1'
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
group :datamapper do # We need this because we want to pin these dependencies to their git master sources
|
111
|
+
|
112
|
+
adapters = ENV['ADAPTER'] || ENV['ADAPTERS']
|
113
|
+
adapters = adapters.to_s.gsub(',',' ').split(' ') - ['in_memory']
|
114
|
+
|
115
|
+
unless adapters.empty?
|
116
|
+
|
117
|
+
DO_VERSION = '~> 0.10.2'
|
118
|
+
DM_DO_ADAPTERS = %w[sqlite postgres mysql oracle sqlserver]
|
119
|
+
|
120
|
+
gem 'data_objects', DO_VERSION, :git => "#{DATAMAPPER}/do.git"
|
121
|
+
|
122
|
+
adapters.each do |adapter|
|
123
|
+
if DM_DO_ADAPTERS.any? { |dm_do_adapter| dm_do_adapter =~ /#{adapter}/ }
|
124
|
+
adapter = 'sqlite3' if adapter == 'sqlite'
|
125
|
+
gem "do_#{adapter}", DO_VERSION, :git => "#{DATAMAPPER}/do.git"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
gem 'dm-do-adapter', DM_VERSION, :git => "#{DATAMAPPER}/dm-do-adapter.git"
|
130
|
+
|
131
|
+
adapters.each do |adapter|
|
132
|
+
gem "dm-#{adapter}-adapter", DM_VERSION, :git => "#{DATAMAPPER}/dm-#{adapter}-adapter.git"
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
plugins = ENV['PLUGINS'] || ENV['PLUGIN']
|
138
|
+
plugins = (plugins.to_s.gsub(',',' ').split(' ') + ['dm-migrations']).uniq
|
139
|
+
|
140
|
+
plugins.each do |plugin|
|
141
|
+
gem plugin, DM_VERSION, :git => "#{DATAMAPPER}/#{plugin}.git"
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
data/README.rdoc
CHANGED
@@ -10,7 +10,7 @@ module Comment
|
|
10
10
|
include DataMapper::Resource
|
11
11
|
is :remixable
|
12
12
|
|
13
|
-
property :id,
|
13
|
+
property :id, Serial
|
14
14
|
property :body, String
|
15
15
|
property :created_at, DateTime
|
16
16
|
end
|
@@ -22,7 +22,7 @@ module Addressable
|
|
22
22
|
is :remixable,
|
23
23
|
:suffix => "address" #Default suffix is module name pluralized
|
24
24
|
|
25
|
-
property :id,
|
25
|
+
property :id, Serial
|
26
26
|
|
27
27
|
property :label, String #home, work, etc...
|
28
28
|
|
@@ -39,7 +39,7 @@ module Vote
|
|
39
39
|
|
40
40
|
is :remixable
|
41
41
|
|
42
|
-
property :id,
|
42
|
+
property :id, Serial
|
43
43
|
property :opinion, Enum.new("good","bad")
|
44
44
|
|
45
45
|
end
|
data/Rakefile
CHANGED
@@ -15,10 +15,11 @@ begin
|
|
15
15
|
|
16
16
|
gem.rubyforge_project = 'datamapper'
|
17
17
|
|
18
|
-
gem.add_dependency 'dm-core', '~> 0.
|
18
|
+
gem.add_dependency 'dm-core', '~> 1.0.0.rc1'
|
19
19
|
|
20
|
-
gem.add_development_dependency '
|
21
|
-
gem.add_development_dependency '
|
20
|
+
gem.add_development_dependency 'dm-validations', '~> 1.0.0.rc1'
|
21
|
+
gem.add_development_dependency 'dm-types', '~> 1.0.0.rc1'
|
22
|
+
gem.add_development_dependency 'rspec', '~> 1.3'
|
22
23
|
end
|
23
24
|
|
24
25
|
Jeweler::GemcutterTasks.new
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
1.0.0.rc1
|
data/dm-is-remixable.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{dm-is-remixable}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "1.0.0.rc1"
|
9
9
|
|
10
|
-
s.required_rubygems_version = Gem::Requirement.new("
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Cory O'Daniel"]
|
12
|
-
s.date = %q{
|
12
|
+
s.date = %q{2010-05-19}
|
13
13
|
s.description = %q{dm-is-remixable allow you to create reusable data functionality}
|
14
14
|
s.email = %q{dm-is-remixable [a] coryodaniel [d] com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -17,7 +17,9 @@ Gem::Specification.new do |s|
|
|
17
17
|
"README.rdoc"
|
18
18
|
]
|
19
19
|
s.files = [
|
20
|
-
"
|
20
|
+
".gitignore",
|
21
|
+
"Gemfile",
|
22
|
+
"LICENSE",
|
21
23
|
"README.rdoc",
|
22
24
|
"Rakefile",
|
23
25
|
"VERSION",
|
@@ -41,6 +43,7 @@ Gem::Specification.new do |s|
|
|
41
43
|
"spec/spec.opts",
|
42
44
|
"spec/spec_helper.rb",
|
43
45
|
"tasks/ci.rake",
|
46
|
+
"tasks/local_gemfile.rake",
|
44
47
|
"tasks/metrics.rake",
|
45
48
|
"tasks/spec.rake",
|
46
49
|
"tasks/yard.rake",
|
@@ -50,26 +53,45 @@ Gem::Specification.new do |s|
|
|
50
53
|
s.rdoc_options = ["--charset=UTF-8"]
|
51
54
|
s.require_paths = ["lib"]
|
52
55
|
s.rubyforge_project = %q{datamapper}
|
53
|
-
s.rubygems_version = %q{1.3.
|
56
|
+
s.rubygems_version = %q{1.3.6}
|
54
57
|
s.summary = %q{dm-is-remixable allow you to create reusable data functionality}
|
58
|
+
s.test_files = [
|
59
|
+
"spec/data/addressable.rb",
|
60
|
+
"spec/data/article.rb",
|
61
|
+
"spec/data/billable.rb",
|
62
|
+
"spec/data/bot.rb",
|
63
|
+
"spec/data/commentable.rb",
|
64
|
+
"spec/data/image.rb",
|
65
|
+
"spec/data/rating.rb",
|
66
|
+
"spec/data/tag.rb",
|
67
|
+
"spec/data/taggable.rb",
|
68
|
+
"spec/data/topic.rb",
|
69
|
+
"spec/data/user.rb",
|
70
|
+
"spec/data/viewable.rb",
|
71
|
+
"spec/integration/remixable_spec.rb",
|
72
|
+
"spec/spec_helper.rb"
|
73
|
+
]
|
55
74
|
|
56
75
|
if s.respond_to? :specification_version then
|
57
76
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
58
77
|
s.specification_version = 3
|
59
78
|
|
60
79
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
61
|
-
s.add_runtime_dependency(%q<dm-core>, ["~> 0.
|
62
|
-
s.add_development_dependency(%q<
|
63
|
-
s.add_development_dependency(%q<
|
80
|
+
s.add_runtime_dependency(%q<dm-core>, ["~> 1.0.0.rc1"])
|
81
|
+
s.add_development_dependency(%q<dm-validations>, ["~> 1.0.0.rc1"])
|
82
|
+
s.add_development_dependency(%q<dm-types>, ["~> 1.0.0.rc1"])
|
83
|
+
s.add_development_dependency(%q<rspec>, ["~> 1.3"])
|
64
84
|
else
|
65
|
-
s.add_dependency(%q<dm-core>, ["~> 0.
|
66
|
-
s.add_dependency(%q<
|
67
|
-
s.add_dependency(%q<
|
85
|
+
s.add_dependency(%q<dm-core>, ["~> 1.0.0.rc1"])
|
86
|
+
s.add_dependency(%q<dm-validations>, ["~> 1.0.0.rc1"])
|
87
|
+
s.add_dependency(%q<dm-types>, ["~> 1.0.0.rc1"])
|
88
|
+
s.add_dependency(%q<rspec>, ["~> 1.3"])
|
68
89
|
end
|
69
90
|
else
|
70
|
-
s.add_dependency(%q<dm-core>, ["~> 0.
|
71
|
-
s.add_dependency(%q<
|
72
|
-
s.add_dependency(%q<
|
91
|
+
s.add_dependency(%q<dm-core>, ["~> 1.0.0.rc1"])
|
92
|
+
s.add_dependency(%q<dm-validations>, ["~> 1.0.0.rc1"])
|
93
|
+
s.add_dependency(%q<dm-types>, ["~> 1.0.0.rc1"])
|
94
|
+
s.add_dependency(%q<rspec>, ["~> 1.3"])
|
73
95
|
end
|
74
96
|
end
|
75
97
|
|
@@ -1,3 +1,16 @@
|
|
1
|
+
require 'dm-core'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'active_support/inflector'
|
5
|
+
rescue LoadError
|
6
|
+
require 'extlib/inflection'
|
7
|
+
class String
|
8
|
+
def underscore
|
9
|
+
Extlib::Inflection.underscore(self)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
1
14
|
# reopen sam/extlib/lib/extlib/object.rb
|
2
15
|
class Object
|
3
16
|
|
@@ -7,8 +20,6 @@ class Object
|
|
7
20
|
|
8
21
|
end
|
9
22
|
|
10
|
-
Extlib::Inflection.rule 'ess', 'esses'
|
11
|
-
|
12
23
|
module DataMapper
|
13
24
|
module Is
|
14
25
|
module Remixable
|
@@ -57,7 +68,7 @@ module DataMapper
|
|
57
68
|
@is_remixable = true
|
58
69
|
|
59
70
|
# support clean suffixes for nested modules
|
60
|
-
default_suffix =
|
71
|
+
default_suffix = ActiveSupport::Inflector.demodulize(self.name).singularize.underscore
|
61
72
|
suffix(options.delete(:suffix) || default_suffix)
|
62
73
|
end
|
63
74
|
|
@@ -68,7 +79,7 @@ module DataMapper
|
|
68
79
|
# ==== Description
|
69
80
|
# Methods available to all DataMapper::Resources
|
70
81
|
module RemixerClassMethods
|
71
|
-
include
|
82
|
+
include DataMapper::Assertions
|
72
83
|
|
73
84
|
def self.included(base);end;
|
74
85
|
|
@@ -146,7 +157,7 @@ module DataMapper
|
|
146
157
|
# Example (from my upcoming dm-is-rateable gem)
|
147
158
|
# remix n, "DataMapper::Is::Rateable::Rating", :as => :ratings
|
148
159
|
remixable_module = case remixable
|
149
|
-
when Symbol then Object.full_const_get(
|
160
|
+
when Symbol then Object.full_const_get(ActiveSupport::Inflector.classify(remixable))
|
150
161
|
when String then Object.full_const_get(remixable)
|
151
162
|
when Module then remixable
|
152
163
|
end
|
@@ -163,7 +174,7 @@ module DataMapper
|
|
163
174
|
#Merge defaults/options
|
164
175
|
options = {
|
165
176
|
:as => nil,
|
166
|
-
:model =>
|
177
|
+
:model => ActiveSupport::Inflector.classify(self.name.underscore + '_' + remixable_module.suffix.pluralize),
|
167
178
|
:for => nil,
|
168
179
|
:on => nil,
|
169
180
|
:unique => false,
|
@@ -172,10 +183,10 @@ module DataMapper
|
|
172
183
|
}.update(options)
|
173
184
|
|
174
185
|
#Make sure the class hasn't been remixed already
|
175
|
-
unless Object.full_const_defined?(
|
186
|
+
unless Object.full_const_defined?(ActiveSupport::Inflector.classify(options[:model]))
|
176
187
|
|
177
188
|
#Storage name of our remixed model
|
178
|
-
options[:table_name] =
|
189
|
+
options[:table_name] = ActiveSupport::Inflector.tableize(options[:model])
|
179
190
|
|
180
191
|
#Other model to mix with in case of M:M through Remixable
|
181
192
|
options[:other_model] = options[:for] || options[:on]
|
@@ -185,8 +196,8 @@ module DataMapper
|
|
185
196
|
|
186
197
|
# map the remixable to the remixed model
|
187
198
|
# since this will be used from 'enhance api' i think it makes perfect sense to
|
188
|
-
# always refer to a remixable by its demodulized
|
189
|
-
remixable_key =
|
199
|
+
# always refer to a remixable by its demodulized underscored constant name
|
200
|
+
remixable_key = ActiveSupport::Inflector.demodulize(remixable_module.name).underscore.to_sym
|
190
201
|
populate_remixables_mapping(model, options.merge(:remixable_key => remixable_key))
|
191
202
|
|
192
203
|
# attach RemixerClassMethods and RemixerInstanceMethods to remixer if defined by remixee
|
@@ -253,12 +264,12 @@ module DataMapper
|
|
253
264
|
# belongs_to :tag
|
254
265
|
# end
|
255
266
|
def enhance(remixable,remixable_model=nil, &block)
|
256
|
-
# always use innermost singular
|
257
|
-
remixable_name = remixable.to_s.
|
267
|
+
# always use innermost singular underscored constant name
|
268
|
+
remixable_name = remixable.to_s.singularize.underscore.to_sym
|
258
269
|
class_name = if remixable_model.nil?
|
259
270
|
@remixables[remixable_name].keys.first
|
260
271
|
else
|
261
|
-
|
272
|
+
ActiveSupport::Inflector.demodulize(remixable_model.to_s).underscore.to_sym
|
262
273
|
end
|
263
274
|
|
264
275
|
model = @remixables[remixable_name][class_name][:model] unless @remixables[remixable_name][class_name].nil?
|
@@ -282,7 +293,7 @@ module DataMapper
|
|
282
293
|
key = options[:remixable_key]
|
283
294
|
accessor_name = options[:as] ? options[:as] : options[:table_name]
|
284
295
|
@remixables[key] ||= {}
|
285
|
-
model_key =
|
296
|
+
model_key = ActiveSupport::Inflector.demodulize(remixable_model.to_s).underscore.to_sym
|
286
297
|
@remixables[key][model_key] ||= {}
|
287
298
|
@remixables[key][model_key][:reader] ||= accessor_name.to_sym
|
288
299
|
@remixables[key][model_key][:writer] ||= "#{accessor_name}=".to_sym
|
@@ -298,7 +309,7 @@ module DataMapper
|
|
298
309
|
# options <Hash> options hash
|
299
310
|
def remix_one_to_many(cardinality, model, options)
|
300
311
|
self.has cardinality, (options[:as] || options[:table_name]).to_sym, :model => model.name
|
301
|
-
model.property
|
312
|
+
model.property ActiveSupport::Inflector.foreign_key(self.name).intern, Integer, :min => 0, :required => true
|
302
313
|
model.belongs_to belongs_to_name(self.name)
|
303
314
|
end
|
304
315
|
|
@@ -310,7 +321,7 @@ module DataMapper
|
|
310
321
|
# model <Class> remixed model that 'self' is relating through
|
311
322
|
# options <Hash> options hash
|
312
323
|
def remix_many_to_many(cardinality, model, options)
|
313
|
-
options[:other_model] = Object.full_const_get(
|
324
|
+
options[:other_model] = Object.full_const_get(ActiveSupport::Inflector.classify(options[:other_model]))
|
314
325
|
|
315
326
|
#TODO if options[:unique] the two *_id's need to be a unique composite key, maybe even
|
316
327
|
# attach a validates_is_unique if the validator is included.
|
@@ -325,8 +336,8 @@ module DataMapper
|
|
325
336
|
model.belongs_to belongs_to_name(options[:other_model].name)
|
326
337
|
if options[:connect]
|
327
338
|
remixed = options[:as]
|
328
|
-
remixed ||= options[:other_model].to_s.
|
329
|
-
self.has cardinality, (options[:for] || options[:on]).
|
339
|
+
remixed ||= options[:other_model].to_s.underscore
|
340
|
+
self.has cardinality, (options[:for] || options[:on]).underscore.pluralize.to_sym, :through => remixed.to_sym
|
330
341
|
end
|
331
342
|
else
|
332
343
|
raise Exception, "options[:via] must be specified when Remixing a module between two of the same class" unless options[:via]
|
@@ -357,7 +368,7 @@ module DataMapper
|
|
357
368
|
# Get instance methods and the :default context validator
|
358
369
|
model.send(:include,remixable)
|
359
370
|
|
360
|
-
if DataMapper.const_defined?('
|
371
|
+
if DataMapper.const_defined?('Validations')
|
361
372
|
|
362
373
|
# Port over any other validation contexts to this model. Skip the
|
363
374
|
# default context since it has already been included above.
|
@@ -370,7 +381,8 @@ module DataMapper
|
|
370
381
|
|
371
382
|
# Port the properties over
|
372
383
|
remixable.properties.each do |prop|
|
373
|
-
|
384
|
+
type = prop.type ? prop.type : prop.class
|
385
|
+
model.property(prop.name, type, prop.options)
|
374
386
|
end
|
375
387
|
|
376
388
|
# Attach remixed model access to RemixeeClassMethods and RemixeeInstanceMethods if defined
|
@@ -382,11 +394,28 @@ module DataMapper
|
|
382
394
|
model.send :include, Object.full_const_get("#{remixable}::RemixeeInstanceMethods")
|
383
395
|
end
|
384
396
|
|
397
|
+
clone_hooks(remixable, model)
|
398
|
+
|
385
399
|
model
|
386
400
|
end
|
387
401
|
|
388
402
|
def belongs_to_name(class_name)
|
389
|
-
class_name.
|
403
|
+
class_name.underscore.gsub(/\//, '_').to_sym
|
404
|
+
end
|
405
|
+
|
406
|
+
private
|
407
|
+
|
408
|
+
def clone_hooks(remixable, model)
|
409
|
+
remixable.__send__(:copy_hooks, model)
|
410
|
+
|
411
|
+
# event name is by default :create, :destroy etc
|
412
|
+
remixable.instance_hooks.each do |event_name, hooks|
|
413
|
+
[:after, :before].each do |callback|
|
414
|
+
hooks[callback].each do |hook|
|
415
|
+
model.send(callback, event_name, hook[:name])
|
416
|
+
end
|
417
|
+
end
|
418
|
+
end
|
390
419
|
end
|
391
420
|
|
392
421
|
end # RemixerClassMethods
|
@@ -435,4 +464,9 @@ module DataMapper
|
|
435
464
|
|
436
465
|
end # Example
|
437
466
|
end # Is
|
467
|
+
|
468
|
+
module Model
|
469
|
+
include DataMapper::Is::Remixable
|
470
|
+
end
|
471
|
+
|
438
472
|
end # DataMapper
|
data/lib/dm-is-remixable.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
include DataMapper::Is::Remixable
|
6
|
-
end
|
1
|
+
begin
|
2
|
+
require 'active_support/inflector'
|
3
|
+
rescue LoadError
|
4
|
+
require 'extlib/inflection'
|
7
5
|
end
|
6
|
+
|
7
|
+
require 'dm-is-remixable/is/remixable'
|
data/spec/data/billable.rb
CHANGED
data/spec/data/commentable.rb
CHANGED
data/spec/data/image.rb
CHANGED
@@ -7,6 +7,16 @@ module Image
|
|
7
7
|
property :description, String
|
8
8
|
property :path, String
|
9
9
|
|
10
|
+
after :save, :hook_method
|
11
|
+
|
12
|
+
def hook_method
|
13
|
+
@hook_method = true
|
14
|
+
end
|
15
|
+
|
16
|
+
def hook_method_called?
|
17
|
+
defined?(@hook_method) ? true : false
|
18
|
+
end
|
19
|
+
|
10
20
|
# These methods will be available to the class remixing this module
|
11
21
|
# If 'User' remixes 'Images', these methods will be available to a User class
|
12
22
|
#
|
@@ -42,4 +52,5 @@ module Image
|
|
42
52
|
'INSTANCE METHOD FOR REMIXEE'
|
43
53
|
end
|
44
54
|
end
|
55
|
+
|
45
56
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
DataMapper
|
3
|
+
describe 'DataMapper::Is::Remixable' do
|
4
|
+
|
5
|
+
supported_by :sqlite, :mysql, :postgres do
|
4
6
|
|
5
|
-
if HAS_SQLITE3 || HAS_MYSQL || HAS_POSTGRES
|
6
|
-
describe 'DataMapper::Is::Remixable' do
|
7
7
|
describe 'DataMapper::Resource' do
|
8
8
|
it "should know if it is remixable" do
|
9
9
|
User.is_remixable?.should be(false)
|
@@ -131,6 +131,15 @@ if HAS_SQLITE3 || HAS_MYSQL || HAS_POSTGRES
|
|
131
131
|
account.should respond_to("expiration")
|
132
132
|
end
|
133
133
|
|
134
|
+
it "should clone hooks from the Remixable Module to the Remixed Model" do
|
135
|
+
article = Article.new
|
136
|
+
article.pics = (@pic = ArticleImage.new)
|
137
|
+
|
138
|
+
expect {
|
139
|
+
article.save
|
140
|
+
}.to change(@pic, :hook_method_called?).from(false).to(true)
|
141
|
+
end
|
142
|
+
|
134
143
|
it "should copy validation contexts from the Remixable Module to the Remixed Model" do
|
135
144
|
ArticleComment.validators.contexts.should have_key(:default)
|
136
145
|
ArticleComment.validators.contexts.should have_key(:publish)
|
@@ -300,5 +309,7 @@ if HAS_SQLITE3 || HAS_MYSQL || HAS_POSTGRES
|
|
300
309
|
it 'should allow the primary and child field names to be specified while remixing' do
|
301
310
|
pending
|
302
311
|
end
|
312
|
+
|
303
313
|
end
|
314
|
+
|
304
315
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,24 +1,10 @@
|
|
1
|
-
require '
|
2
|
-
|
3
|
-
# use local dm-core if running from a typical dev checkout.
|
4
|
-
lib = File.join('..', '..', 'dm-core', 'lib')
|
5
|
-
$LOAD_PATH.unshift(lib) if File.directory?(lib)
|
6
|
-
require 'dm-core'
|
7
|
-
|
8
|
-
# use local dm-types if running from a typical dev checkout.
|
9
|
-
lib = File.join('..', 'dm-types', 'lib')
|
10
|
-
$LOAD_PATH.unshift(lib) if File.directory?(lib)
|
11
|
-
require 'dm-types'
|
12
|
-
|
13
|
-
# use local dm-validations if running from a typical dev checkout.
|
14
|
-
lib = File.join('..', 'dm-validations', 'lib')
|
15
|
-
$LOAD_PATH.unshift(lib) if File.directory?(lib)
|
16
|
-
require 'dm-validations'
|
17
|
-
|
18
|
-
# Support running specs with 'rake spec' and 'spec'
|
19
|
-
$LOAD_PATH.unshift('lib') unless $LOAD_PATH.include?('lib')
|
1
|
+
require 'dm-core/spec/setup'
|
2
|
+
require 'dm-core/spec/lib/adapter_helpers'
|
20
3
|
|
21
4
|
require 'dm-is-remixable'
|
5
|
+
require 'dm-migrations'
|
6
|
+
require 'dm-validations'
|
7
|
+
require 'dm-types'
|
22
8
|
|
23
9
|
require 'data/addressable'
|
24
10
|
require 'data/article'
|
@@ -33,20 +19,6 @@ require 'data/topic'
|
|
33
19
|
require 'data/user'
|
34
20
|
require 'data/viewable'
|
35
21
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
begin
|
40
|
-
DataMapper.setup(:default, ENV["#{name.to_s.upcase}_SPEC_URI"] || default_uri)
|
41
|
-
true
|
42
|
-
rescue LoadError => e
|
43
|
-
warn "Could not load do_#{name}: #{e}"
|
44
|
-
false
|
45
|
-
end
|
22
|
+
Spec::Runner.configure do |config|
|
23
|
+
config.extend(DataMapper::Spec::Adapters::Helpers)
|
46
24
|
end
|
47
|
-
|
48
|
-
ENV['ADAPTER'] ||= 'sqlite3'
|
49
|
-
|
50
|
-
HAS_SQLITE3 = load_driver(:sqlite3, 'sqlite3::memory:')
|
51
|
-
HAS_MYSQL = load_driver(:mysql, 'mysql://localhost/dm_core_test')
|
52
|
-
HAS_POSTGRES = load_driver(:postgres, 'postgres://postgres@localhost/dm_core_test')
|
@@ -0,0 +1,18 @@
|
|
1
|
+
desc "Support bundling from local source code (allows BUNDLE_GEMFILE=Gemfile.local bundle foo)"
|
2
|
+
task :local_gemfile do |t|
|
3
|
+
|
4
|
+
root = Pathname(__FILE__).dirname.parent
|
5
|
+
datamapper = root.parent
|
6
|
+
|
7
|
+
source_regex = /DATAMAPPER = 'git:\/\/github.com\/datamapper'/
|
8
|
+
gem_source_regex = /:git => \"#\{DATAMAPPER\}\/(.+?)(?:\.git)?\"/
|
9
|
+
|
10
|
+
root.join('Gemfile.local').open('w') do |f|
|
11
|
+
root.join('Gemfile').open.each do |line|
|
12
|
+
line.sub!(source_regex, "DATAMAPPER = '#{datamapper}'")
|
13
|
+
line.sub!(gem_source_regex, ':path => "#{DATAMAPPER}/\1"')
|
14
|
+
f.puts line
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
data/tasks/spec.rake
CHANGED
metadata
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dm-is-remixable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease: true
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- rc1
|
10
|
+
version: 1.0.0.rc1
|
5
11
|
platform: ruby
|
6
12
|
authors:
|
7
13
|
- Cory O'Daniel
|
@@ -9,39 +15,67 @@ autorequire:
|
|
9
15
|
bindir: bin
|
10
16
|
cert_chain: []
|
11
17
|
|
12
|
-
date:
|
18
|
+
date: 2010-05-19 00:00:00 -07:00
|
13
19
|
default_executable:
|
14
20
|
dependencies:
|
15
21
|
- !ruby/object:Gem::Dependency
|
16
22
|
name: dm-core
|
17
|
-
|
18
|
-
|
19
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
25
|
requirements:
|
21
26
|
- - ~>
|
22
27
|
- !ruby/object:Gem::Version
|
23
|
-
|
24
|
-
|
28
|
+
segments:
|
29
|
+
- 1
|
30
|
+
- 0
|
31
|
+
- 0
|
32
|
+
- rc1
|
33
|
+
version: 1.0.0.rc1
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
25
36
|
- !ruby/object:Gem::Dependency
|
26
|
-
name:
|
27
|
-
|
28
|
-
|
29
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
name: dm-validations
|
38
|
+
prerelease: false
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
30
40
|
requirements:
|
31
41
|
- - ~>
|
32
42
|
- !ruby/object:Gem::Version
|
33
|
-
|
34
|
-
|
43
|
+
segments:
|
44
|
+
- 1
|
45
|
+
- 0
|
46
|
+
- 0
|
47
|
+
- rc1
|
48
|
+
version: 1.0.0.rc1
|
49
|
+
type: :development
|
50
|
+
version_requirements: *id002
|
35
51
|
- !ruby/object:Gem::Dependency
|
36
|
-
name:
|
52
|
+
name: dm-types
|
53
|
+
prerelease: false
|
54
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ~>
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
segments:
|
59
|
+
- 1
|
60
|
+
- 0
|
61
|
+
- 0
|
62
|
+
- rc1
|
63
|
+
version: 1.0.0.rc1
|
37
64
|
type: :development
|
38
|
-
|
39
|
-
|
65
|
+
version_requirements: *id003
|
66
|
+
- !ruby/object:Gem::Dependency
|
67
|
+
name: rspec
|
68
|
+
prerelease: false
|
69
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
40
70
|
requirements:
|
41
71
|
- - ~>
|
42
72
|
- !ruby/object:Gem::Version
|
43
|
-
|
44
|
-
|
73
|
+
segments:
|
74
|
+
- 1
|
75
|
+
- 3
|
76
|
+
version: "1.3"
|
77
|
+
type: :development
|
78
|
+
version_requirements: *id004
|
45
79
|
description: dm-is-remixable allow you to create reusable data functionality
|
46
80
|
email: dm-is-remixable [a] coryodaniel [d] com
|
47
81
|
executables: []
|
@@ -52,6 +86,8 @@ extra_rdoc_files:
|
|
52
86
|
- LICENSE
|
53
87
|
- README.rdoc
|
54
88
|
files:
|
89
|
+
- .gitignore
|
90
|
+
- Gemfile
|
55
91
|
- LICENSE
|
56
92
|
- README.rdoc
|
57
93
|
- Rakefile
|
@@ -76,6 +112,7 @@ files:
|
|
76
112
|
- spec/spec.opts
|
77
113
|
- spec/spec_helper.rb
|
78
114
|
- tasks/ci.rake
|
115
|
+
- tasks/local_gemfile.rake
|
79
116
|
- tasks/metrics.rake
|
80
117
|
- tasks/spec.rake
|
81
118
|
- tasks/yard.rake
|
@@ -93,20 +130,37 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
93
130
|
requirements:
|
94
131
|
- - ">="
|
95
132
|
- !ruby/object:Gem::Version
|
133
|
+
segments:
|
134
|
+
- 0
|
96
135
|
version: "0"
|
97
|
-
version:
|
98
136
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
99
137
|
requirements:
|
100
|
-
- - "
|
138
|
+
- - ">"
|
101
139
|
- !ruby/object:Gem::Version
|
102
|
-
|
103
|
-
|
140
|
+
segments:
|
141
|
+
- 1
|
142
|
+
- 3
|
143
|
+
- 1
|
144
|
+
version: 1.3.1
|
104
145
|
requirements: []
|
105
146
|
|
106
147
|
rubyforge_project: datamapper
|
107
|
-
rubygems_version: 1.3.
|
148
|
+
rubygems_version: 1.3.6
|
108
149
|
signing_key:
|
109
150
|
specification_version: 3
|
110
151
|
summary: dm-is-remixable allow you to create reusable data functionality
|
111
|
-
test_files:
|
112
|
-
|
152
|
+
test_files:
|
153
|
+
- spec/data/addressable.rb
|
154
|
+
- spec/data/article.rb
|
155
|
+
- spec/data/billable.rb
|
156
|
+
- spec/data/bot.rb
|
157
|
+
- spec/data/commentable.rb
|
158
|
+
- spec/data/image.rb
|
159
|
+
- spec/data/rating.rb
|
160
|
+
- spec/data/tag.rb
|
161
|
+
- spec/data/taggable.rb
|
162
|
+
- spec/data/topic.rb
|
163
|
+
- spec/data/user.rb
|
164
|
+
- spec/data/viewable.rb
|
165
|
+
- spec/integration/remixable_spec.rb
|
166
|
+
- spec/spec_helper.rb
|