schemaker 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source "http://rubygems.org"
2
+
3
+ # gem "activerecord", ">= 3.0.1"
4
+
5
+ group :development do
6
+ gem "activerecord", ">= 3.0.1"
7
+ gem "rspec", ">= 2.6.0"
8
+ gem "bundler", "~> 1.0.6"
9
+ gem "jeweler", "~> 1.6.2"
10
+ gem "rcov", ">= 0"
11
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Kristian Mandrup
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.textile ADDED
@@ -0,0 +1,49 @@
1
+ h1. Schemaker
2
+
3
+ This is the *Schema Maker* also known as the *schemaker*. This gem can help configure your model relationships for 3 models, the subject, the join and the object model.
4
+ Typically when you add some behavior field to a subject (fx a UserAccount model class), this may require a 1-M or M-M relationship to the object of that relationship.
5
+ With _ActiveRecord_ this can require a join model or just a symmetrical _:has_and_belongs_to_many_. If you apply Schemaker, it will handle all this magic for you!
6
+
7
+ Schemaker is intended for use when creating gems that require somewhat complex model relationships for adding behavior. It does the "heavy lifting" on this part of the work.
8
+ There will likely be adapters for other data stores too, to simplify ensuring that your gem can support and store the relationships correctly for these data stores.
9
+
10
+ h2. Install
11
+
12
+ Gemfile:
13
+
14
+ @gem 'schemaker@
15
+
16
+ @$ bundle@
17
+
18
+ h2. Usage
19
+
20
+ Create a complex Many-to-Many join through the join model
21
+
22
+ <pre>require 'schemaker'
23
+
24
+ models = Schemaker::Models.new UserAccount, Role, UsersRoles, :subject_key => :troles
25
+ models.configure</pre>
26
+
27
+ Create a "quick join" (a symmetrical :has_and_belongs_to_many for the subject and object model)
28
+
29
+ @models.subject_model.quick_join@
30
+
31
+ Create a :has_one to relationship from the subject to the object
32
+
33
+ @models.subject_model.create_has_one :object@
34
+
35
+ h2. Contributing to schemaker
36
+
37
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
38
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
39
+ * Fork the project
40
+ * Start a feature/bugfix branch
41
+ * Commit and push until you are happy with your contribution
42
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
43
+ * 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.
44
+
45
+ h2. Copyright
46
+
47
+ Copyright (c) 2011 Kristian Mandrup. See LICENSE.txt for
48
+ further details.
49
+
data/Rakefile ADDED
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "schemaker"
18
+ gem.homepage = "http://github.com/kristianmandrup/schemaker"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Schema maker takes care of configuring your model schemas to map behavior}
21
+ gem.description = %Q{Configures relationships between subject, join and object model for a given behavior}
22
+ gem.email = "kmandrup@gmail.com"
23
+ gem.authors = ["Kristian Mandrup"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rspec/core'
29
+ require 'rspec/core/rake_task'
30
+ RSpec::Core::RakeTask.new(:spec) do |spec|
31
+ spec.pattern = FileList['spec/**/*_spec.rb']
32
+ end
33
+
34
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
35
+ spec.pattern = 'spec/**/*_spec.rb'
36
+ spec.rcov = true
37
+ end
38
+
39
+ task :default => :spec
40
+
41
+ require 'rake/rdoctask'
42
+ Rake::RDocTask.new do |rdoc|
43
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
44
+
45
+ rdoc.rdoc_dir = 'rdoc'
46
+ rdoc.title = "schemaker #{version}"
47
+ rdoc.rdoc_files.include('README*')
48
+ rdoc.rdoc_files.include('lib/**/*.rb')
49
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,204 @@
1
+ #
2
+ # @author Kristian Mandrup
3
+ #
4
+ # Basic Model configuration functionality
5
+ #
6
+ # Each type of model to be configured shares some common functionality and state, that is encapsulated here for reuse
7
+ #
8
+ module Schemaker
9
+ class BaseModel
10
+ attr_accessor :models, :my_class
11
+ attr_reader :logs # can be used to later check which relationships were set up
12
+
13
+ # @param [Schema::Models] each model needs to have access to the collection of models it may need to create relations with
14
+ # @param [Class] each model must have a reference to the Class it aims to configure!
15
+ def initialize models, my_class
16
+ raise ArgumentError, "The first argument must be a Schema::Models instance" if !models.is_a?(Schemaker::Models)
17
+ raise ArgumentError, "The second argument must be the Class that is to be configured" if !my_class.is_a?(Class)
18
+
19
+ @models = models
20
+ @my_class = my_class
21
+ @logs = []
22
+ end
23
+
24
+ # The models :subject and :object must both be configured
25
+ # with a has_many relationship to the join model which the has_many :through references
26
+ def configure
27
+ create_has_many :join, class_name_option(join_class)
28
+ end
29
+
30
+ # The class name of the Class to be configured
31
+ # @return [String] class name
32
+ def clazz_name
33
+ my_class.to_s
34
+ end
35
+ alias_method :my_class_name, :clazz_name
36
+
37
+ def self.model_types
38
+ [:object, :subject, :join]
39
+ end
40
+
41
+ # Generate convenience methods for: :object, :subject, :join
42
+ # - object_model
43
+ # - object_class
44
+ # - object_class_name
45
+
46
+ model_types.each do |model_type|
47
+ class_eval %{
48
+ def #{model_type}_model
49
+ models.#{model_type}_model
50
+ end
51
+
52
+ def #{model_type}_class
53
+ models.#{model_type}_class
54
+ end
55
+
56
+ def #{model_type}_class_name
57
+ #{model_type}_class.clazz_name
58
+ end
59
+ }
60
+ end
61
+
62
+ protected
63
+
64
+ # Is global logging turned on
65
+ def log_on?
66
+ Schemaker.log_on?
67
+ end
68
+
69
+ # Create a 'belongs_to' relationship on the model (Class)
70
+ # Example:
71
+ # Role.belongs_to :user, :class_name => 'User'
72
+ def create_belongs_to clazz, options = {}
73
+ make_relationship :belongs_to, clazz, options.merge(:key => singular_key(clazz))
74
+ end
75
+
76
+ # Create a 'has_many' relationship on the model (Class)
77
+ # Example:
78
+ # User.has_many :roles, :class_name => 'Role'
79
+ def create_has_many clazz, options = {}
80
+ make_relationship :has_many, clazz, options
81
+ end
82
+
83
+ # Create a 'has_many' relationship on the model (Class)
84
+ # Example:
85
+ # User.has_one :roles, :class_name => 'Role'
86
+ def create_has_one clazz, options = {}
87
+ make_relationship :has_one, clazz, options.merge(:key => singular_key(clazz))
88
+ end
89
+
90
+ # Create a 'has_many :through' relationship on the model (Class)
91
+ # Example:
92
+ # User.has_many :roles, :class_name => 'Role', :through => 'UsersRoles'
93
+ def create_has_many_through clazz, options = {}
94
+ create_has_many clazz, through_options(options)
95
+ end
96
+
97
+ # To setup symmetrical has_and_belongs_to_many relationship:
98
+ #
99
+ # Example:
100
+ #
101
+ # class UserAccount < ActiveRecord::Base
102
+ # has_and_belongs_to_many :troles, :class_name => 'Role'
103
+ # end
104
+ #
105
+ # class Role < ActiveRecord::Base
106
+ # has_and_belongs_to_many :user_accounts, :class_name => 'User'
107
+ # end
108
+ #
109
+ def has_and_belongs_many to_clazz, options = {}
110
+ make_relationship :has_and_belongs_to_many, to_clazz, options[:from]
111
+ to_clazz.make_relationship :has_and_belongs_to_many, my_class, options[:to]
112
+ end
113
+
114
+ # Creates a given type of relationship
115
+ # @param [Symbol] the type of relationship, fx :has_many
116
+ # @param [Class, Symbol] the Class that is the object of the relationship, fx Role for a User.has_many relationship
117
+ # @param [Hash] any extra relationship options, fx for a :through relationship, or to indicate :class_name etc.
118
+ def make_relationship relationship_name, clazz, options = {}
119
+ key_name = options.delete(:key) || key(clazz)
120
+
121
+ opts_str = options.empty? ? '' : options.inspect.insert(0, ', ').gsub(/[{}]/ , '')
122
+ log "#{my_class_name}.#{relationship_name} :#{key_name}#{opts_str}" if log_on?
123
+
124
+ return my_class.send(relationship_name, key_name) if options.empty?
125
+
126
+ my_class.send(relationship_name, key_name, options)
127
+ end
128
+
129
+ # creates a key for a given type
130
+ # @param type [Symbol] - either :object, :subject or :join
131
+ def key type
132
+ models.key type
133
+ end
134
+
135
+ def get_class type
136
+ models.get_class type
137
+ end
138
+
139
+ def singular_key cls_name
140
+ model = get_class(cls_name)
141
+ model.to_s.singularize.underscore
142
+ end
143
+
144
+ def make_key cls_name
145
+ models.make_key cls_name
146
+ end
147
+
148
+ # log the relationship being added
149
+ # - to STDOUT via puts
150
+ # - to a logs list
151
+ def log msg
152
+ puts msg
153
+ logs << msg
154
+ end
155
+
156
+ # sets up the :source relationship option, typically for a has_many through relationship
157
+ def source_option cls_name
158
+ model = get_class(cls_name)
159
+ {:source => source(model) }
160
+ end
161
+
162
+ # sets up the :class_name relationship option for a given class (model
163
+ # @param [Class, String] the class to point to
164
+ def class_name_option cls_name
165
+ model = get_class(cls_name)
166
+ {:class_name => model.to_s }
167
+ end
168
+
169
+ # sets up the :through relationship option, always points to the join model
170
+ def through_option
171
+ {:through => join_model.through_key }
172
+ end
173
+
174
+ # sets up the :foreign_key relationship option
175
+ # the foreign key name should always correspond to 'my own' class name
176
+ def foreign_key_option cls_name
177
+ model = get_class(cls_name)
178
+ {:foreign_key => foreign_key(model) }
179
+ end
180
+
181
+ # sets up the full :through relationship options
182
+ # Example:
183
+ # :class_name => 'Role', :through => 'UsersRoles', :source => :role, :foreign_key => :user_id)
184
+ def through_options cls_name
185
+ model = get_class(cls_name)
186
+ through_option.merge(source_option model).merge(class_name_option model)
187
+ end
188
+
189
+ # creates the source
190
+ # Role becomes :role
191
+ def source cls_name
192
+ model = get_class(cls_name)
193
+ model.to_s.underscore.singularize.to_sym
194
+ end
195
+
196
+ # creates the foreign key
197
+ # RefManyAccount becomes :account_id
198
+ def foreign_key cls_name
199
+ model = get_class(cls_name)
200
+ name = model.to_s.underscore.split('_').last.singularize
201
+ :"#{name}_id"
202
+ end
203
+ end
204
+ end
@@ -0,0 +1,40 @@
1
+ #
2
+ # @author Kristian Mandrup
3
+ #
4
+ # Model configuration of the Join model (fx UsersRoles)
5
+ #
6
+ # Knows how to configure the Join model between a subject model (the main target of the behavior fx UserAccount) and the object model (the behavior to be added, fx Role)
7
+ #
8
+ module Schemaker
9
+ class JoinModel < BaseModel
10
+
11
+ # @param [Schema::Models] each model needs to have access to the collection of models it may need to create relations with
12
+ # @param [Class] reference to the Class it aims to configure!
13
+ def initialize models, clazz
14
+ super
15
+ end
16
+
17
+ def simple_key
18
+ clazz_name.to_s.underscore
19
+ end
20
+
21
+ def through_key
22
+ make_key clazz_name
23
+ end
24
+
25
+ # The join model always belongs to both the object and subject model
26
+ # the subject and object model can then each have a has_many relationship to the join model
27
+ # thus creating a Many-to-Many relationship via the join model
28
+
29
+ # Example:
30
+ # UsersRoles
31
+ # belongs_to :user, :class_name => 'UserAccount' (subject)
32
+ # belongs_to :role, :class_name => 'Role' (object)
33
+ #
34
+ # @note Do not call super here!
35
+ def configure
36
+ create_belongs_to :subject, class_name_option(:subject)
37
+ create_belongs_to :object, class_name_option(:object)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,33 @@
1
+ #
2
+ # @author Kristian Mandrup
3
+ #
4
+ # Model configuration of the Object model (fx Role)
5
+ #
6
+ # Knows how to configure the relationship fro the Object model to the subject model via the Join model
7
+ #
8
+ module Schemaker
9
+ class ObjectModel < BaseModel
10
+
11
+ # @param [Schema::Models] each model needs to have access to the collection of models it may need to create relations with
12
+ # @param [Class] reference to the Class it aims to configure!
13
+ def initialize models, clazz
14
+ super
15
+ end
16
+
17
+ # Configures has_many through relationship via Join model for the object model (fx Role)
18
+ #
19
+ # Example:
20
+ # Role (object)
21
+ # has_many :accounts, :class_name => 'RefManyAccount', :through => :accounts_roles (subject)
22
+ # has_many :user_roles, :class_name => 'UserRole' (join)
23
+ def configure
24
+ super
25
+ create_has_many_through :subject
26
+ end
27
+
28
+ # @note important to use super to avoid recursive stack overflow!
29
+ def through_options options = {}
30
+ options.merge super(:subject)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,41 @@
1
+ #
2
+ # @author Kristian Mandrup
3
+ #
4
+ # Model configuration of the Subject model (fx Role)
5
+ #
6
+ # Knows how to configure the relationship fro the Object model to the subject model via the Join model
7
+ #
8
+ module Schemaker
9
+ class SubjectModel < BaseModel
10
+
11
+ # the main field for the behavior to add, fx :troles for adding roles behavior
12
+ attr_accessor :main_field
13
+
14
+ # @param [Schema::Models] each model needs to have access to the collection of models it may need to create relations with
15
+ # @param [Class] reference to the Class it aims to configure!
16
+ # @param [Symbol] the name of the main field for the behavior to add, fx :troles for adding roles behavior
17
+ def initialize models, clazz, main_field
18
+ super models, clazz
19
+ @main_field = main_field
20
+ end
21
+
22
+ # Used to set up a 'quick join' using Rails conventions and 'has_and_belongs_to_many' on the subject and object
23
+ def quick_join options = {}
24
+ create_has_and_belongs_to_many :object
25
+ end
26
+
27
+ # Example:
28
+ # UserAccount (subject)
29
+ # has_many :user_roles, :class_name => 'UserRole' (join)
30
+ # has_many :roles, :class_name => 'Role', :through => :users_roles (subject)
31
+ def configure
32
+ super
33
+ create_has_many_through :object, :key => main_field
34
+ end
35
+
36
+ # @note important to use super to avoid recursive stack overflow!
37
+ def through_options options = {}
38
+ options.merge super(:object).merge(foreign_key_option :subject)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,109 @@
1
+ #
2
+ # @author Kristian Mandrup
3
+ #
4
+ # Model configuration
5
+ # Has responsibiloity to configure relationships between all models
6
+ # A single behavior decoration can have up to three acting models in a joined relationship
7
+
8
+ # The subject model:
9
+ # - is the model which is the subject of the behavior added.
10
+ # - it has the main field, which CAN be a relationship to the object model, either directly or via a join model (fx in Relational DBs)
11
+ #
12
+ # The object model:
13
+ # - is the object of interest to the subject, fx a Role model is the object of interest for a UserAccount (subject)
14
+ # - the object can be referenced directly, via a join model or embedded under the subject
15
+ #
16
+ # The join model:
17
+ # - is used to bind object to subject in a Many-to-Many relationship, typically for Relational DBs
18
+ # - it must have a foreign key for both object and subject model, and most often no primary key of its own
19
+
20
+ module Schemaker
21
+ class Models
22
+ attr_accessor :subject_model, :object_model, :join_model
23
+
24
+ # Sets up the models that take part in the model relationship to be configured
25
+ # @param subject_class [Class]
26
+ # @param object_class [Class]
27
+ # @param join_class [Class]
28
+ # @param options [Hash] - contains the key to be used for the main field (subject key) and possibly other options to configure the models more precisely as needed
29
+ def initialize subject_class, object_class, join_class, options = {}
30
+ @subject_model = SubjectModel.new self, subject_class, options[:subject_key]
31
+ @object_model = ObjectModel.new self, object_class
32
+ @join_model = JoinModel.new self, join_class
33
+ end
34
+
35
+ # creates a key for a given type
36
+ # @param type [Symbol] - either :object, :subject or :join
37
+ def key type
38
+ make_key get_class(type)
39
+ end
40
+
41
+ # configure each model in turn
42
+ def configure
43
+ [subject_model, object_model, join_model].each do
44
+ |model| model.configure
45
+ end
46
+ end
47
+
48
+ def logs
49
+ @logs ||= [subject_model, object_model, join_model].inject([]) do |res, model|
50
+ res << model.logs
51
+ res
52
+ end.flatten
53
+ end
54
+
55
+ def self.model_types
56
+ [:object, :subject, :join]
57
+ end
58
+
59
+ # generate methods:
60
+ # - object_class
61
+ # - subject_class
62
+ # - join_class
63
+ model_types.each do |model_type|
64
+ class_eval %{
65
+ def #{model_type}_class
66
+ #{model_type}_model.clazz_name
67
+ end
68
+ }
69
+ end
70
+
71
+ # retrieves a given Class ie. a type of model
72
+ # @param [Class, String, Symbol, BaseModel] which class to get
73
+ # @return [Class] the Class (model) of interest
74
+ def get_class type
75
+ case type
76
+ when Class
77
+ type
78
+ when BaseModel
79
+ type.my_class
80
+ when String, Symbol
81
+ return get_class send("#{type}_model") if [:subject, :object, :join].include?(type.to_sym)
82
+ type.to_s.constantize
83
+ else
84
+ raise "Can't determine a class from: #{type}"
85
+ end
86
+ end
87
+
88
+ # creates a key from a class name
89
+ # fx UsersRoles becomes :user_roles, where only the last part is pluralised!
90
+ # @param [String] the class name
91
+ def make_key class_name
92
+ name = class_name.to_s.pluralize.gsub(/::/, '__').underscore
93
+ only_last_part_plural(name).to_sym
94
+ end
95
+
96
+ protected
97
+
98
+ # Takes a composite name and makes a nice sounding key that follows the Rails conventions
99
+ # fx UsersRoles becomes :user_roles, where only the last part is pluralised!
100
+ # @param [String] the class name, fx UsersRoles
101
+ def only_last_part_plural cls_name
102
+ parts = cls_name.split('_')
103
+ name = parts.inject([]) do |res, part|
104
+ res << (part != parts.last ? part.singularize : part)
105
+ res
106
+ end.join('_')
107
+ end
108
+ end
109
+ end
data/lib/schemaker.rb ADDED
@@ -0,0 +1,14 @@
1
+ module Schemaker
2
+ class << self
3
+ attr_accessor :log_on
4
+
5
+ alias_method :log_on?, :log_on
6
+ end
7
+
8
+ autoload :Models, 'schemaker/models'
9
+
10
+ autoload :BaseModel, 'schemaker/models/base_model'
11
+ autoload :JoinModel, 'schemaker/models/join_model'
12
+ autoload :ObjectModel, 'schemaker/models/object_model'
13
+ autoload :SubjectModel, 'schemaker/models/subject_model'
14
+ end
data/schemaker.gemspec ADDED
@@ -0,0 +1,71 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{schemaker}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = [%q{Kristian Mandrup}]
12
+ s.date = %q{2011-06-12}
13
+ s.description = %q{Configures relationships between subject, join and object model for a given behavior}
14
+ s.email = %q{kmandrup@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.textile"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".rspec",
22
+ "Gemfile",
23
+ "LICENSE.txt",
24
+ "README.textile",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "lib/schemaker.rb",
28
+ "lib/schemaker/models.rb",
29
+ "lib/schemaker/models/base_model.rb",
30
+ "lib/schemaker/models/join_model.rb",
31
+ "lib/schemaker/models/object_model.rb",
32
+ "lib/schemaker/models/subject_model.rb",
33
+ "schemaker.gemspec",
34
+ "spec/models_helper.rb",
35
+ "spec/schemaker/model/join_spec.rb",
36
+ "spec/schemaker/model/object_spec.rb",
37
+ "spec/schemaker/model/subject_spec.rb",
38
+ "spec/schemaker/models_spec.rb",
39
+ "spec/spec_helper.rb"
40
+ ]
41
+ s.homepage = %q{http://github.com/kristianmandrup/schemaker}
42
+ s.licenses = [%q{MIT}]
43
+ s.require_paths = [%q{lib}]
44
+ s.rubygems_version = %q{1.8.5}
45
+ s.summary = %q{Schema maker takes care of configuring your model schemas to map behavior}
46
+
47
+ if s.respond_to? :specification_version then
48
+ s.specification_version = 3
49
+
50
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
51
+ s.add_development_dependency(%q<activerecord>, [">= 3.0.1"])
52
+ s.add_development_dependency(%q<rspec>, [">= 2.6.0"])
53
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.6"])
54
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.2"])
55
+ s.add_development_dependency(%q<rcov>, [">= 0"])
56
+ else
57
+ s.add_dependency(%q<activerecord>, [">= 3.0.1"])
58
+ s.add_dependency(%q<rspec>, [">= 2.6.0"])
59
+ s.add_dependency(%q<bundler>, ["~> 1.0.6"])
60
+ s.add_dependency(%q<jeweler>, ["~> 1.6.2"])
61
+ s.add_dependency(%q<rcov>, [">= 0"])
62
+ end
63
+ else
64
+ s.add_dependency(%q<activerecord>, [">= 3.0.1"])
65
+ s.add_dependency(%q<rspec>, [">= 2.6.0"])
66
+ s.add_dependency(%q<bundler>, ["~> 1.0.6"])
67
+ s.add_dependency(%q<jeweler>, ["~> 1.6.2"])
68
+ s.add_dependency(%q<rcov>, [">= 0"])
69
+ end
70
+ end
71
+
@@ -0,0 +1,53 @@
1
+ require 'rspec'
2
+ require 'active_record'
3
+ require 'schemaker'
4
+
5
+ Schemaker.log_on = true
6
+
7
+ class UserAccount < ActiveRecord::Base
8
+ end
9
+
10
+ class Role < ActiveRecord::Base
11
+ end
12
+
13
+ class UsersRoles < ActiveRecord::Base
14
+ end
15
+
16
+ def join_class
17
+ UsersRoles
18
+ end
19
+
20
+ def object_class
21
+ Role
22
+ end
23
+
24
+ def subject_class
25
+ UserAccount
26
+ end
27
+
28
+ def logs_matches logs, str
29
+ logs.any? {|log| match? log, str }
30
+ end
31
+
32
+ def matches log, str
33
+ log.should match(str) # /#{Regexp.escape(str)}/
34
+ end
35
+
36
+ def match? log, str
37
+ log =~ /#{Regexp.escape(str)}/
38
+ end
39
+
40
+
41
+ def matches_all log, *strings
42
+ strings.each {|str| match? log, str}
43
+ end
44
+
45
+
46
+ def models_class
47
+ Schemaker::Models
48
+ end
49
+
50
+
51
+ def models
52
+ @models ||= models_class.new subject_class, object_class, join_class, :subject_key => :troles
53
+ end
@@ -0,0 +1,27 @@
1
+ require 'models_helper'
2
+
3
+ class UsersRoles < ActiveRecord::Base
4
+ end
5
+
6
+ def join_model_class
7
+ Schemaker::JoinModel
8
+ end
9
+
10
+ describe join_model_class do
11
+ let(:join_model) do
12
+ join_model_class.new models, UsersRoles
13
+ end
14
+
15
+ describe '#configure' do
16
+ it 'should configure join model' do
17
+ join_model.configure
18
+
19
+ # check the logs!
20
+ last_log = join_model.logs.last
21
+ first_log = join_model.logs.first
22
+
23
+ matches_all first_log, 'belongs_to :user_account', ':class_name=>"UserAccount"'
24
+ matches_all last_log, 'belongs_to :role', ':class_name=>"Role"'
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,24 @@
1
+ require 'models_helper'
2
+
3
+ def object_model_class
4
+ Schemaker::ObjectModel
5
+ end
6
+
7
+ describe object_model_class do
8
+ let(:object_model) do
9
+ object_model_class.new models, Role
10
+ end
11
+
12
+ describe '#configure' do
13
+ it 'should configure object model' do
14
+ object_model.configure
15
+
16
+ # check the logs!
17
+ last_log = object_model.logs.last
18
+ first_log = object_model.logs.first
19
+
20
+ matches_all first_log, 'has_many :user_roles', ':class_name=>"UsersRoles"'
21
+ matches_all last_log, 'Role.has_many :user_accounts', ':through=>:user_roles', ':source=>:user_account', ':class_name=>"UserAccount"'
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,25 @@
1
+ require 'troles/common/config/schema/models_helper'
2
+
3
+ def subject_model_class
4
+ Schemaker::SubjectModel
5
+ end
6
+
7
+ describe subject_model_class do
8
+ let(:subject_model) do
9
+ subject_model_class.new models, UserAccount, :troles
10
+ end
11
+
12
+ describe '#configure' do
13
+ it 'should configure subject model' do
14
+ subject_model.configure
15
+
16
+ # check the logs!
17
+ last_log = subject_model.logs.last
18
+ first_log = subject_model.logs.first
19
+
20
+ matches_all first_log, 'has_many :user_roles', ':class_name=>"UsersRoles"'
21
+ # has_many :roles, {:through=>:user_roles, :source=>:role, :class_name=>"Role", :foreign_key=>:account_id}
22
+ matches_all last_log, 'UserAccount.has_many :troles', ':through=>:user_roles', ':source=>:role', ':class_name=>"Role"', ':foreign_key=>:account_id'
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,16 @@
1
+ require 'models_helper'
2
+
3
+ describe models_class do
4
+ let(:models) do
5
+ # subject, object, join
6
+ models_class.new UserAccount, Role, UsersRoles, :subject_key => :troles
7
+ end
8
+
9
+ describe '#configure' do
10
+ it 'should configure all models' do
11
+ models.configure
12
+
13
+ logs_matches(models.logs, 'UserAccount.has_many :troles').should
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,6 @@
1
+ require 'rspec'
2
+ require 'schemaker'
3
+
4
+ RSpec.configure do |config|
5
+
6
+ end
metadata ADDED
@@ -0,0 +1,126 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: schemaker
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Kristian Mandrup
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-06-12 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activerecord
16
+ requirement: &2156091260 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 3.0.1
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *2156091260
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ requirement: &2156086680 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: 2.6.0
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *2156086680
36
+ - !ruby/object:Gem::Dependency
37
+ name: bundler
38
+ requirement: &2156085240 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 1.0.6
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *2156085240
47
+ - !ruby/object:Gem::Dependency
48
+ name: jeweler
49
+ requirement: &2156084180 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 1.6.2
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *2156084180
58
+ - !ruby/object:Gem::Dependency
59
+ name: rcov
60
+ requirement: &2156081880 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *2156081880
69
+ description: Configures relationships between subject, join and object model for a
70
+ given behavior
71
+ email: kmandrup@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files:
75
+ - LICENSE.txt
76
+ - README.textile
77
+ files:
78
+ - .document
79
+ - .rspec
80
+ - Gemfile
81
+ - LICENSE.txt
82
+ - README.textile
83
+ - Rakefile
84
+ - VERSION
85
+ - lib/schemaker.rb
86
+ - lib/schemaker/models.rb
87
+ - lib/schemaker/models/base_model.rb
88
+ - lib/schemaker/models/join_model.rb
89
+ - lib/schemaker/models/object_model.rb
90
+ - lib/schemaker/models/subject_model.rb
91
+ - schemaker.gemspec
92
+ - spec/models_helper.rb
93
+ - spec/schemaker/model/join_spec.rb
94
+ - spec/schemaker/model/object_spec.rb
95
+ - spec/schemaker/model/subject_spec.rb
96
+ - spec/schemaker/models_spec.rb
97
+ - spec/spec_helper.rb
98
+ homepage: http://github.com/kristianmandrup/schemaker
99
+ licenses:
100
+ - MIT
101
+ post_install_message:
102
+ rdoc_options: []
103
+ require_paths:
104
+ - lib
105
+ required_ruby_version: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ segments:
112
+ - 0
113
+ hash: -374026981416273501
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ! '>='
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ requirements: []
121
+ rubyforge_project:
122
+ rubygems_version: 1.8.5
123
+ signing_key:
124
+ specification_version: 3
125
+ summary: Schema maker takes care of configuring your model schemas to map behavior
126
+ test_files: []