activerecord-model-spaces 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,5 @@
1
+ script: "JRUBY_OPTS=-J-Djruby.objectspace.enabled=true rake"
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.3
5
+ - jruby
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "rake", ">= 0.8.7"
4
+ gem "activerecord", ">= 2.3.0"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "rspec", "~> 2.12.0"
10
+ gem "rdoc", "~> 3.12"
11
+ gem "bundler", "~> 1.2.3"
12
+ gem "jeweler", "~> 1.8.4"
13
+ gem "rcov", ">= 0", :platforms => :mri_18
14
+ gem "simplecov", ">= 0", :platforms => :mri_19
15
+ end
@@ -0,0 +1,56 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activemodel (3.2.11)
5
+ activesupport (= 3.2.11)
6
+ builder (~> 3.0.0)
7
+ activerecord (3.2.11)
8
+ activemodel (= 3.2.11)
9
+ activesupport (= 3.2.11)
10
+ arel (~> 3.0.2)
11
+ tzinfo (~> 0.3.29)
12
+ activesupport (3.2.11)
13
+ i18n (~> 0.6)
14
+ multi_json (~> 1.0)
15
+ arel (3.0.2)
16
+ builder (3.0.4)
17
+ diff-lcs (1.1.3)
18
+ git (1.2.5)
19
+ i18n (0.6.1)
20
+ jeweler (1.8.4)
21
+ bundler (~> 1.0)
22
+ git (>= 1.2.5)
23
+ rake
24
+ rdoc
25
+ json (1.7.6)
26
+ multi_json (1.5.0)
27
+ rake (10.0.3)
28
+ rcov (1.0.0)
29
+ rdoc (3.12)
30
+ json (~> 1.4)
31
+ rspec (2.12.0)
32
+ rspec-core (~> 2.12.0)
33
+ rspec-expectations (~> 2.12.0)
34
+ rspec-mocks (~> 2.12.0)
35
+ rspec-core (2.12.2)
36
+ rspec-expectations (2.12.1)
37
+ diff-lcs (~> 1.1.3)
38
+ rspec-mocks (2.12.1)
39
+ simplecov (0.7.1)
40
+ multi_json (~> 1.0)
41
+ simplecov-html (~> 0.7.1)
42
+ simplecov-html (0.7.1)
43
+ tzinfo (0.3.35)
44
+
45
+ PLATFORMS
46
+ ruby
47
+
48
+ DEPENDENCIES
49
+ activerecord (>= 2.3.0)
50
+ bundler (~> 1.2.3)
51
+ jeweler (~> 1.8.4)
52
+ rake (>= 0.8.7)
53
+ rcov
54
+ rdoc (~> 3.12)
55
+ rspec (~> 2.12.0)
56
+ simplecov
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 mccraig mccraig of the clan mccraig
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.
@@ -0,0 +1,98 @@
1
+ = activerecord-model-spaces
2
+
3
+ {<img src="https://travis-ci.org/mccraigmccraig/activerecord-model-spaces.png?branch=master" alt="Build Status" />}[https://travis-ci.org/mccraigmccraig/activerecord-model-spaces]
4
+ {<img src="https://codeclimate.com/badge.png" alt="Code Climate"/>}[https://codeclimate.com/github/mccraigmccraig/activerecord-model-spaces]
5
+
6
+ Provides a means of contextually associating sets of ActiveRecord models with database tables through a <tt>table_name</tt> method implementation
7
+
8
+ This can be used to maintain multiple independent versions of model datasets, for applications including multi-tenancy
9
+
10
+ Additionally, each model participating in a ModelSpace can optionally be assigned a number of "history versions", and methods are provided to create new or updated versions of the datasets in a ModelSpace without causing locks or large transactions
11
+
12
+ Models which participate in a ModelSpace need only make sure that they use the <tt>table_name</tt> method whenever they refer to the database table. Since all ActiveRecord methods already do this, it is only application methods which generate SQL which must take care
13
+
14
+ == Installation
15
+
16
+ gem "activerecord-model-spaces", "~> 0.1.0"
17
+
18
+ == Usage
19
+
20
+ Include the <tt>ActiveRecord::ModelSpaces</tt> module in a model Class, and declare the model to be part of a ModelSpace, optionally specifying a number of history versions (which defaults to 0) and a base table name (from which contextual table names are constructed, and which defaults to the normal table name)
21
+
22
+ require 'active_record/model_spaces'
23
+
24
+ class AModel < ActiveRecord::Base
25
+ include ActiveRecord::ModelSpaces
26
+
27
+ in_model_space :metadata, :history_versions=>1, :base_table_name=>"unusual_models"
28
+ end
29
+
30
+ Each ModelSpace may have many models associated with it, but each model may only be associated with a single ModelSpace
31
+
32
+ At this point, the model can be used in ModelSpaces context, and data will be sourced from a different table according to the context, the context key and any history version. Outside of a ModelSpaces context the model will source data from it's usual table
33
+
34
+ To establish a context use the <tt>with_context</tt> method, which provides a key to be used along with the ModelSpace name to generate the name of the database table to be used by the model for the duration of the context
35
+
36
+ AModel.table_name # "unusual_models"
37
+
38
+ ActiveRecord::ModelSpaces.with_context(:metadata, :one) do
39
+ AModel.table_name # "metadata__one__unusual_models"
40
+ end
41
+
42
+ If the table to be used by a model within a context does not exist it will be created when the context is created. The created table will have the same schema as the normal model table
43
+
44
+ If a model is declared as having history_versions then historical copies of the tables will be maintained. New or updated versions of a model can be created using the new_version and updated_version class methods on the model Class, while a context for the ModelSpace is established. The new versions are only visible within the context that they are created in, until the context complete without Error, at which point any new context established for that ModelSpace will use the newly created versions. Table names wrap once the given number of history version tables have been used
45
+
46
+ class BModel < ActiveRecord::Base
47
+ include ActiveRecord::ModelSpaces
48
+
49
+ in_model_space :metadata, :history_versions=>1
50
+ end
51
+
52
+ ActiveRecord::ModelSpaces.with_context(:metadata, :one) do
53
+ AModel.table_name # "metadata__one__unusual_models"
54
+
55
+ AModel.new_version do
56
+ AModel.table_name # "metadata__one__unusual_models__1"
57
+ end
58
+
59
+ AModel.table_name # "metadata__one__unusual_models__1"
60
+
61
+ BModel.table_name # "metadata__one__b_models"
62
+
63
+ BModel.updated_version do
64
+ BModel.table_name # "metadata__one__b_models__1"
65
+ end
66
+
67
+ BModel.table_name # "metadata__one__b_models__1"
68
+ end
69
+
70
+ ActiveRecord::ModelSpaces.with_context(:metadata, :one) do
71
+ AModel.table_name # "metadata__one__unusual_models__1"
72
+ BModel.table_name # "metadata__one__b_models__1"
73
+
74
+ AModel.new_version do
75
+ AModel.table_name # "metadata__one__unusual_models"
76
+ end
77
+
78
+ AModel.table_name # "metadata__one__unusual_models"
79
+ end
80
+
81
+ ActiveRecord::ModelSpaces.with_context(:metadata, :one) do
82
+ AModel.table_name # "metadata__one__unusual_models"
83
+ end
84
+
85
+ == Contributing to activerecord-model-spaces
86
+
87
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
88
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
89
+ * Fork the project.
90
+ * Start a feature/bugfix branch.
91
+ * Commit and push until you are happy with your contribution.
92
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
93
+ * 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.
94
+
95
+ == Copyright
96
+
97
+ Copyright (c) 2013 mccraig mccraig of the clan mccraig. See LICENSE.txt for
98
+ further details.
@@ -0,0 +1,55 @@
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 = "activerecord-model-spaces"
18
+ gem.homepage = "http://github.com/mccraigmccraig/activerecord-model-spaces"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{manage activerecord model to table mappings}
21
+ gem.description = %Q{map activerecord models to tables depending on context}
22
+ gem.email = "mccraigmccraig@gmail.com"
23
+ gem.authors = ["mccraig mccraig of the clan mccraig"]
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
+ RSpec::Core::RakeTask.new(:simplecov) do |spec|
40
+ spec.pattern = 'spec/**/*_spec.rb'
41
+ ENV['SIMPLECOV'] = "true"
42
+ # `open coverage/index.html`
43
+ end
44
+
45
+ task :default => :spec
46
+
47
+ require 'rdoc/task'
48
+ Rake::RDocTask.new do |rdoc|
49
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
50
+
51
+ rdoc.rdoc_dir = 'rdoc'
52
+ rdoc.title = "activerecord-model-spaces #{version}"
53
+ rdoc.rdoc_files.include('README*')
54
+ rdoc.rdoc_files.include('lib/**/*.rb')
55
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.0
@@ -0,0 +1,87 @@
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 = "activerecord-model-spaces"
8
+ s.version = "0.2.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["mccraig mccraig of the clan mccraig"]
12
+ s.date = "2013-02-20"
13
+ s.description = "map activerecord models to tables depending on context"
14
+ s.email = "mccraigmccraig@gmail.com"
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".rspec",
22
+ ".travis.yml",
23
+ "Gemfile",
24
+ "Gemfile.lock",
25
+ "LICENSE.txt",
26
+ "README.rdoc",
27
+ "Rakefile",
28
+ "VERSION",
29
+ "activerecord-model-spaces.gemspec",
30
+ "lib/active_record/model_spaces.rb",
31
+ "lib/active_record/model_spaces/context.rb",
32
+ "lib/active_record/model_spaces/model_space.rb",
33
+ "lib/active_record/model_spaces/persistor.rb",
34
+ "lib/active_record/model_spaces/registry.rb",
35
+ "lib/active_record/model_spaces/table_manager.rb",
36
+ "lib/active_record/model_spaces/table_names.rb",
37
+ "lib/active_record/model_spaces/util.rb",
38
+ "spec/active_record/model_spaces/context_spec.rb",
39
+ "spec/active_record/model_spaces/model_space_spec.rb",
40
+ "spec/active_record/model_spaces/persistor_spec.rb",
41
+ "spec/active_record/model_spaces/registry_spec.rb",
42
+ "spec/active_record/model_spaces/table_manager_spec.rb",
43
+ "spec/active_record/model_spaces/table_names_spec.rb",
44
+ "spec/active_record/model_spaces/util_spec.rb",
45
+ "spec/active_record/model_spaces_spec.rb",
46
+ "spec/spec_helper.rb"
47
+ ]
48
+ s.homepage = "http://github.com/mccraigmccraig/activerecord-model-spaces"
49
+ s.licenses = ["MIT"]
50
+ s.require_paths = ["lib"]
51
+ s.rubygems_version = "1.8.23"
52
+ s.summary = "manage activerecord model to table mappings"
53
+
54
+ if s.respond_to? :specification_version then
55
+ s.specification_version = 3
56
+
57
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
58
+ s.add_runtime_dependency(%q<rake>, [">= 0.8.7"])
59
+ s.add_runtime_dependency(%q<activerecord>, [">= 2.3.0"])
60
+ s.add_development_dependency(%q<rspec>, ["~> 2.12.0"])
61
+ s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
62
+ s.add_development_dependency(%q<bundler>, ["~> 1.2.3"])
63
+ s.add_development_dependency(%q<jeweler>, ["~> 1.8.4"])
64
+ s.add_development_dependency(%q<rcov>, [">= 0"])
65
+ s.add_development_dependency(%q<simplecov>, [">= 0"])
66
+ else
67
+ s.add_dependency(%q<rake>, [">= 0.8.7"])
68
+ s.add_dependency(%q<activerecord>, [">= 2.3.0"])
69
+ s.add_dependency(%q<rspec>, ["~> 2.12.0"])
70
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
71
+ s.add_dependency(%q<bundler>, ["~> 1.2.3"])
72
+ s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
73
+ s.add_dependency(%q<rcov>, [">= 0"])
74
+ s.add_dependency(%q<simplecov>, [">= 0"])
75
+ end
76
+ else
77
+ s.add_dependency(%q<rake>, [">= 0.8.7"])
78
+ s.add_dependency(%q<activerecord>, [">= 2.3.0"])
79
+ s.add_dependency(%q<rspec>, ["~> 2.12.0"])
80
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
81
+ s.add_dependency(%q<bundler>, ["~> 1.2.3"])
82
+ s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
83
+ s.add_dependency(%q<rcov>, [">= 0"])
84
+ s.add_dependency(%q<simplecov>, [">= 0"])
85
+ end
86
+ end
87
+
@@ -0,0 +1,89 @@
1
+ require 'active_record'
2
+
3
+ require 'active_record/model_spaces/registry'
4
+
5
+ # Include this module in an ActiveRecord model to enable participation of the model
6
+ # in a ModelSpace.
7
+ #
8
+ # A ModelSpace has a name and, for each model, a number of history versions >= 0
9
+ #
10
+ # Once participating in a ModelSpace, a Context must be established before
11
+ # the model can be used. The context specifies a prefix and manages versioning
12
+ #
13
+ module ActiveRecord
14
+ module ModelSpaces
15
+
16
+ REGISTRY = Registry.new
17
+
18
+ def self.included(mod)
19
+ class << mod
20
+ include ClassMethods
21
+ end
22
+ end
23
+
24
+ module_function
25
+
26
+ def with_context(model_space_name, model_space_key, &block)
27
+ REGISTRY.with_context(model_space_name, model_space_key, &block)
28
+ end
29
+
30
+ def active_key(model_space_name)
31
+ REGISTRY.active_key(model_space_name)
32
+ end
33
+
34
+ def kill_context(model_space_name, model_space_key)
35
+ REGISTRY.kill_context(model_space_name, model_space_key)
36
+ end
37
+
38
+ def enforce_context
39
+ REGISTRY.enforce_context
40
+ end
41
+
42
+ def set_enforce_context(ec)
43
+ REGISTRY.set_enforce_context(ec)
44
+ end
45
+
46
+ module ClassMethods
47
+
48
+ # register a model as belonging to a model space
49
+ def in_model_space(model_space_name, opts={})
50
+ REGISTRY.register_model(self, model_space_name, opts)
51
+ end
52
+
53
+ def set_table_name(table_name)
54
+ REGISTRY.set_base_table_name(self, table_name)
55
+ end
56
+
57
+ def table_name=(table_name)
58
+ REGISTRY.set_base_table_name(self, table_name)
59
+ end
60
+
61
+ def table_name
62
+ ActiveRecord::ModelSpaces::REGISTRY.table_name(self)
63
+ end
64
+
65
+ def current_table_name
66
+ REGISTRY.current_table_name(self)
67
+ end
68
+
69
+ def working_table_name
70
+ REGISTRY.working_table_name(self)
71
+ end
72
+
73
+ # create a new version of the model
74
+ def new_version(&block)
75
+ REGISTRY.new_version(self, &block)
76
+ end
77
+
78
+ # create an updated version of the model
79
+ def updated_version(&block)
80
+ REGISTRY.updated_version(self, &block)
81
+ end
82
+
83
+ def hoover
84
+ REGISTRY.hoover(self)
85
+ end
86
+ end
87
+
88
+ end
89
+ end