railsgarden-has_meta_data 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1 @@
1
+ * [0.1.0] Initial Version
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 [name of plugin creator]
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/Manifest ADDED
@@ -0,0 +1,16 @@
1
+ CHANGELOG
2
+ has_meta_data_plugin.sqlite3
3
+ init.rb
4
+ install.rb
5
+ lib/has_meta_data.rb
6
+ Manifest
7
+ MIT-LICENSE
8
+ Rakefile
9
+ README.rdoc
10
+ tasks/has_meta_data_tasks.rake
11
+ test/config/database.yml
12
+ test/has_meta_data_test.rb
13
+ test/models/article.rb
14
+ test/schema.rb
15
+ test/test_helper.rb
16
+ uninstall.rb
data/README.rdoc ADDED
@@ -0,0 +1,82 @@
1
+ == Has Meta Data
2
+
3
+ This plugin allows you to extend one of your models with additional supplementary data stored in another table through a has_one relationship. The benefit of this plugin over a simple has_one is that the meta model class is dynamically defined (though extendable via the has_meta_data declaration) and fields on the meta model are automatically delegated to from the main model, allowing you to work solely with your primary model and not worry about the storage of the data in a separate meta table. This plugin also automatically handles creation of the meta model if you set a field on your model that exists in the meta model table.
4
+
5
+ Common use cases for this are database efficiency if only a small number of your records have a certain set of data or in conjunction with STI to accomplish something akin to Class Table Inheritance (CTI).
6
+
7
+ In short, it's a transparent way of splitting up data into two tables while still treating them as one model.
8
+
9
+ == Installation
10
+
11
+ # In environment.rb:
12
+ config.gem 'railsgarden-has_meta_data', :lib => 'has_meta_data', :source => 'http://gems.github.com'
13
+
14
+ == Basic Example
15
+
16
+ ## Database Schema
17
+ create_table :articles, :force => true do |t|
18
+ t.string :title
19
+ t.text :body
20
+ end
21
+
22
+ create_table :article_meta, :force => true do |t|
23
+ t.references :article
24
+ t.string :reference_link
25
+ t.text :reference_note
26
+ end
27
+
28
+ ## Model
29
+ class Article < ActiveRecord::Base
30
+ has_meta_data
31
+ end
32
+
33
+ ## Exposed Class Methods & Scopes:
34
+ Article.meta_data_class
35
+ => Article::Meta
36
+ Article.with_meta_data.all
37
+ => (Articles that have associated meta data)
38
+ Article.without_meta_data.all
39
+ => (Articles with no associated meta data)
40
+
41
+ ## Usage Examples:
42
+
43
+ article = Article.create(:title => 'Title', :body => 'Body')
44
+ article.has_meta_data? # => false
45
+
46
+ article.reference_link = 'http://benhughes.name/'
47
+ article.has_meta_data? # => true
48
+ article.meta
49
+ # => #<Article::Meta reference_link: "http://benhughes.name/", reference_note: nil>
50
+
51
+ article = Article.create(:title => 'Title', :body => 'Body', :reference_link => 'http://benhughes.name/')
52
+ article.has_meta_data? # => true
53
+ article.reference_link # => "http://benhughes.name/"
54
+
55
+ == Changing the Defaults
56
+
57
+ You can control the name of the meta class, foreign key, and table name not unlike ActiveRecord associations:
58
+
59
+ class Article < ActiveRecord::Base
60
+ has_meta_data :class_name => 'AdditionalData',
61
+ :foreign_key => 'news_article_id',
62
+ :table_name => 'news_article_additional_data'
63
+ end
64
+
65
+
66
+ == Extending the Meta Data Class
67
+
68
+ Because you don't directly define the meta data class, you can specify a block of code to be run in its
69
+ context by passing a block to has_draft:
70
+
71
+ class Article < ActiveRecord::Base
72
+ belongs_to :user
73
+
74
+ has_meta_data do
75
+ belongs_to :some_author
76
+
77
+ def do_something
78
+ # Something
79
+ end
80
+ end
81
+
82
+ end
data/Rakefile ADDED
@@ -0,0 +1,36 @@
1
+ require 'rubygems'
2
+ require 'echoe'
3
+ require 'rake'
4
+ require 'rake/testtask'
5
+ require 'rake/rdoctask'
6
+
7
+ desc 'Default: run unit tests.'
8
+ task :default => :test
9
+
10
+ desc 'Test the has_meta_data plugin.'
11
+ Rake::TestTask.new(:test) do |t|
12
+ t.libs << 'lib'
13
+ t.pattern = 'test/**/*_test.rb'
14
+ t.verbose = true
15
+ end
16
+
17
+ desc 'Generate documentation for the has_meta_data plugin.'
18
+ Rake::RDocTask.new(:rdoc) do |rdoc|
19
+ rdoc.rdoc_dir = 'rdoc'
20
+ rdoc.title = 'HasMetaData'
21
+ rdoc.options << '--line-numbers' << '--inline-source'
22
+ rdoc.rdoc_files.include('README')
23
+ rdoc.rdoc_files.include('lib/**/*.rb')
24
+ end
25
+
26
+ Echoe.new('has_meta_data', '0.1.0') do |p|
27
+ p.description = "Create one model backed by a primary table and a supplementary 'meta' table."
28
+ p.url = "http://github.com/railsgarden/has_meta_data"
29
+ p.author = "Ben Hughes"
30
+ p.email = "ben@railsgarden.com"
31
+ p.ignore_pattern = ["tmp/*", "script/*"]
32
+ p.development_dependencies = []
33
+ end
34
+
35
+ Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
36
+
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{has_meta_data}
5
+ s.version = "0.1.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Ben Hughes"]
9
+ s.date = %q{2009-01-16}
10
+ s.description = %q{Create one model backed by a primary table and a supplementary 'meta' table.}
11
+ s.email = %q{ben@railsgarden.com}
12
+ s.extra_rdoc_files = ["CHANGELOG", "lib/has_meta_data.rb", "README.rdoc", "tasks/has_meta_data_tasks.rake"]
13
+ s.files = ["CHANGELOG", "has_meta_data.gemspec", "init.rb", "install.rb", "lib/has_meta_data.rb", "Manifest", "MIT-LICENSE", "Rakefile", "README.rdoc", "tasks/has_meta_data_tasks.rake", "test/config/database.yml", "test/has_meta_data_test.rb", "test/models/article.rb", "test/schema.rb", "test/test_helper.rb", "uninstall.rb"]
14
+ s.has_rdoc = true
15
+ s.homepage = %q{http://github.com/railsgarden/has_meta_data}
16
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Has_meta_data", "--main", "README.rdoc"]
17
+ s.require_paths = ["lib"]
18
+ s.rubyforge_project = %q{has_meta_data}
19
+ s.rubygems_version = %q{1.3.1}
20
+ s.summary = %q{Create one model backed by a primary table and a supplementary 'meta' table.}
21
+ s.test_files = ["test/has_meta_data_test.rb", "test/test_helper.rb"]
22
+
23
+ if s.respond_to? :specification_version then
24
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
25
+ s.specification_version = 2
26
+
27
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
28
+ else
29
+ end
30
+ else
31
+ end
32
+ end
data/init.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'has_meta_data'
2
+
3
+ ActiveRecord::Base.send(:include, Rubiety::HasMetaData)
data/install.rb ADDED
@@ -0,0 +1 @@
1
+ # Install hook code here
@@ -0,0 +1,69 @@
1
+ module Rubiety
2
+ module HasMetaData
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ end
6
+
7
+ module ClassMethods
8
+ def has_meta_data(options = {}, &block)
9
+ return if self.included_modules.include?(HasMetaData::InstanceMethods)
10
+ include HasMetaData::InstanceMethods
11
+
12
+ cattr_accessor :meta_data_class_name, :meta_data_foreign_key, :meta_data_table_name, :meta_data_columns
13
+
14
+ self.meta_data_class_name = options[:class_name] || 'Meta'
15
+ self.meta_data_foreign_key = options[:foreign_key] || self.to_s.foreign_key
16
+ self.meta_data_table_name = options[:table_name] || "#{table_name_prefix}#{self.name.demodulize.underscore}_meta#{table_name_suffix}"
17
+
18
+
19
+ # Create Relationship to Meta Data
20
+ class_eval do
21
+ has_one :meta,
22
+ :class_name => "#{self.to_s}::#{meta_data_class_name}",
23
+ :foreign_key => meta_data_foreign_key,
24
+ :dependent => :destroy
25
+
26
+ named_scope :with_meta, :include => [:meta], :conditions => "#{meta_data_table_name}.id IS NOT NULL"
27
+ named_scope :without_meta, :include => [:meta], :conditions => "#{meta_data_table_name}.id IS NULL"
28
+ end
29
+
30
+ # Dynamically Create Model::Meta Class
31
+ const_set(meta_data_class_name, Class.new(ActiveRecord::Base))
32
+
33
+ meta_data_class.cattr_accessor :original_class
34
+ meta_data_class.original_class = self
35
+ meta_data_class.set_table_name(meta_data_table_name)
36
+
37
+ # Draft Parent Association
38
+ meta_data_class.belongs_to self.to_s.demodulize.underscore.to_sym, :class_name => "::#{self.to_s}", :foreign_key => meta_data_foreign_key
39
+
40
+ # Block extension
41
+ meta_data_class.class_eval(&block) if block_given?
42
+
43
+ # Finally setup attribute delegation to the meta fields
44
+ self.meta_data_columns = meta_data_class.content_columns.map(&:name)
45
+
46
+ meta_data_columns.each do |field|
47
+ define_method(field.to_sym) do
48
+ meta.send(field.to_sym) if has_meta_data?
49
+ end
50
+
51
+ define_method("#{field}=".to_sym) do |value|
52
+ self.build_meta unless has_meta_data?
53
+ meta.send("#{field}=".to_sym, value)
54
+ end
55
+ end
56
+ end
57
+
58
+ def meta_data_class
59
+ const_get(meta_data_class_name)
60
+ end
61
+ end
62
+
63
+ module InstanceMethods
64
+ def has_meta_data?
65
+ !self.meta.nil?
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :has_meta_data do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,18 @@
1
+ sqlite:
2
+ :adapter: sqlite
3
+ :dbfile: has_meta_data_plugin.sqlite
4
+ sqlite3:
5
+ :adapter: sqlite3
6
+ :dbfile: has_meta_data_plugin.sqlite3
7
+ postgresql:
8
+ :adapter: postgresql
9
+ :username: postgres
10
+ :password: postgres
11
+ :database: has_meta_data_plugin_test
12
+ :min_messages: ERROR
13
+ mysql:
14
+ :adapter: mysql
15
+ :host: localhost
16
+ :username: root
17
+ :password:
18
+ :database: has_meta_data_plugin_test
@@ -0,0 +1,93 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+ require File.join(File.dirname(__FILE__), 'models/article')
3
+
4
+ class ArticleTest < Test::Unit::TestCase
5
+
6
+ context "Article model" do
7
+ should_have_one :meta
8
+ should_have_named_scope :with_meta
9
+ should_have_named_scope :without_meta
10
+
11
+ should_have_class_methods :meta_data_class_name, :meta_data_foreign_key, :meta_data_table_name
12
+
13
+ should "default class name to Meta" do
14
+ assert_equal "Meta", Article.meta_data_class_name
15
+ end
16
+
17
+ should "expose meta class constant" do
18
+ assert_equal Article::Meta, Article.meta_data_class
19
+ end
20
+
21
+ should "default foreign key to article_id" do
22
+ assert_equal "article_id", Article.meta_data_foreign_key
23
+ end
24
+
25
+ should "default table name to article_meta" do
26
+ assert_equal "article_meta", Article.meta_data_table_name
27
+ end
28
+
29
+ should "detect correct meta data columns" do
30
+ assert_equal ['reference_link', 'reference_note'], Article.meta_data_columns
31
+ end
32
+
33
+ context "Meta model" do
34
+ should "have a be defined under Article" do
35
+ assert Article.constants.include?('Meta')
36
+ end
37
+
38
+ should "load" do
39
+ assert_nothing_raised do
40
+ Article::Meta
41
+ end
42
+ end
43
+
44
+ should "expose original class name of Article" do
45
+ assert_equal Article, Article::Meta.original_class
46
+ end
47
+ end
48
+ end
49
+
50
+ context "an new article without meta data" do
51
+ setup { @article = Article.new(:title => 'Title', :body => 'Body') }
52
+
53
+ should "not have meta data" do
54
+ assert !@article.has_meta_data?
55
+ end
56
+
57
+ should "return nil for meta data fields" do
58
+ assert_nil @article.reference_link
59
+ assert_nil @article.reference_note
60
+ end
61
+ end
62
+
63
+ context "a new article with meta data" do
64
+ setup { @article = Article.new(:title => 'Title', :body => 'Body', :reference_link => 'http://benhughes.name/') }
65
+
66
+ should "have meta data" do
67
+ assert @article.has_meta_data?
68
+ end
69
+
70
+ should "return values for meta data fields" do
71
+ assert_equal 'http://benhughes.name/', @article.reference_link
72
+ assert_nil @article.reference_note
73
+ end
74
+ end
75
+
76
+ context "a new article after setting meta data fields through mutators" do
77
+ setup do
78
+ @article = Article.new(:title => 'Title', :body => 'Body')
79
+ @article.reference_link = 'http://benhughes.name/'
80
+ @article.reference_note = 'Ben Hughes Author'
81
+ end
82
+
83
+ should "have meta data" do
84
+ assert @article.has_meta_data?
85
+ end
86
+
87
+ should "return values for meta data fields" do
88
+ assert_equal 'http://benhughes.name/', @article.reference_link
89
+ assert_equal 'Ben Hughes Author', @article.reference_note
90
+ end
91
+ end
92
+
93
+ end
@@ -0,0 +1,3 @@
1
+ class Article < ActiveRecord::Base
2
+ has_meta_data
3
+ end
data/test/schema.rb ADDED
@@ -0,0 +1,14 @@
1
+ ActiveRecord::Schema.define(:version => 0) do
2
+
3
+ create_table :articles, :force => true do |t|
4
+ t.string :title
5
+ t.text :body
6
+ end
7
+
8
+ create_table :article_meta, :force => true do |t|
9
+ t.references :article
10
+ t.string :reference_link
11
+ t.text :reference_note
12
+ end
13
+
14
+ end
@@ -0,0 +1,25 @@
1
+ require 'test/unit'
2
+ require 'rubygems'
3
+ require 'active_record'
4
+ require 'active_record/fixtures'
5
+ require 'shoulda/rails'
6
+
7
+ require File.expand_path(File.join(File.dirname(__FILE__), '../lib/has_meta_data'))
8
+
9
+ config = YAML::load(IO.read(File.join(File.dirname(__FILE__), 'config', '/database.yml')))
10
+ ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
11
+ ActiveRecord::Base.configurations = {'test' => config[ENV['DB'] || 'sqlite3']}
12
+ ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])
13
+
14
+ load(File.dirname(__FILE__) + "/schema.rb")
15
+
16
+ Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/"
17
+ $:.unshift(Test::Unit::TestCase.fixture_path)
18
+ $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))
19
+
20
+ class Test::Unit::TestCase
21
+ self.use_transactional_fixtures = true
22
+ self.use_instantiated_fixtures = false
23
+ end
24
+
25
+ require File.expand_path(File.join(File.dirname(__FILE__), '../init'))
data/uninstall.rb ADDED
@@ -0,0 +1 @@
1
+ # Uninstall hook code here
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: railsgarden-has_meta_data
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ben Hughes
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-01-16 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Create one model backed by a primary table and a supplementary 'meta' table.
17
+ email: ben@railsgarden.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - CHANGELOG
24
+ - lib/has_meta_data.rb
25
+ - README.rdoc
26
+ - tasks/has_meta_data_tasks.rake
27
+ files:
28
+ - CHANGELOG
29
+ - has_meta_data.gemspec
30
+ - init.rb
31
+ - install.rb
32
+ - lib/has_meta_data.rb
33
+ - Manifest
34
+ - MIT-LICENSE
35
+ - Rakefile
36
+ - README.rdoc
37
+ - tasks/has_meta_data_tasks.rake
38
+ - test/config/database.yml
39
+ - test/has_meta_data_test.rb
40
+ - test/models/article.rb
41
+ - test/schema.rb
42
+ - test/test_helper.rb
43
+ - uninstall.rb
44
+ has_rdoc: true
45
+ homepage: http://github.com/railsgarden/has_meta_data
46
+ post_install_message:
47
+ rdoc_options:
48
+ - --line-numbers
49
+ - --inline-source
50
+ - --title
51
+ - Has_meta_data
52
+ - --main
53
+ - README.rdoc
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: "0"
61
+ version:
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: "1.2"
67
+ version:
68
+ requirements: []
69
+
70
+ rubyforge_project: has_meta_data
71
+ rubygems_version: 1.2.0
72
+ signing_key:
73
+ specification_version: 2
74
+ summary: Create one model backed by a primary table and a supplementary 'meta' table.
75
+ test_files:
76
+ - test/has_meta_data_test.rb
77
+ - test/test_helper.rb