prim 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ LICENSE
2
+
3
+ The MIT License
4
+
5
+ Copyright (c) 2012 Piers Mainwaring and Orca Health, Inc.
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in
15
+ all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ THE SOFTWARE.
data/README.md CHANGED
@@ -32,9 +32,13 @@ end
32
32
 
33
33
  Great! Now let's say we've added a specific set of Languages. Our Users can now have new Language associations by simply creating a record in the `user_languages` mapping table, relating a User and a Language. But what if we want to know which of a User's Languages is their most important? Well, we could add a `sort_order` or `primary` column to the `user_languages` table, but then we'll need to write code to manage it all.
34
34
 
35
- Enter __Prim__.
35
+ Enter __Prim__. Add
36
36
 
37
- With __Prim__ we can just add a line of code to the User model...
37
+ ```ruby
38
+ gem 'prim'
39
+ ```
40
+
41
+ to your Gemfile. With __Prim__ we can just add a line of code to the User model...
38
42
 
39
43
  ```ruby
40
44
  class User < ActiveRecord::Base
data/lib/prim.rb CHANGED
@@ -27,11 +27,11 @@ module Prim
27
27
  Prim.configured_primaries << self.prim_relationships[ singular_name ]
28
28
 
29
29
  define_method "primary_#{ singular_name }" do
30
- get_primary(singular_name)
30
+ prim_collection_for(singular_name).primary
31
31
  end
32
32
 
33
- define_method "primary_#{ singular_name }=" do |record|
34
- assign_primary(singular_name, record)
33
+ define_method "primary_#{ singular_name }=" do |instance|
34
+ prim_collection_for(singular_name).primary = instance
35
35
  end
36
36
  end
37
37
  end
@@ -1,7 +1,7 @@
1
1
  module Prim
2
2
  # Collection largely wraps an association collection (like a Relation) but adds
3
3
  # the concept of a primary member. Collections can only exist in the context of
4
- # a Relationship (see Prim::Relationship for more info) and an `owner` instance,
4
+ # a Relationship (see Prim::Relationship for more info) and an "owning" `instance`,
5
5
  # and contain mapping records.
6
6
  class Collection
7
7
 
@@ -14,14 +14,20 @@ module Prim
14
14
  @instance = instance
15
15
  @relationship = relationship
16
16
 
17
- # Attach this collection to the mapping class so it has access to static methods.
18
- relationship.reflected_class.prim_collection = self
17
+ # Attach the relationship to the mapping class.
18
+ relationship.reflected_class.prim_relationship = relationship
19
19
  end
20
20
 
21
+ # Loads the primary member of this collection.
21
22
  def primary
22
- sources.where( relationship.through_reflection.name => { primary: true } ).first
23
+ sources.where( relationship.collection_label => { primary: true } ).first.try do |record|
24
+ record.primary = true
25
+ record
26
+ end
23
27
  end
24
28
 
29
+ # Sets the primary member of this collection. Requires a `source_record` to
30
+ # be passed (i.e. a Tag if Post `has_many :tags, through: :taggings`).
25
31
  def primary= source_record
26
32
  mapping = mapping_for(source_record)
27
33
 
@@ -40,18 +46,6 @@ module Prim
40
46
  true
41
47
  end
42
48
 
43
- def siblings_for mapping
44
- foreign_key = relationship.mapping_reflection.foreign_key
45
- mapping_type = relationship.mapping_reflection.type
46
- mapping_class = relationship.reflected_class
47
- primary_key = mapping_class.primary_key
48
-
49
- query = relationship.reflected_class.where( foreign_key => mapping[ foreign_key ] )
50
- query = query.where( mapping_type => mapping[ mapping_type ] ) unless mapping_type.nil?
51
-
52
- query.where( mapping_class.arel_table[ primary_key ].not_eq( mapping[ primary_key ] ) )
53
- end
54
-
55
49
  private
56
50
 
57
51
  # Creates a new source record and a mapping between it and the owner instance.
@@ -68,7 +62,7 @@ module Prim
68
62
  end
69
63
 
70
64
  def mappings force_reload = false
71
- instance.send( relationship.collection_method, force_reload )
65
+ instance.send( relationship.collection_label, force_reload )
72
66
  end
73
67
 
74
68
  def sources force_reload = false
@@ -5,15 +5,7 @@ module Prim
5
5
  module InstanceMethods
6
6
 
7
7
  module Owner
8
- def get_primary singular_name
9
- collection_for(singular_name).primary
10
- end
11
-
12
- def assign_primary singular_name, instance
13
- collection_for(singular_name).primary = instance
14
- end
15
-
16
- def collection_for singular_name
8
+ def prim_collection_for singular_name
17
9
  @_prim_collections ||= {}
18
10
  @_prim_collections[ singular_name ] ||= Prim::Collection.new(self.class.prim_relationships[ singular_name ], self)
19
11
  end
@@ -24,6 +16,10 @@ module Prim
24
16
 
25
17
  included do
26
18
  validate :only_one_primary
19
+
20
+ def self.primary
21
+ where( primary: true ).first
22
+ end
27
23
  end
28
24
 
29
25
  def only_one_primary
@@ -32,8 +28,42 @@ module Prim
32
28
  end
33
29
  end
34
30
 
31
+ # Builds a query selecting all siblings for a given mapping record. A record's
32
+ # siblings are any records in the table of the `reflected_class` that match
33
+ # the given record's foreign key and, if the association is polymorphic,
34
+ # its foreign type. The set of siblings *excludes* `self` (this record).
35
35
  def siblings
36
- prim_collection.siblings_for self
36
+ foreign_key = prim_relationship.mapping_reflection.foreign_key
37
+ mapping_type = prim_relationship.mapping_reflection.type
38
+ primary_key = prim_relationship.reflected_class.primary_key
39
+
40
+ # Select all by foreign key first, to handle all cases.
41
+ query = self.class.where( foreign_key => self[ foreign_key ] )
42
+
43
+ # Only select by a foreign "type" column if one is used on the `reflected_class`,
44
+ # making it a polymorphic association.
45
+ unless mapping_type.nil?
46
+ query = query.where( mapping_type => self[ mapping_type ] )
47
+ end
48
+
49
+ # Exclude this record from the query.
50
+ query.where( self.class.arel_table[ primary_key ].not_eq( self[ primary_key ] ) )
51
+ end
52
+ end
53
+
54
+ module Source
55
+ extend ActiveSupport::Concern
56
+
57
+ included do
58
+ attr_writer :primary
59
+
60
+ def primary
61
+ @primary || false
62
+ end
63
+
64
+ def primary?
65
+ primary
66
+ end
37
67
  end
38
68
  end
39
69
 
@@ -34,17 +34,19 @@ module Prim
34
34
  # TODO: ensure the association isn't nested?
35
35
 
36
36
  reflected_class.send :include, InstanceMethods::Reflected
37
- reflected_class.class_attribute :prim_collection
37
+ reflected_class.class_attribute :prim_relationship
38
+
39
+ source_class.send :include, InstanceMethods::Source if mapping_table?
38
40
  end
39
41
 
40
42
  # The association method to call on the owning class to retrieve a record's collection.
41
- def collection_method
43
+ def collection_label
42
44
  options[:through] || mapping_reflection.plural_name
43
45
  end
44
46
 
45
47
  # The class of the reflection source: i.e. Post if the owning class `has_many :posts`.
46
48
  def source_class
47
- source_reflection.klass
49
+ reflection.klass
48
50
  end
49
51
 
50
52
  # The class of the `mapping_reflection`.
@@ -55,7 +57,7 @@ module Prim
55
57
  # The association reflection representing the link between the owning class and the
56
58
  # mapping class, whether or not the mapping class represents a join-table.
57
59
  def mapping_reflection
58
- through_reflection || source_reflection
60
+ through_reflection || reflection
59
61
  end
60
62
 
61
63
  # True if this relationship relies on a mapping table for `primary` records.
data/prim.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "prim"
3
- s.version = "0.0.3"
4
- s.date = "2012-12-19"
3
+ s.version = "0.0.4"
4
+ s.date = "2013-01-02"
5
5
  s.summary = "Easily manage Rails associations that need a primary member."
6
6
  s.description = "With Prim it's easy to add a primary member to any one-to-many or many-to-many association. " +
7
7
  "Just add a short configuration to a model, generate and run a migration, and you're all set."
@@ -10,7 +10,8 @@ Gem::Specification.new do |s|
10
10
  s.files = `git ls-files`.split("\n")
11
11
  s.homepage = "https://github.com/orcahealth/prim"
12
12
 
13
- s.add_dependency "activerecord", "~> 3.2.0"
13
+ s.add_dependency "activerecord", "~> 3.2.0"
14
+ s.add_dependency "activesupport", "~> 3.2.0"
14
15
 
15
16
  s.require_paths = [ "lib" ]
16
17
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prim
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-19 00:00:00.000000000 Z
12
+ date: 2013-01-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -27,6 +27,22 @@ dependencies:
27
27
  - !ruby/object:Gem::Version
28
28
  version: 3.2.0
29
29
  none: false
30
+ - !ruby/object:Gem::Dependency
31
+ name: activesupport
32
+ prerelease: false
33
+ requirement: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 3.2.0
38
+ none: false
39
+ type: :runtime
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ version: 3.2.0
45
+ none: false
30
46
  description: With Prim it's easy to add a primary member to any one-to-many or many-to-many
31
47
  association. Just add a short configuration to a model, generate and run a migration,
32
48
  and you're all set.
@@ -35,6 +51,7 @@ executables: []
35
51
  extensions: []
36
52
  extra_rdoc_files: []
37
53
  files:
54
+ - LICENSE
38
55
  - README.md
39
56
  - lib/prim.rb
40
57
  - lib/prim/collection.rb