has_content 0.0.2
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/CHANGELOG +2 -0
- data/MIT-LICENSE +24 -0
- data/README.md +13 -0
- data/Rakefile +42 -0
- data/db/migrate/create_has_content_records.rb +11 -0
- data/lib/has_content/active_record.rb +24 -0
- data/lib/has_content/content_owner.rb +63 -0
- data/lib/has_content/engine.rb +4 -0
- data/lib/has_content/record.rb +42 -0
- data/lib/has_content/version.rb +3 -0
- data/lib/has_content.rb +9 -0
- data/spec/content_owner_spec.rb +41 -0
- data/spec/has_content/active_record_spec.rb +35 -0
- data/spec/has_content/record_spec.rb +55 -0
- data/spec/owner_shared.rb +54 -0
- data/spec/spec_helper.rb +30 -0
- data/spec/test_app.rb +18 -0
- metadata +130 -0
data/CHANGELOG
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
Copyright 2012 Ian White
|
2
|
+
|
3
|
+
This plugin was developed by Ian White (http://github.com/ianwhite)
|
4
|
+
while working at Distinctive Doors (http://distinctivedoors.co.uk/oss)
|
5
|
+
who have kindly agreed to release this under the MIT-LICENSE.
|
6
|
+
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
8
|
+
a copy of this software and associated documentation files (the
|
9
|
+
"Software"), to deal in the Software without restriction, including
|
10
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
11
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
12
|
+
permit persons to whom the Software is furnished to do so, subject to
|
13
|
+
the following conditions:
|
14
|
+
|
15
|
+
The above copyright notice and this permission notice shall be
|
16
|
+
included in all copies or substantial portions of the Software.
|
17
|
+
|
18
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
20
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
22
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
23
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
24
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
has_content [](http://travis-ci.org/i2w/has_content)
|
2
|
+
======
|
3
|
+
|
4
|
+
Add a content relation to any active_record, which acts like a text field, but is actually a separate object.
|
5
|
+
|
6
|
+
This means it's very easy to add/remove fields, but also the contents can be objects in their own right (useful for editing CMS stuff etc)
|
7
|
+
|
8
|
+
This was developed by [Ian White](http://github.com/ianwhite) while working at [Distinctive Doors](http://distinctivedoors.co.uk/oss) who have kindly agreed to release this under the MIT-LICENSE.
|
9
|
+
|
10
|
+
License
|
11
|
+
-------
|
12
|
+
|
13
|
+
This project uses the MIT-LICENSE.
|
data/Rakefile
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'HasContent'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.md', 'CHANGELOG', 'MIT-LICENSE')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
require 'rspec/core/rake_task'
|
24
|
+
|
25
|
+
RSpec::Core::RakeTask.new(:spec)
|
26
|
+
|
27
|
+
desc "Run the specs with simplecov"
|
28
|
+
task :simplecov => [:simplecov_env, :spec]
|
29
|
+
task :simplecov_env do ENV['SIMPLECOV'] = '1' end
|
30
|
+
|
31
|
+
task :default => :spec
|
32
|
+
|
33
|
+
Bundler::GemHelper.install_tasks
|
34
|
+
|
35
|
+
task :release => :check_gemfile
|
36
|
+
|
37
|
+
task :check_gemfile do
|
38
|
+
if File.exists?("Gemfile.lock") && File.read("Gemfile.lock") != File.read("Gemfile.lock.development")
|
39
|
+
cp "Gemfile.lock", "Gemfile.lock.development"
|
40
|
+
raise "** Gemfile.lock.development has been updated, please commit these changes."
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class CreateHasContentRecords < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :has_content_records, :force => true do |t|
|
4
|
+
t.belongs_to :owner, :polymorphic => true
|
5
|
+
t.string :name
|
6
|
+
t.text :content
|
7
|
+
t.timestamps
|
8
|
+
end
|
9
|
+
add_index :has_content_records, [:owner_id, :owner_type, :name], :unique => true
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module HasContent
|
2
|
+
# has_content concern: allow spcification of content on models
|
3
|
+
#
|
4
|
+
# content is a polymorphic association that is laoded on demand, and appears as if it were a normal attribute.
|
5
|
+
# The advantages being that you can add content to models without modifying the database schema, and that you
|
6
|
+
# can treat pieces of content as objects in their own right (for example in place editing).
|
7
|
+
#
|
8
|
+
# class MyModel
|
9
|
+
# has_content :body, :sidebar
|
10
|
+
# end
|
11
|
+
module ActiveRecord
|
12
|
+
extend ActiveSupport::Concern
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
# specify that this class has the following named content
|
16
|
+
def has_content *names
|
17
|
+
include ContentOwner unless self < ContentOwner
|
18
|
+
options = names.extract_options!
|
19
|
+
raise ArgumentError, "you must supply at least one content name" if names.size == 0
|
20
|
+
names.each {|name| add_content(name.to_s, options)}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module HasContent
|
2
|
+
module ContentOwner
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
delegate :content_names, :content_association_names, :to => 'self.class'
|
7
|
+
class_attribute :content_names
|
8
|
+
self.content_names ||= []
|
9
|
+
end
|
10
|
+
|
11
|
+
# return a hash of content attributes with their content only (for loaded content only)
|
12
|
+
def content_attributes
|
13
|
+
content_names.inject({}) do |attrs, name|
|
14
|
+
attrs.merge!(name => send(name)) if send("#{name}_content")
|
15
|
+
attrs
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# include content_attributes in attributes hash
|
20
|
+
def attributes
|
21
|
+
super.merge content_attributes
|
22
|
+
end
|
23
|
+
|
24
|
+
module ClassMethods
|
25
|
+
def content_association_names
|
26
|
+
content_names.map {|name| "#{name}_content"}
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
def add_content name, options = {}
|
31
|
+
raise ArgumentError, "name should be suitable for a simple attribute method" unless name =~ /\A[_a-z][_a-z0-9]+\Z/i
|
32
|
+
if content_names.include?(name)
|
33
|
+
raise ArgumentError, "Content #{name} is already declared in #{self.name}"
|
34
|
+
else
|
35
|
+
add_content_association name, options
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def add_content_association name, options
|
40
|
+
content_names << name
|
41
|
+
|
42
|
+
has_one "#{name}_content".to_sym, options.reverse_merge(:as => 'owner', :class_name => 'HasContent::Record', :dependent => :destroy, :conditions => {name: name}, :autosave => true)
|
43
|
+
|
44
|
+
define_method name do
|
45
|
+
send("find_or_build_#{name}_content").content
|
46
|
+
end
|
47
|
+
|
48
|
+
define_method "#{name}=" do |value|
|
49
|
+
(send("find_or_build_#{name}_content").content = value).tap do |*|
|
50
|
+
if respond_to?(:updated_at?) && send("find_or_build_#{name}_content").changed?
|
51
|
+
updated_at_will_change!
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
define_method "find_or_build_#{name}_content" do
|
57
|
+
send("#{name}_content") || send("build_#{name}_content", name: name)
|
58
|
+
end
|
59
|
+
private "find_or_build_#{name}_content".to_sym
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module HasContent
|
2
|
+
class Record < ActiveRecord::Base
|
3
|
+
self.table_name = 'has_content_records'
|
4
|
+
|
5
|
+
belongs_to :owner, polymorphic: true
|
6
|
+
|
7
|
+
validates :name, presence: true,
|
8
|
+
inclusion: {in: lambda(&:allowed_names), if: :owner},
|
9
|
+
uniqueness: {scope: %w(owner_id owner_type), if: :owner_persisted?}
|
10
|
+
|
11
|
+
before_create :verify_valid_owner! # this badboy is here because owner is sometimes not present at validation
|
12
|
+
# because content is a has_one on owner, with autosave true
|
13
|
+
|
14
|
+
# Contents are only ever instantiated by has_content assoc, and it's convenient for them to
|
15
|
+
# always refer (for links to content etc).
|
16
|
+
# If there is a validation problem, the save will fail silently (which is fine)
|
17
|
+
def initialize(*)
|
18
|
+
super
|
19
|
+
save if new_record? && owner_persisted?
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
content
|
24
|
+
end
|
25
|
+
|
26
|
+
def allowed_names
|
27
|
+
owner.try(:content_names) || []
|
28
|
+
end
|
29
|
+
|
30
|
+
protected
|
31
|
+
|
32
|
+
def owner_persisted?
|
33
|
+
owner && !owner.new_record?
|
34
|
+
end
|
35
|
+
|
36
|
+
# see the before_create hook above
|
37
|
+
def verify_valid_owner!
|
38
|
+
owner.reload # raises ActiveRecord::RecordNotFound if owner not found
|
39
|
+
valid? or raise ActiveRecord::RecordInvalid, self
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/has_content.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'has_content/version'
|
2
|
+
require 'has_content/record'
|
3
|
+
require 'has_content/content_owner'
|
4
|
+
require 'has_content/active_record'
|
5
|
+
require 'has_content/engine' if defined?(Rails)
|
6
|
+
|
7
|
+
ActiveSupport.on_load(:active_record) do
|
8
|
+
include HasContent::ActiveRecord
|
9
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'owner_shared'
|
3
|
+
|
4
|
+
describe ContentOwner do
|
5
|
+
let(:owner) { described_class.new }
|
6
|
+
let(:content_name) { :body }
|
7
|
+
|
8
|
+
it_should_behave_like "new owner with has_content"
|
9
|
+
|
10
|
+
its(:content_names) { should == ['body', 'excerpt', 'sidebar'] }
|
11
|
+
|
12
|
+
its(:content_association_names) { should == ['body_content', 'excerpt_content', 'sidebar_content'] }
|
13
|
+
|
14
|
+
describe "subclass" do
|
15
|
+
let(:klass) { Class.new(described_class) }
|
16
|
+
let(:owner) { klass.new }
|
17
|
+
|
18
|
+
it_should_behave_like "new owner with has_content"
|
19
|
+
|
20
|
+
context 'after adding new content :thingo' do
|
21
|
+
before(:all) do klass.has_content :thingo end
|
22
|
+
|
23
|
+
its(:content_names) { should == ['body', 'excerpt', 'sidebar', 'thingo'] }
|
24
|
+
|
25
|
+
its(:content_association_names) { should == ['body_content', 'excerpt_content', 'sidebar_content', 'thingo_content'] }
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'when a content attribute is protected' do
|
29
|
+
before(:all) do klass.attr_protected :excerpt end
|
30
|
+
|
31
|
+
it 'setting via attributes fails' do
|
32
|
+
owner.attributes = {excerpt: 'foo', body: 'bar'}
|
33
|
+
owner.excerpt.should be_nil
|
34
|
+
owner.body.should == 'bar'
|
35
|
+
owner.save
|
36
|
+
owner.reload.body_content.content.should == 'bar'
|
37
|
+
owner.reload.excerpt_content.content.should be_nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HasContent::ActiveRecord do
|
4
|
+
subject { content_owner }
|
5
|
+
let(:content_owner) { Class.new(ActiveRecord::Base) }
|
6
|
+
|
7
|
+
describe '.has_content(name)' do
|
8
|
+
subject { content_owner.has_content(name) }
|
9
|
+
|
10
|
+
describe 'requires name be in a format suitable for a simple accessor method' do
|
11
|
+
['foo bar', '123bar', 'foo!', 'foo=', 'foo-bar', 'foo+bar'].each do |invalid|
|
12
|
+
context invalid.inspect do
|
13
|
+
let(:name) { invalid }
|
14
|
+
it { expect { subject }.to raise_error ArgumentError }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
['_foo', 'foo_bar', 'a123bar', 'foo', 'FooBar'].each do |valid|
|
19
|
+
context valid.inspect do
|
20
|
+
let(:name) { valid }
|
21
|
+
it { expect { subject }.to_not raise_error }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
it '.has_content() raises ArgumentError' do
|
28
|
+
expect{ content_owner.has_content }.to raise_error(ArgumentError)
|
29
|
+
end
|
30
|
+
|
31
|
+
it '.has_content(<extsiting name>) raises ArgumentError' do
|
32
|
+
content_owner.has_content(:foo)
|
33
|
+
expect{ content_owner.has_content(:foo) }.to raise_error(ArgumentError)
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HasContent::Record do
|
4
|
+
subject { record }
|
5
|
+
|
6
|
+
let(:record) { described_class.new attrs }
|
7
|
+
let(:attrs) { {} }
|
8
|
+
|
9
|
+
it "does not save itself - as it's invalid" do
|
10
|
+
should be_new_record
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'with valid attributes' do
|
14
|
+
let(:attrs) { {:name => 'body', :owner => owner} }
|
15
|
+
let(:owner) { ContentOwner.create! }
|
16
|
+
|
17
|
+
it "saves itself (to enable always referring relationships)" do
|
18
|
+
should_not be_new_record
|
19
|
+
end
|
20
|
+
|
21
|
+
it { should be_valid }
|
22
|
+
|
23
|
+
describe '[validation]' do
|
24
|
+
it 'requires :name' do
|
25
|
+
subject.name = nil
|
26
|
+
should_not be_valid
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'requires :name + :owner be unique' do
|
30
|
+
record.save!
|
31
|
+
record = described_class.new :name => 'body', :owner => owner
|
32
|
+
record.should_not be_valid
|
33
|
+
record.name = 'excerpt'
|
34
|
+
record.should be_valid
|
35
|
+
record.name = 'body'
|
36
|
+
record.owner = ContentOwner.create!
|
37
|
+
record.should be_valid
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'requires :name be one of owner\'s content_names' do
|
41
|
+
record.name = 'not_there'
|
42
|
+
record.should_not be_valid
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '#to_s' do
|
48
|
+
subject { record.to_s }
|
49
|
+
|
50
|
+
it 'is the content attribute' do
|
51
|
+
record.content = 'foo'
|
52
|
+
subject.should == 'foo'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
shared_examples_for "new owner with has_content" do
|
2
|
+
|
3
|
+
# set the following to use this shared spec:
|
4
|
+
#
|
5
|
+
# let(:owner) { a content owner instance }
|
6
|
+
# let(:content_name) { the name of the content }
|
7
|
+
|
8
|
+
it 'should be built on demand for #content reader' do
|
9
|
+
owner.send(content_name)
|
10
|
+
owner.send("#{content_name}_content").should be_kind_of(HasContent::Record)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should be built on demand for #content= writer' do
|
14
|
+
owner.send("#{content_name}=", 'foo')
|
15
|
+
owner.send("#{content_name}_content").content.should == 'foo'
|
16
|
+
end
|
17
|
+
|
18
|
+
it "content should have name == content_name" do
|
19
|
+
owner.send(content_name)
|
20
|
+
owner.send("#{content_name}_content").name.should == content_name.to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
it "after save and reload, should have content" do
|
24
|
+
owner.send("#{content_name}=", "foo")
|
25
|
+
owner.save!
|
26
|
+
owner.class.find(owner.id).send(content_name).should == "foo"
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should have content_attributes corresponding to contents' do
|
30
|
+
owner.send("#{content_name}=", "Foo")
|
31
|
+
owner.content_attributes[content_name.to_s].should == "Foo"
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should allow setting content via attributes" do
|
35
|
+
owner.update_attributes content_name => "Foo"
|
36
|
+
owner.reload.send(content_name).should == "Foo"
|
37
|
+
end
|
38
|
+
|
39
|
+
context '[before being saved]' do
|
40
|
+
it "should not create a content record until save" do
|
41
|
+
lambda { owner.send(content_name) }.should_not change(HasContent::Record, :count)
|
42
|
+
lambda { owner.save! }.should change(HasContent::Record, :count).by(1)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context '[after being saved]' do
|
47
|
+
before { owner.save! }
|
48
|
+
|
49
|
+
it 'should create content record on access' do
|
50
|
+
lambda { owner.send(content_name) }.should change(HasContent::Record, :count).by(1)
|
51
|
+
lambda { owner.save! }.should_not change(HasContent::Record, :count)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
ENV['RAILS_ENV'] = 'test'
|
2
|
+
|
3
|
+
if ENV['SIMPLECOV']
|
4
|
+
require 'simplecov'
|
5
|
+
SimpleCov.start do
|
6
|
+
add_filter "_spec.rb"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
begin
|
11
|
+
require 'pry'
|
12
|
+
rescue LoadError
|
13
|
+
end
|
14
|
+
|
15
|
+
require 'active_record'
|
16
|
+
require 'rspec'
|
17
|
+
require 'database_cleaner'
|
18
|
+
|
19
|
+
require_relative '../lib/has_content'
|
20
|
+
require_relative 'test_app'
|
21
|
+
|
22
|
+
DatabaseCleaner.strategy = :truncation
|
23
|
+
DatabaseCleaner.clean_with :truncation
|
24
|
+
|
25
|
+
RSpec.configure do |config|
|
26
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
27
|
+
|
28
|
+
config.before(:each) { DatabaseCleaner.start }
|
29
|
+
config.after(:each) { DatabaseCleaner.clean }
|
30
|
+
end
|
data/spec/test_app.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ":memory:")
|
2
|
+
|
3
|
+
ActiveRecord::Migration.suppress_messages do
|
4
|
+
ActiveRecord::Schema.define do
|
5
|
+
create_table(:content_owners, :force => true) do |t|
|
6
|
+
t.string :name
|
7
|
+
t.timestamps
|
8
|
+
end
|
9
|
+
|
10
|
+
require_relative '../db/migrate/create_has_content_records'
|
11
|
+
CreateHasContentRecords.new.change
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class ContentOwner < ActiveRecord::Base
|
16
|
+
has_content :body
|
17
|
+
has_content :excerpt, :sidebar
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: has_content
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ian White
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-20 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activerecord
|
16
|
+
requirement: &70244228437940 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '3.2'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70244228437940
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rake
|
27
|
+
requirement: &70244228459060 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70244228459060
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rspec
|
38
|
+
requirement: &70244228456400 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '2'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70244228456400
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: sqlite3
|
49
|
+
requirement: &70244228453880 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70244228453880
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: database_cleaner
|
60
|
+
requirement: &70244228452440 !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: *70244228452440
|
69
|
+
description: Simple wrapper for adding content via a polymorphic join for any active
|
70
|
+
record. Version 0.0.2.
|
71
|
+
email:
|
72
|
+
- ian.w.white@gmail.com
|
73
|
+
executables: []
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- db/migrate/create_has_content_records.rb
|
78
|
+
- lib/has_content/active_record.rb
|
79
|
+
- lib/has_content/content_owner.rb
|
80
|
+
- lib/has_content/engine.rb
|
81
|
+
- lib/has_content/record.rb
|
82
|
+
- lib/has_content/version.rb
|
83
|
+
- lib/has_content.rb
|
84
|
+
- MIT-LICENSE
|
85
|
+
- Rakefile
|
86
|
+
- README.md
|
87
|
+
- CHANGELOG
|
88
|
+
- spec/content_owner_spec.rb
|
89
|
+
- spec/has_content/active_record_spec.rb
|
90
|
+
- spec/has_content/record_spec.rb
|
91
|
+
- spec/owner_shared.rb
|
92
|
+
- spec/spec_helper.rb
|
93
|
+
- spec/test_app.rb
|
94
|
+
homepage: http://github.com/i2w/has_content
|
95
|
+
licenses: []
|
96
|
+
post_install_message:
|
97
|
+
rdoc_options: []
|
98
|
+
require_paths:
|
99
|
+
- lib
|
100
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
101
|
+
none: false
|
102
|
+
requirements:
|
103
|
+
- - ! '>='
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
segments:
|
107
|
+
- 0
|
108
|
+
hash: -2447319576099344314
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
+
none: false
|
111
|
+
requirements:
|
112
|
+
- - ! '>='
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
segments:
|
116
|
+
- 0
|
117
|
+
hash: -2447319576099344314
|
118
|
+
requirements: []
|
119
|
+
rubyforge_project:
|
120
|
+
rubygems_version: 1.8.15
|
121
|
+
signing_key:
|
122
|
+
specification_version: 3
|
123
|
+
summary: Simple wrapper for adding content via a polymorphic join for any active record
|
124
|
+
test_files:
|
125
|
+
- spec/content_owner_spec.rb
|
126
|
+
- spec/has_content/active_record_spec.rb
|
127
|
+
- spec/has_content/record_spec.rb
|
128
|
+
- spec/owner_shared.rb
|
129
|
+
- spec/spec_helper.rb
|
130
|
+
- spec/test_app.rb
|