piggyback 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1,3 @@
1
+ v0.2 Leaner codebase by taking better advantage of AR-ecosystem. Improved specs.
2
+
3
+ v0.1 Initial version
data/MIT-LICENSE ADDED
@@ -0,0 +1,21 @@
1
+
2
+ Copyright (c) 2011 Andreas Korth
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Manifest CHANGED
@@ -1,6 +1,10 @@
1
- README.rdoc
1
+ CHANGELOG
2
+ MIT-LICENSE
3
+ README.markdown
2
4
  Rakefile
3
5
  lib/piggyback.rb
6
+ piggyback.gemspec
7
+ spec/models.rb
4
8
  spec/piggyback_spec.rb
5
9
  spec/spec_helper.rb
6
10
  Manifest
data/README.markdown ADDED
@@ -0,0 +1,110 @@
1
+ # Piggyback
2
+
3
+ An extension for piggybacking of ActiveRecord™ models.
4
+
5
+ ### What is Piggybacking?
6
+
7
+ Piggybacking refers to the technique of dynamically including attributes from an associated object into the master object. This is achieved by joining the associated object's table in a database query and selecting the attributes that should be included with the parent object.
8
+
9
+ This is best illustrated in an example. Consider these models:
10
+
11
+ class Author < ActiveRecord::Base
12
+ has_many :articles
13
+ end
14
+
15
+ class Post < ActiveRecord::Base
16
+ belongs_to :author
17
+ end
18
+
19
+ ActiveRecord supports piggybacking simply by joining the associated table and selecting columns from it:
20
+
21
+ >> post = Post.joins(:author).select('posts.*, author.name AS author_name').first
22
+
23
+ >> post.title
24
+ => "Why piggybacking in ActiveRecord is flawed"
25
+
26
+ >> post.author_name
27
+ => "Alec Smart"
28
+
29
+ As you can see, the `name` attribute from `Author` is treated as if it were an attribute of `User`. ActiveRecord dynamically determines a model's attributes from the result set returned by the database. Every column in the result set becomes an attribute of the instantiated ActiveRecord objects. Whether the columns originate from the model's own or from a foreign table doesn't make a difference.
30
+
31
+ Or so it seems. Actually there is a drawback which becomes obvious when we select non-string columns:
32
+
33
+ >> post = Post.joins(:author).select('posts.*, author.birthday AS author_birthday, author.rating AS author_rating').first
34
+
35
+ >> post.author_birthday
36
+ => "2011-03-01"
37
+
38
+ >> post.author_rating
39
+ => "4.5"
40
+
41
+ Any attributes originating from foreign tables are not automatically type-casted as we would expect. This is because the database always returns results in text format. The model only knows about the data types of the columns in its own table. Since this information is used when ActiveRecord does its type-casting magic, it doesn't work with foreign columns.
42
+
43
+ We could work around this by defining attribute reader methods in the `Post` model that implicitly converts the values:
44
+
45
+ class Post < ActiveRecord::Base
46
+ ...
47
+
48
+ def author_birthday
49
+ Date.parse(read_attribute('author_birthday'))
50
+ end
51
+
52
+ def author_rating
53
+ read_attribute('author_rating').to_f
54
+ end
55
+ end
56
+
57
+ However this is tedious, error-prone and repetitive if you do it in many models. The type-casting code shown above isn't solid and would be more complex in a real-life situation in order to deal with `nil` values, for example.
58
+
59
+
60
+ ### Piggyback to the rescue!
61
+
62
+ Piggyback introduces the `piggybacks` directive which allows us to easily define which attributes we want to piggyback from associated models. Not only does it take care of the type-casting but also provides us with some additional benefits.
63
+
64
+ You simply declare which association you want to piggyback and how the attribute names should be mapped:
65
+
66
+ class Post < ActiveRecord::Base
67
+ belongs_to :author
68
+
69
+ piggybacks :author, :birthday => :author_birthday, :rating => :author_rating
70
+ end
71
+
72
+ Now you can do the following:
73
+
74
+ >> post = Post.piggyback(:author).first
75
+
76
+ >> post.author_birthday
77
+ => Tue, 01 Mar 2011
78
+
79
+ >> post.author_rating
80
+ => 4.5
81
+
82
+ The type-casting works with any type of attribute, even with serialized ones.
83
+
84
+ As you can see, the `piggibacks` statement replaces the `joins` and `select` parts of the query. Using it is optional but makes life easier since you don't have to write the SQL for `select` by hand.
85
+
86
+ Of course, `piggibacks` plays nice with Arel and you can add additional `joins`, `select` and other statements as you like, for example:
87
+
88
+ Post.select('posts.title, posts.body').piggibacks(:author).joins(:comments).where(:published => true)
89
+
90
+ __Please note:__ If you want to restrict the columns selected from the master table as in the example above, you have to do so _before_ the `piggibacks` statement. Otherwise it will insert the select-all wildcard `SELECT posts.*` rendering your column selection useless.
91
+
92
+ If you don't need to map the attribute names of the piggybacked model, you can simply do:
93
+
94
+ piggyback :author, [:name, :birthday, :rating]
95
+
96
+
97
+ ### Computed values
98
+
99
+ If you want to use an SQL-expression for selecting an attribute, Piggyback can also help you with that. If `Author` didn't have a single `name` attribute, but `first_name` and `last_name`, you could concatenate them into a single attribute:
100
+
101
+ class Post < ActiveRecord::Base
102
+ belongs_to :author
103
+
104
+ piggybacks :author, :author_name => "authors.first_name || ' ' || authors.last_name"
105
+ end
106
+
107
+ >> post.author_name
108
+ => "Donald Duck"
109
+
110
+ In fact, every value you pass in as a string will be treated as raw SQL in the SELECT clause.
data/Rakefile CHANGED
@@ -1,14 +1,15 @@
1
- require 'rubygems'
2
1
  require 'rake'
3
2
  require 'echoe'
4
3
 
5
- Echoe.new('piggyback', '0.1.0') do |p|
6
- p.description = "Piggyback associated models with ActiveRecord"
4
+ Echoe.new('piggyback', '0.2.0') do |p|
5
+ p.description = "Piggyback attributes from associated models with ActiveRecord"
7
6
  p.url = "http://github.com/juni0r/piggyback"
8
7
  p.author = "Andreas Korth"
9
8
  p.email = "andreas.korth@gmail.com"
10
9
  p.ignore_pattern = ["tmp/*", "log/*", "Gemfile", "Gemfile.lock"]
11
- p.development_dependencies = []
10
+
11
+ p.runtime_dependencies = ["activerecord >=3.0.0"]
12
+ p.development_dependencies = ["rspec", "sqlite3"]
12
13
  end
13
14
 
14
15
  Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
data/lib/piggyback.rb CHANGED
@@ -1,95 +1,109 @@
1
1
  module Piggyback
2
2
  extend ActiveSupport::Concern
3
3
 
4
- included do |model|
5
- model.class_inheritable_hash :piggyback_associations
6
- model.piggyback_associations = {}
7
-
8
- model.class_inheritable_hash :piggyback_attributes
9
- model.piggyback_attributes = {}
10
- end
11
-
12
- class Association
4
+ class Association #:nodoc:
5
+
6
+ def initialize(reflection, mappings = {})
7
+ @reflection = reflection
8
+ @mappings = mappings
9
+ end
10
+
11
+ def add_mappings(mappings)
12
+ @mappings.merge!(mappings)
13
+ end
14
+
15
+ def map(&block)
16
+ @mappings.map(&block)
17
+ end
18
+
19
+ def has_attribute?(attr_name)
20
+ @mappings.has_key? attr_name
21
+ end
13
22
 
14
- attr_reader :reflection, :attributes
23
+ def column(attr_name)
24
+ @reflection.klass.columns_hash[@mappings[attr_name]]
25
+ end
26
+
27
+ def serialized_attribute(attr_name)
28
+ @reflection.klass.serialized_attributes[@mappings[attr_name]]
29
+ end
15
30
 
16
- def initialize(*args)
17
- @reflection, @attributes = *args
31
+ def quoted_table_name
32
+ @reflection.klass.quoted_table_name
18
33
  end
19
34
  end
20
35
 
21
36
  module ClassMethods
22
-
23
- def piggy(*associations)
24
- columns = piggyback_attributes.values_at(*associations).map do |association|
25
- table_name = association.reflection.klass.quoted_table_name
26
- association.attributes.map do |attribute, mapping|
27
- if attribute != mapping
28
- "#{table_name}.#{connection.quote_column_name(mapping)} AS #{attribute}"
29
- else
30
- "#{table_name}.#{connection.quote_column_name(attribute)}"
31
- end
32
- end
33
- end
34
- columns.flatten!
35
- columns.unshift("#{quoted_table_name}.*") unless scoped.select_values.any?
36
- select(columns.join(', ')).joins(*associations)
37
+
38
+ def piggyback_associations
39
+ read_inheritable_attribute(:piggyback_associations) || write_inheritable_attribute(:piggyback_associations, {})
37
40
  end
38
41
 
42
+ def piggyback_association_for_attribute(attr_name)
43
+ piggyback_associations.each_value.detect{ |association| association.has_attribute? attr_name }
44
+ end
39
45
 
40
- def piggyback(association, *unmapped_attributes)
46
+ def piggybacks(association, *attributes)
41
47
 
48
+ attributes.flatten!
49
+ mapped_attributes = attributes.extract_options!
42
50
  reflection = reflect_on_association(association.to_sym)
43
-
44
- unless reflection
45
- raise ArgumentError.new("#{self.class.name} has no association named '#{association}'.")
46
- end
47
-
48
- unless [:belongs_to, :has_one].include?(reflection.macro)
49
- raise ArgumentError.new("Only belongs_to and has_many associations can be used for piggybacking.")
50
- end
51
-
52
- mapped_attributes = unmapped_attributes.extract_options!
53
- unmapped_attributes.concat(Array(mapped_attributes.delete(:attributes)))
54
51
 
55
- attributes = {}
52
+ raise ArgumentError, "#{name} has no association named '#{association}'" if reflection.nil?
53
+ raise ArgumentError, "Piggyback only supports belongs_to and has_one associations" if reflection.collection?
54
+ raise ArgumentError, "No attributes specified for piggybacking" if attributes.empty?
55
+
56
+ mappings = {}
56
57
 
57
- unmapped_attributes.flatten.each do |attr_name|
58
- attr_name = attr_name.to_s
59
- attributes[attr_name] = attr_name
58
+ attributes.each do |attr_name|
59
+ mappings[attr_name.to_s] = attr_name.to_s
60
60
  end
61
61
 
62
- mapped_attributes.each do |attr_name, mapping|
63
- attributes[attr_name.to_s] = mapping.to_s
62
+ mapped_attributes.each do |attr_name, mapped_name|
63
+ mappings[attr_name.to_s] = mapped_name.is_a?(String) ? Arel.sql(mapped_name) : mapped_name.to_s
64
64
  end
65
65
 
66
- association = Association.new(reflection, attributes)
66
+ association = (piggyback_associations[reflection.name] ||= Association.new(reflection))
67
+ association.add_mappings(mappings)
67
68
 
68
- piggyback_attributes[reflection.name] = association
69
-
70
- attributes.each do |attr_name, mapping|
71
- piggyback_associations[attr_name] = association
72
- define_method attr_name do
73
- if @attributes.has_key?(attr_name)
74
- read_attribute(attr_name)
75
- else
76
- send(reflection.name).send(mapping)
77
- end
78
- end
79
- end
69
+ # These default procs for +columns_hash+ and +serialized_attributes+
70
+ # allow +read_attribute+ to work transparently and consistently with
71
+ # attributes from joined models. They rely heavily on the implementation
72
+ # of +read_attribute+ and related methods. Since ActiveRecord doesn't
73
+ # provide hooks for overriding this behavior, it is the simplest and
74
+ # least intrusive way to implement proper type casting for attributes
75
+ # while avoiding code duplication.
80
76
 
81
77
  columns_hash.default_proc = lambda do |hash, attr_name|
82
- if association = piggyback_associations[attr_name]
83
- association.reflection.klass.columns_hash[attr_name]
78
+ if association = piggyback_association_for_attribute(attr_name)
79
+ association.column(attr_name)
84
80
  end
85
81
  end
86
82
 
87
83
  serialized_attributes.default_proc = lambda do |hash, attr_name|
88
- if association = piggyback_associations[attr_name]
89
- association.reflection.klass.serialized_attributes[attr_name]
84
+ if association = piggyback_association_for_attribute(attr_name)
85
+ association.serialized_attribute(attr_name)
90
86
  end
91
87
  end
92
88
  end
89
+
90
+ def piggyback(*associations)
91
+ columns = piggyback_associations.values_at(*associations).map do |association|
92
+ association.map do |attr_name, mapped_name|
93
+ if attr_name != mapped_name
94
+ if mapped_name.is_a? Arel::Nodes::SqlLiteral
95
+ "#{mapped_name} AS #{attr_name}"
96
+ else
97
+ "#{association.quoted_table_name}.#{connection.quote_column_name(mapped_name)} AS #{attr_name}"
98
+ end
99
+ else
100
+ "#{association.quoted_table_name}.#{connection.quote_column_name(attr_name)}"
101
+ end
102
+ end
103
+ end
104
+ columns.unshift("#{quoted_table_name}.*") unless scoped.select_values.any?
105
+ select(columns.flatten.join(', ')).joins(*associations)
106
+ end
93
107
  end
94
108
  end
95
109
 
data/piggyback.gemspec CHANGED
@@ -2,28 +2,37 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{piggyback}
5
- s.version = "0.1.0"
5
+ s.version = "0.2.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Andreas Korth"]
9
- s.date = %q{2011-03-20}
10
- s.description = %q{Piggyback associated models with ActiveRecord}
9
+ s.date = %q{2011-03-21}
10
+ s.description = %q{Piggyback attributes from associated models with ActiveRecord}
11
11
  s.email = %q{andreas.korth@gmail.com}
12
- s.extra_rdoc_files = ["README.rdoc", "lib/piggyback.rb"]
13
- s.files = ["README.rdoc", "Rakefile", "lib/piggyback.rb", "spec/piggyback_spec.rb", "spec/spec_helper.rb", "Manifest", "piggyback.gemspec"]
12
+ s.extra_rdoc_files = ["CHANGELOG", "README.markdown", "lib/piggyback.rb"]
13
+ s.files = ["CHANGELOG", "MIT-LICENSE", "README.markdown", "Rakefile", "lib/piggyback.rb", "piggyback.gemspec", "spec/models.rb", "spec/piggyback_spec.rb", "spec/spec_helper.rb", "Manifest"]
14
14
  s.homepage = %q{http://github.com/juni0r/piggyback}
15
- s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Piggyback", "--main", "README.rdoc"]
15
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Piggyback", "--main", "README.markdown"]
16
16
  s.require_paths = ["lib"]
17
17
  s.rubyforge_project = %q{piggyback}
18
18
  s.rubygems_version = %q{1.5.2}
19
- s.summary = %q{Piggyback associated models with ActiveRecord}
19
+ s.summary = %q{Piggyback attributes from associated models with ActiveRecord}
20
20
 
21
21
  if s.respond_to? :specification_version then
22
22
  s.specification_version = 3
23
23
 
24
24
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
25
+ s.add_runtime_dependency(%q<activerecord>, [">= 3.0.0"])
26
+ s.add_development_dependency(%q<rspec>, [">= 0"])
27
+ s.add_development_dependency(%q<sqlite3>, [">= 0"])
25
28
  else
29
+ s.add_dependency(%q<activerecord>, [">= 3.0.0"])
30
+ s.add_dependency(%q<rspec>, [">= 0"])
31
+ s.add_dependency(%q<sqlite3>, [">= 0"])
26
32
  end
27
33
  else
34
+ s.add_dependency(%q<activerecord>, [">= 3.0.0"])
35
+ s.add_dependency(%q<rspec>, [">= 0"])
36
+ s.add_dependency(%q<sqlite3>, [">= 0"])
28
37
  end
29
38
  end
data/spec/models.rb ADDED
@@ -0,0 +1,44 @@
1
+ silence_stream(STDOUT) do
2
+ ActiveRecord::Schema.define(:version => 1) do
3
+
4
+ create_table :essentials do |t|
5
+ t.string :token
6
+ t.timestamps
7
+ end
8
+
9
+ create_table :details do |t|
10
+ t.belongs_to :essential
11
+
12
+ t.string :first_name
13
+ t.string :last_name
14
+ t.string :words
15
+ t.integer :count
16
+ t.boolean :checked
17
+ t.date :birthday
18
+ t.text :baggage
19
+
20
+ t.timestamps
21
+ end
22
+ end
23
+ end
24
+
25
+ class Essential < ActiveRecord::Base
26
+ has_one :detail, :inverse_of => :essential
27
+ has_many :details
28
+
29
+ piggybacks :detail, [:first_name, :last_name, :count, :checked, :birthday, :baggage],
30
+ :name => "details.first_name || ' ' || details.last_name",
31
+ :detail_updated_at => :updated_at
32
+ end
33
+
34
+ class Detail < ActiveRecord::Base
35
+ belongs_to :essential, :inverse_of => :detail
36
+
37
+ serialize :baggage
38
+
39
+ piggybacks :essential, :token
40
+
41
+ def name
42
+ "#{first_name} #{last_name}"
43
+ end
44
+ end
@@ -2,33 +2,76 @@ require 'spec_helper'
2
2
 
3
3
  describe Piggyback do
4
4
 
5
- before do
6
- Essential.create(:position => 1).create_detail(
7
- :name => "nice",
8
- :awesome => true,
9
- :position => 23,
10
- :birthday => "18.12.1974",
11
- :baggage => {:key => "value"})
5
+ context "directive" do
6
+
7
+ def definition_should_raise(message, &block)
8
+ lambda{ Essential.class_eval(&block) }.should raise_error(ArgumentError, message)
9
+ end
10
+
11
+ it "should require the association to be defined" do
12
+ definition_should_raise "Essential has no association named 'bogus'" do
13
+ piggybacks :bogus, [:attribute]
14
+ end
15
+ end
16
+
17
+ it "should not work with has_many associations" do
18
+ definition_should_raise "Piggyback only supports belongs_to and has_one associations" do
19
+ piggybacks :details, [:attribute]
20
+ end
21
+ end
22
+
23
+ it "should require attributes" do
24
+ definition_should_raise "No attributes specified for piggybacking" do
25
+ piggybacks :detail
26
+ end
27
+ end
12
28
  end
13
29
 
14
- it "should read attributes" do
15
- e = Essential.piggy(:detail).first
16
- e.should_not_receive(:detail)
17
- e.name.should eql("nice")
18
- e.awesome.should be_true
19
- e.position.should eql(1)
20
- e.rank.should eql(23)
21
- e.birthday.should eql(Date.new(1974,12,18))
22
- e.baggage.should eql({:key => "value"})
23
- end
30
+ context "relation" do
31
+
32
+ let :essential do
33
+ Essential.create(:token => "TOKEN").create_detail(
34
+ :first_name => "John",
35
+ :last_name => "Doe",
36
+ :count => 23,
37
+ :checked => false,
38
+ :birthday => "18.12.1974",
39
+ :baggage => {:key => "value"})
40
+
41
+ Essential.piggyback(:detail).first
42
+ end
43
+
44
+ it "should not load the association" do
45
+ essential.should_not_receive(:detail)
46
+ essential.first_name.should be_present
47
+ end
48
+
49
+ it "should read string attributes" do
50
+ essential.first_name.should eql("John")
51
+ end
52
+
53
+ it "should read integer attributes" do
54
+ essential.count.should eql(23)
55
+ end
56
+
57
+ it "should read boolean attributes" do
58
+ essential.checked.should eql(false)
59
+ end
60
+
61
+ it "should read date attributes" do
62
+ essential.birthday.should eql(Date.new(1974,12,18))
63
+ end
24
64
 
25
- it "should read attributes from the association" do
26
- e = Essential.first
27
- e.name.should eql("nice")
28
- e.awesome.should be_true
29
- e.position.should eql(1)
30
- e.rank.should eql(23)
31
- e.birthday.should eql(Date.new(1974,12,18))
32
- e.baggage.should eql({:key => "value"})
65
+ it "should read serialized attributes" do
66
+ essential.baggage.should eql({:key => "value"})
67
+ end
68
+
69
+ it "should read a mapped attribute" do
70
+ essential.detail_updated_at.should be_instance_of(Time)
71
+ end
72
+
73
+ it "should read computed attributes" do
74
+ essential.name.should eql("John Doe")
75
+ end
33
76
  end
34
77
  end
data/spec/spec_helper.rb CHANGED
@@ -1,12 +1,8 @@
1
- Root = Pathname.new(File.expand_path(File.join(File.dirname(__FILE__), '..')))
1
+ GEM_ROOT = File.expand_path('../..',__FILE__)
2
+ $: << File.join(GEM_ROOT,'lib')
2
3
 
3
- $: << Root.join('lib')
4
-
5
- require 'fileutils'
6
4
  require 'active_record'
7
- # require 'active_support/buffered_logger'
8
5
  require 'piggyback'
9
- require 'rspec'
10
6
 
11
7
  RSpec.configure do |config|
12
8
  config.before do
@@ -15,35 +11,6 @@ RSpec.configure do |config|
15
11
  end
16
12
 
17
13
  ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:", :verbosity => "silent")
18
- ActiveRecord::Base.logger = ActiveSupport::BufferedLogger.new(Root.join('log','test.log'))
19
-
20
- silence_stream(STDOUT) do
21
- ActiveRecord::Schema.define(:version => 1) do
22
- create_table :essentials do |t|
23
- t.integer :position
24
- t.timestamps
25
- end
26
-
27
- create_table :details do |t|
28
- t.belongs_to :essential
29
- t.string :name
30
- t.integer :position
31
- t.boolean :awesome
32
- t.date :birthday
33
- t.text :baggage
34
- t.timestamps
35
- end
36
- end
37
- end
38
-
39
- class Essential < ActiveRecord::Base
40
- has_one :detail
41
- # piggyback :detail, :attributes => [:name, :awesome, :birthday, :baggage], :rank => :position
42
- # piggyback :detail, :name, :awesome, :birthday, :baggage, :rank => :position
43
- piggyback :detail, [:name, :awesome, :birthday, :baggage], :rank => :position
44
- end
14
+ ActiveRecord::Base.logger = ActiveSupport::BufferedLogger.new(File.join(GEM_ROOT,'log','test.log'))
45
15
 
46
- class Detail < ActiveRecord::Base
47
- belongs_to :essential
48
- serialize :baggage
49
- end
16
+ require 'models'
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: piggyback
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.1.0
5
+ version: 0.2.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Andreas Korth
@@ -10,27 +10,63 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-03-20 00:00:00 +01:00
13
+ date: 2011-03-21 00:00:00 +01:00
14
14
  default_executable:
15
- dependencies: []
16
-
17
- description: Piggyback associated models with ActiveRecord
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: activerecord
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: 3.0.0
25
+ type: :runtime
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: "0"
36
+ type: :development
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: sqlite3
40
+ prerelease: false
41
+ requirement: &id003 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ type: :development
48
+ version_requirements: *id003
49
+ description: Piggyback attributes from associated models with ActiveRecord
18
50
  email: andreas.korth@gmail.com
19
51
  executables: []
20
52
 
21
53
  extensions: []
22
54
 
23
55
  extra_rdoc_files:
24
- - README.rdoc
56
+ - CHANGELOG
57
+ - README.markdown
25
58
  - lib/piggyback.rb
26
59
  files:
27
- - README.rdoc
60
+ - CHANGELOG
61
+ - MIT-LICENSE
62
+ - README.markdown
28
63
  - Rakefile
29
64
  - lib/piggyback.rb
65
+ - piggyback.gemspec
66
+ - spec/models.rb
30
67
  - spec/piggyback_spec.rb
31
68
  - spec/spec_helper.rb
32
69
  - Manifest
33
- - piggyback.gemspec
34
70
  has_rdoc: true
35
71
  homepage: http://github.com/juni0r/piggyback
36
72
  licenses: []
@@ -42,7 +78,7 @@ rdoc_options:
42
78
  - --title
43
79
  - Piggyback
44
80
  - --main
45
- - README.rdoc
81
+ - README.markdown
46
82
  require_paths:
47
83
  - lib
48
84
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -63,6 +99,6 @@ rubyforge_project: piggyback
63
99
  rubygems_version: 1.5.2
64
100
  signing_key:
65
101
  specification_version: 3
66
- summary: Piggyback associated models with ActiveRecord
102
+ summary: Piggyback attributes from associated models with ActiveRecord
67
103
  test_files: []
68
104
 
data/README.rdoc DELETED
File without changes