rails_dynamic_associations 0.1.0
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.
- checksums.yaml +7 -0
 - data/MIT-LICENSE +20 -0
 - data/README.md +93 -0
 - data/Rakefile +25 -0
 - data/app/models/relation.rb +78 -0
 - data/app/models/role.rb +32 -0
 - data/config/initializers/model_associations.rb +9 -0
 - data/db/migrate/01_create_roles.rb +10 -0
 - data/db/migrate/02_create_relations.rb +14 -0
 - data/lib/core_ext/string.rb +8 -0
 - data/lib/rails_dynamic_associations/active_record/associations.rb +101 -0
 - data/lib/rails_dynamic_associations/active_record/relations.rb +62 -0
 - data/lib/rails_dynamic_associations/active_record/roles.rb +24 -0
 - data/lib/rails_dynamic_associations/active_record.rb +9 -0
 - data/lib/rails_dynamic_associations/engine.rb +5 -0
 - data/lib/rails_dynamic_associations/version.rb +3 -0
 - data/lib/rails_dynamic_associations.rb +35 -0
 - data/lib/tasks/rails_dynamic_associations_tasks.rake +4 -0
 - metadata +104 -0
 
    
        checksums.yaml
    ADDED
    
    | 
         @@ -0,0 +1,7 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ---
         
     | 
| 
      
 2 
     | 
    
         
            +
            SHA1:
         
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 02f1e9739f27b665443124374994afc6729e4e8f
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: f5d07be362c9b98969dfe4b5b0109f6b429f2c0f
         
     | 
| 
      
 5 
     | 
    
         
            +
            SHA512:
         
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 5ee36ecaeee3642a97e3875c93c365e7323ac01ecc6fd7db0f2e67310eaf3a23aa61d9a0e351ee88b5c98f7de8d676f31fa456a1d992167dd8e37d4a9e9fd6ec
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: fc3ce8c1acbdebba32efd429e06eb5fc0b3390fc72163eb28905730f0a6293f5e0222fd67b2d89b8045a87aa138157f7b43b105bb070a7581efda2e0a0422802
         
     | 
    
        data/MIT-LICENSE
    ADDED
    
    | 
         @@ -0,0 +1,20 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            Copyright 2013 Alexander Senko, SoftPro Ltd.
         
     | 
| 
      
 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/README.md
    ADDED
    
    | 
         @@ -0,0 +1,93 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # RailsDynamicAssociations
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Define your model associations in the database without changing the schema or models.
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            ## Features
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            * Creates associations for your models when application starts.
         
     | 
| 
      
 8 
     | 
    
         
            +
            * Provides `Relation` & `Role` models.
         
     | 
| 
      
 9 
     | 
    
         
            +
            * No configuration code needed.
         
     | 
| 
      
 10 
     | 
    
         
            +
            * No code generated or inserted to your app (except migrations).
         
     | 
| 
      
 11 
     | 
    
         
            +
            * Adds some useful methods to `ActiveRecord` objects to handle their relations.
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            ## Installation
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            1. Add the gem to your `Gemfile` and `bundle` it.
         
     | 
| 
      
 16 
     | 
    
         
            +
            2. Copy migrations to your app (`rake rails_dynamic_associations:install:migrations`).
         
     | 
| 
      
 17 
     | 
    
         
            +
            3. Migrate the DB (`rake db:migrate`).
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            ## Usage
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            Add configuration records to the DB:
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            ``` ruby
         
     | 
| 
      
 24 
     | 
    
         
            +
            	Relation.create({
         
     | 
| 
      
 25 
     | 
    
         
            +
            		source_type: Person,
         
     | 
| 
      
 26 
     | 
    
         
            +
            		target_type: Book,
         
     | 
| 
      
 27 
     | 
    
         
            +
            	})
         
     | 
| 
      
 28 
     | 
    
         
            +
            ```
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
            Or use a helper method:
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
            ``` ruby
         
     | 
| 
      
 33 
     | 
    
         
            +
            	Relation.seed Person, Book
         
     | 
| 
      
 34 
     | 
    
         
            +
            ```
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
            Now you have:
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
            ``` ruby
         
     | 
| 
      
 39 
     | 
    
         
            +
            	person.books
         
     | 
| 
      
 40 
     | 
    
         
            +
            	book.people
         
     | 
| 
      
 41 
     | 
    
         
            +
            ```
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
            ### Roles
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
            You can create multiple role-based associations between two models.
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
            ``` ruby
         
     | 
| 
      
 48 
     | 
    
         
            +
            	Relation.seed Person, Book, %w[
         
     | 
| 
      
 49 
     | 
    
         
            +
            		author
         
     | 
| 
      
 50 
     | 
    
         
            +
            		editor
         
     | 
| 
      
 51 
     | 
    
         
            +
            	]
         
     | 
| 
      
 52 
     | 
    
         
            +
            ```
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
            You will get:
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
            ``` ruby
         
     | 
| 
      
 57 
     | 
    
         
            +
            	person.books
         
     | 
| 
      
 58 
     | 
    
         
            +
            	person.authored_books
         
     | 
| 
      
 59 
     | 
    
         
            +
            	person.edited_books
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
            	book.people
         
     | 
| 
      
 62 
     | 
    
         
            +
            	book.author_people
         
     | 
| 
      
 63 
     | 
    
         
            +
            	book.editor_people
         
     | 
| 
      
 64 
     | 
    
         
            +
            ```
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
            #### `User` special case
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
            In case you have set up relations with a `User` model you'll get a slightly different naming:
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
            ``` ruby
         
     | 
| 
      
 71 
     | 
    
         
            +
            	Relation.seed User, Book, %w[
         
     | 
| 
      
 72 
     | 
    
         
            +
            		author
         
     | 
| 
      
 73 
     | 
    
         
            +
            		editor
         
     | 
| 
      
 74 
     | 
    
         
            +
            	]
         
     | 
| 
      
 75 
     | 
    
         
            +
            ```
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
            ``` ruby
         
     | 
| 
      
 78 
     | 
    
         
            +
            	book.users
         
     | 
| 
      
 79 
     | 
    
         
            +
            	book.authors
         
     | 
| 
      
 80 
     | 
    
         
            +
            	book.editors
         
     | 
| 
      
 81 
     | 
    
         
            +
            ```
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
            ###### TODO
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
            * Describe self-referential associations.
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
            ## Contributing
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
            1. Fork it
         
     | 
| 
      
 90 
     | 
    
         
            +
            2. Create your feature branch (`git checkout -b my-new-feature`)
         
     | 
| 
      
 91 
     | 
    
         
            +
            3. Commit your changes (`git commit -am 'Add some feature'`)
         
     | 
| 
      
 92 
     | 
    
         
            +
            4. Push to the branch (`git push origin my-new-feature`)
         
     | 
| 
      
 93 
     | 
    
         
            +
            5. Create new Pull Request
         
     | 
    
        data/Rakefile
    ADDED
    
    | 
         @@ -0,0 +1,25 @@ 
     | 
|
| 
      
 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    = 'RailsDynamicAssociations'
         
     | 
| 
      
 18 
     | 
    
         
            +
            	rdoc.options << '--line-numbers'
         
     | 
| 
      
 19 
     | 
    
         
            +
            	rdoc.rdoc_files.include('README.md')
         
     | 
| 
      
 20 
     | 
    
         
            +
            	rdoc.rdoc_files.include('lib/**/*.rb')
         
     | 
| 
      
 21 
     | 
    
         
            +
            end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            Bundler::GemHelper.install_tasks
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
         @@ -0,0 +1,78 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Relation < ActiveRecord::Base
         
     | 
| 
      
 2 
     | 
    
         
            +
            	belongs_to :source, polymorphic: true
         
     | 
| 
      
 3 
     | 
    
         
            +
            	belongs_to :target, polymorphic: true
         
     | 
| 
      
 4 
     | 
    
         
            +
            	belongs_to :role
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            	delegate :name, to: :role, allow_nil: true
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            	RailsDynamicAssociations.directions.each &-> (attribute, direction) do
         
     | 
| 
      
 9 
     | 
    
         
            +
            		scope "#{direction}_abstract", -> (object = nil) {
         
     | 
| 
      
 10 
     | 
    
         
            +
            			if object then
         
     | 
| 
      
 11 
     | 
    
         
            +
            				send direction, object
         
     | 
| 
      
 12 
     | 
    
         
            +
            			else
         
     | 
| 
      
 13 
     | 
    
         
            +
            				all
         
     | 
| 
      
 14 
     | 
    
         
            +
            			end.
         
     | 
| 
      
 15 
     | 
    
         
            +
            				where "#{attribute}_id"   => nil
         
     | 
| 
      
 16 
     | 
    
         
            +
            		}
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            		scope "#{direction}_general", -> {
         
     | 
| 
      
 19 
     | 
    
         
            +
            			send("#{direction}_abstract").
         
     | 
| 
      
 20 
     | 
    
         
            +
            				where "#{attribute}_type" => nil
         
     | 
| 
      
 21 
     | 
    
         
            +
            		}
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            		scope direction, -> (object) {
         
     | 
| 
      
 24 
     | 
    
         
            +
            			case object
         
     | 
| 
      
 25 
     | 
    
         
            +
            			when nil then
         
     | 
| 
      
 26 
     | 
    
         
            +
            				all
         
     | 
| 
      
 27 
     | 
    
         
            +
            			when Symbol then
         
     | 
| 
      
 28 
     | 
    
         
            +
            				send "#{direction}_#{object}"
         
     | 
| 
      
 29 
     | 
    
         
            +
            			when Class then
         
     | 
| 
      
 30 
     | 
    
         
            +
            				where "#{attribute}_type" => object.base_class
         
     | 
| 
      
 31 
     | 
    
         
            +
            			else
         
     | 
| 
      
 32 
     | 
    
         
            +
            				where "#{attribute}_type" => object.class.base_class,
         
     | 
| 
      
 33 
     | 
    
         
            +
            				      "#{attribute}_id"   => object.id
         
     | 
| 
      
 34 
     | 
    
         
            +
            			end
         
     | 
| 
      
 35 
     | 
    
         
            +
            		}
         
     | 
| 
      
 36 
     | 
    
         
            +
            	end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
            	scope :abstract, -> {
         
     | 
| 
      
 39 
     | 
    
         
            +
            		of_abstract.to_abstract
         
     | 
| 
      
 40 
     | 
    
         
            +
            	}
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            	scope :applied, -> {
         
     | 
| 
      
 43 
     | 
    
         
            +
            		where.not source_id: nil,
         
     | 
| 
      
 44 
     | 
    
         
            +
            		          target_id: nil
         
     | 
| 
      
 45 
     | 
    
         
            +
            	}
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
            	scope :named, -> (*names) {
         
     | 
| 
      
 48 
     | 
    
         
            +
            		if names.present? then
         
     | 
| 
      
 49 
     | 
    
         
            +
            			where     roles: { name: names.flatten.map(&:to_s) }
         
     | 
| 
      
 50 
     | 
    
         
            +
            		else
         
     | 
| 
      
 51 
     | 
    
         
            +
            			where.not roles: { name: nil }
         
     | 
| 
      
 52 
     | 
    
         
            +
            		end.
         
     | 
| 
      
 53 
     | 
    
         
            +
            			includes :role
         
     | 
| 
      
 54 
     | 
    
         
            +
            	}
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
            	def self.seed source, target, roles = nil
         
     | 
| 
      
 57 
     | 
    
         
            +
            		(roles.present? ? by_roles(roles) : [ self ]).map do |scope|
         
     | 
| 
      
 58 
     | 
    
         
            +
            			scope.create source_type: source,
         
     | 
| 
      
 59 
     | 
    
         
            +
            			             target_type: target
         
     | 
| 
      
 60 
     | 
    
         
            +
            		end
         
     | 
| 
      
 61 
     | 
    
         
            +
            	end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
            	def self.by_roles *names
         
     | 
| 
      
 64 
     | 
    
         
            +
            		Role.find_or_create_named(*names).
         
     | 
| 
      
 65 
     | 
    
         
            +
            			map &:relations
         
     | 
| 
      
 66 
     | 
    
         
            +
            	end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
            	# Using polymorphic associations in combination with single table inheritance (STI) is
         
     | 
| 
      
 70 
     | 
    
         
            +
            	# a little tricky. In order for the associations to work as expected, ensure that you
         
     | 
| 
      
 71 
     | 
    
         
            +
            	# store the base model for the STI models in the type column of the polymorphic
         
     | 
| 
      
 72 
     | 
    
         
            +
            	# association.
         
     | 
| 
      
 73 
     | 
    
         
            +
            	for reflection in reflections.values.select { |r| r.options[:polymorphic] } do
         
     | 
| 
      
 74 
     | 
    
         
            +
            		define_method "#{reflection.name}_type=" do |type|
         
     | 
| 
      
 75 
     | 
    
         
            +
            			super type && type.to_s.classify.constantize.base_class.to_s
         
     | 
| 
      
 76 
     | 
    
         
            +
            		end
         
     | 
| 
      
 77 
     | 
    
         
            +
            	end
         
     | 
| 
      
 78 
     | 
    
         
            +
            end
         
     | 
    
        data/app/models/role.rb
    ADDED
    
    | 
         @@ -0,0 +1,32 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Role < ActiveRecord::Base
         
     | 
| 
      
 2 
     | 
    
         
            +
            	has_many :relations
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            	validates :name, presence: true, uniqueness: true
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            	scope :named, -> (*names) {
         
     | 
| 
      
 7 
     | 
    
         
            +
            		where name: names.flatten.map(&:to_s)
         
     | 
| 
      
 8 
     | 
    
         
            +
            	}
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            	scope :available, -> {
         
     | 
| 
      
 11 
     | 
    
         
            +
            		includes(:relations).
         
     | 
| 
      
 12 
     | 
    
         
            +
            			where relations: { id: Relation.of_abstract } # TODO: simplify
         
     | 
| 
      
 13 
     | 
    
         
            +
            	}
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            	scope :in, -> (object) {
         
     | 
| 
      
 16 
     | 
    
         
            +
            		where relations: { id: object.source_relations } # TODO: simplify
         
     | 
| 
      
 17 
     | 
    
         
            +
            	}
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            	scope :for, -> (subject) {
         
     | 
| 
      
 20 
     | 
    
         
            +
            		where relations: { id: subject.target_relations } # TODO: simplify
         
     | 
| 
      
 21 
     | 
    
         
            +
            	}
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            	def self.find_or_create_named *names
         
     | 
| 
      
 24 
     | 
    
         
            +
            		names.flatten!
         
     | 
| 
      
 25 
     | 
    
         
            +
            		names.compact!
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            		(existing = named(names)).all +
         
     | 
| 
      
 28 
     | 
    
         
            +
            			(names - existing.map(&:name)).map { |name|
         
     | 
| 
      
 29 
     | 
    
         
            +
            				create name: name
         
     | 
| 
      
 30 
     | 
    
         
            +
            			}
         
     | 
| 
      
 31 
     | 
    
         
            +
            	end
         
     | 
| 
      
 32 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,9 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ActiveSupport.on_load :model_class do
         
     | 
| 
      
 2 
     | 
    
         
            +
            	for type in RailsDynamicAssociations.directions.keys do
         
     | 
| 
      
 3 
     | 
    
         
            +
            		for relation in send("#{type}_relations").abstract.select(&:"#{type}_type") do
         
     | 
| 
      
 4 
     | 
    
         
            +
            			setup_relation type, relation.send("#{type}_type").constantize, relation.role do |association|
         
     | 
| 
      
 5 
     | 
    
         
            +
            				attr_accessible "#{association.to_s.singularize}_ids"
         
     | 
| 
      
 6 
     | 
    
         
            +
            			end
         
     | 
| 
      
 7 
     | 
    
         
            +
            		end
         
     | 
| 
      
 8 
     | 
    
         
            +
            	end if self != Relation and Relation.table_exists? # needed for DB migrations & schema initializing
         
     | 
| 
      
 9 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,14 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class CreateRelations < ActiveRecord::Migration
         
     | 
| 
      
 2 
     | 
    
         
            +
            	def change
         
     | 
| 
      
 3 
     | 
    
         
            +
            		create_table :relations do |t|
         
     | 
| 
      
 4 
     | 
    
         
            +
            			t.references :source, polymorphic: { default: 'User' }
         
     | 
| 
      
 5 
     | 
    
         
            +
            			t.references :target, polymorphic: true
         
     | 
| 
      
 6 
     | 
    
         
            +
            			t.references :role
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            			t.timestamps
         
     | 
| 
      
 9 
     | 
    
         
            +
            		end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            		add_index :relations, [ :source_id, :source_type, :target_id, :target_type, :role_id ], unique: true,
         
     | 
| 
      
 12 
     | 
    
         
            +
            		          name: 'index_relations_on_source_and_target_and_role'
         
     | 
| 
      
 13 
     | 
    
         
            +
            	end
         
     | 
| 
      
 14 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,101 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'active_support/concern'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module RailsDynamicAssociations::ActiveRecord
         
     | 
| 
      
 4 
     | 
    
         
            +
            	module Associations
         
     | 
| 
      
 5 
     | 
    
         
            +
            		extend ActiveSupport::Concern
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            		module ClassMethods
         
     | 
| 
      
 8 
     | 
    
         
            +
            			protected
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            			def setup_relation type, target = self, role = nil
         
     | 
| 
      
 11 
     | 
    
         
            +
            				define_association type, target
         
     | 
| 
      
 12 
     | 
    
         
            +
            				define_association type, target, role if role
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            				for association, method in RailsDynamicAssociations.self_referential_recursive do
         
     | 
| 
      
 15 
     | 
    
         
            +
            					define_recursive_methods association, method if association.in? reflections and not method_defined? method
         
     | 
| 
      
 16 
     | 
    
         
            +
            				end
         
     | 
| 
      
 17 
     | 
    
         
            +
            			end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            			private
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            			def define_relations_association type, target = self, role = nil
         
     | 
| 
      
 22 
     | 
    
         
            +
            				:"#{role ? association_name(type, target, role).to_s.singularize : type}_relations".tap do |association|
         
     | 
| 
      
 23 
     | 
    
         
            +
            					unless association.in? reflections then
         
     | 
| 
      
 24 
     | 
    
         
            +
            						has_many association, conditions: role && { role_id: role.id },
         
     | 
| 
      
 25 
     | 
    
         
            +
            						         as: (RailsDynamicAssociations.directions.keys - [ type ]).first, class_name: 'Relation'
         
     | 
| 
      
 26 
     | 
    
         
            +
            					end
         
     | 
| 
      
 27 
     | 
    
         
            +
            				end
         
     | 
| 
      
 28 
     | 
    
         
            +
            			end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
            			def define_association type, target = self, role = nil
         
     | 
| 
      
 31 
     | 
    
         
            +
            				unless (association = association_name(type, target, role)).in? reflections then
         
     | 
| 
      
 32 
     | 
    
         
            +
            					has_many association,
         
     | 
| 
      
 33 
     | 
    
         
            +
            					         through:     define_relations_association(type, target, role),
         
     | 
| 
      
 34 
     | 
    
         
            +
            					         source:      type,
         
     | 
| 
      
 35 
     | 
    
         
            +
            					         source_type: target.base_class.name,
         
     | 
| 
      
 36 
     | 
    
         
            +
            					         class_name:  target.name
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
            					define_association_with_roles association unless role
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
            					yield association if block_given?
         
     | 
| 
      
 41 
     | 
    
         
            +
            				end
         
     | 
| 
      
 42 
     | 
    
         
            +
            			end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            			def define_association_with_roles association
         
     | 
| 
      
 45 
     | 
    
         
            +
            				redefine_method "#{association}_with_roles" do |*roles|
         
     | 
| 
      
 46 
     | 
    
         
            +
            					send(association).where(
         
     | 
| 
      
 47 
     | 
    
         
            +
            						relations: {
         
     | 
| 
      
 48 
     | 
    
         
            +
            							role_id: Role.named(roles).pluck(:id)
         
     | 
| 
      
 49 
     | 
    
         
            +
            						}
         
     | 
| 
      
 50 
     | 
    
         
            +
            					)
         
     | 
| 
      
 51 
     | 
    
         
            +
            				end
         
     | 
| 
      
 52 
     | 
    
         
            +
            			end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
            			def define_recursive_methods association, method, tree_method = "#{method.to_s.singularize}_tree", distance_method = "#{method}_with_distance"
         
     | 
| 
      
 55 
     | 
    
         
            +
            				redefine_method tree_method do
         
     | 
| 
      
 56 
     | 
    
         
            +
            					send(association).inject([]) { |tree, node|
         
     | 
| 
      
 57 
     | 
    
         
            +
            						tree << node << node.send(tree_method)
         
     | 
| 
      
 58 
     | 
    
         
            +
            					}.reject &:blank?
         
     | 
| 
      
 59 
     | 
    
         
            +
            				end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
            				redefine_method distance_method do
         
     | 
| 
      
 62 
     | 
    
         
            +
            					(with_distance = -> (level, distance) {
         
     | 
| 
      
 63 
     | 
    
         
            +
            						if level.is_a? Array then
         
     | 
| 
      
 64 
     | 
    
         
            +
            							level.inject(ActiveSupport::OrderedHash.new) { |hash, node|
         
     | 
| 
      
 65 
     | 
    
         
            +
            								hash.merge with_distance[node, distance.next]
         
     | 
| 
      
 66 
     | 
    
         
            +
            							}
         
     | 
| 
      
 67 
     | 
    
         
            +
            						else
         
     | 
| 
      
 68 
     | 
    
         
            +
            							{ level => distance }
         
     | 
| 
      
 69 
     | 
    
         
            +
            						end
         
     | 
| 
      
 70 
     | 
    
         
            +
            					})[send(tree_method), 0]
         
     | 
| 
      
 71 
     | 
    
         
            +
            				end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
            				redefine_method method do
         
     | 
| 
      
 74 
     | 
    
         
            +
            					send(tree_method).flatten
         
     | 
| 
      
 75 
     | 
    
         
            +
            				end
         
     | 
| 
      
 76 
     | 
    
         
            +
            			end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
            			def association_name type, target = self, role = nil
         
     | 
| 
      
 79 
     | 
    
         
            +
            				if role then
         
     | 
| 
      
 80 
     | 
    
         
            +
            					if target == self || target <= User then
         
     | 
| 
      
 81 
     | 
    
         
            +
            						{
         
     | 
| 
      
 82 
     | 
    
         
            +
            							source: role.name,
         
     | 
| 
      
 83 
     | 
    
         
            +
            							target: "#{role.name.passivize}_#{target.name.split('::').reverse.join}",
         
     | 
| 
      
 84 
     | 
    
         
            +
            						}[type]
         
     | 
| 
      
 85 
     | 
    
         
            +
            					else
         
     | 
| 
      
 86 
     | 
    
         
            +
            						"#{{
         
     | 
| 
      
 87 
     | 
    
         
            +
            							source: role.name,
         
     | 
| 
      
 88 
     | 
    
         
            +
            							target: role.name.passivize,
         
     | 
| 
      
 89 
     | 
    
         
            +
            						}[type]}_#{association_name type, target}"
         
     | 
| 
      
 90 
     | 
    
         
            +
            					end
         
     | 
| 
      
 91 
     | 
    
         
            +
            				else
         
     | 
| 
      
 92 
     | 
    
         
            +
            					if target == self then
         
     | 
| 
      
 93 
     | 
    
         
            +
            						RailsDynamicAssociations.self_referential_recursive[type].to_s
         
     | 
| 
      
 94 
     | 
    
         
            +
            					else
         
     | 
| 
      
 95 
     | 
    
         
            +
            						target.name.split('::').reverse.join
         
     | 
| 
      
 96 
     | 
    
         
            +
            					end
         
     | 
| 
      
 97 
     | 
    
         
            +
            				end.tableize.to_sym
         
     | 
| 
      
 98 
     | 
    
         
            +
            			end
         
     | 
| 
      
 99 
     | 
    
         
            +
            		end
         
     | 
| 
      
 100 
     | 
    
         
            +
            	end
         
     | 
| 
      
 101 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,62 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'active_support/concern'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module RailsDynamicAssociations::ActiveRecord
         
     | 
| 
      
 4 
     | 
    
         
            +
            	module Relations
         
     | 
| 
      
 5 
     | 
    
         
            +
            		extend ActiveSupport::Concern
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            		included do
         
     | 
| 
      
 8 
     | 
    
         
            +
            			extend  ClassAndInstanceMethods
         
     | 
| 
      
 9 
     | 
    
         
            +
            			include ClassAndInstanceMethods
         
     | 
| 
      
 10 
     | 
    
         
            +
            		end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            		module ClassMethods
         
     | 
| 
      
 13 
     | 
    
         
            +
            			RailsDynamicAssociations.opposite_directions.each &-> (association, method) do
         
     | 
| 
      
 14 
     | 
    
         
            +
            				define_method "#{association}_relations" do
         
     | 
| 
      
 15 
     | 
    
         
            +
            					Relation.send method, self
         
     | 
| 
      
 16 
     | 
    
         
            +
            				end
         
     | 
| 
      
 17 
     | 
    
         
            +
            			end
         
     | 
| 
      
 18 
     | 
    
         
            +
            		end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            		module ClassAndInstanceMethods
         
     | 
| 
      
 21 
     | 
    
         
            +
            			# TODO: use keyword arguments
         
     | 
| 
      
 22 
     | 
    
         
            +
            			def find_relations args = {}
         
     | 
| 
      
 23 
     | 
    
         
            +
            				directions = RailsDynamicAssociations.directions
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            				for association, method in directions do
         
     | 
| 
      
 26 
     | 
    
         
            +
            					args[association] = args.delete method
         
     | 
| 
      
 27 
     | 
    
         
            +
            				end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            				as = [ args[:as] ].flatten
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
            				if directions.keys.inject(nil) { |r, k| !r ^ !args[k] } then # direction specified
         
     | 
| 
      
 32 
     | 
    
         
            +
            					for association, method in directions do
         
     | 
| 
      
 33 
     | 
    
         
            +
            						next unless args[association]
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
            						return (as.present? ?
         
     | 
| 
      
 36 
     | 
    
         
            +
            							source_relations.named(as) :
         
     | 
| 
      
 37 
     | 
    
         
            +
            							source_relations
         
     | 
| 
      
 38 
     | 
    
         
            +
            						).send method, args[association]
         
     | 
| 
      
 39 
     | 
    
         
            +
            					end
         
     | 
| 
      
 40 
     | 
    
         
            +
            				else # both directions
         
     | 
| 
      
 41 
     | 
    
         
            +
            					directions.map do |association, method|
         
     | 
| 
      
 42 
     | 
    
         
            +
            						as.present? ?
         
     | 
| 
      
 43 
     | 
    
         
            +
            							send("#{association}_relations").named(as) :
         
     | 
| 
      
 44 
     | 
    
         
            +
            							send("#{association}_relations")
         
     | 
| 
      
 45 
     | 
    
         
            +
            					end.sum
         
     | 
| 
      
 46 
     | 
    
         
            +
            				end
         
     | 
| 
      
 47 
     | 
    
         
            +
            			end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
            			def relative? args = {}
         
     | 
| 
      
 50 
     | 
    
         
            +
            				find_relations(args).
         
     | 
| 
      
 51 
     | 
    
         
            +
            					present?
         
     | 
| 
      
 52 
     | 
    
         
            +
            			end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
            			def relatives args = {}
         
     | 
| 
      
 55 
     | 
    
         
            +
            				find_relations(args).
         
     | 
| 
      
 56 
     | 
    
         
            +
            					map { |r|
         
     | 
| 
      
 57 
     | 
    
         
            +
            						([ r.source, r.target ] - [ self ]).first
         
     | 
| 
      
 58 
     | 
    
         
            +
            					}.uniq
         
     | 
| 
      
 59 
     | 
    
         
            +
            			end
         
     | 
| 
      
 60 
     | 
    
         
            +
            		end
         
     | 
| 
      
 61 
     | 
    
         
            +
            	end
         
     | 
| 
      
 62 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,24 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'active_support/concern'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module RailsDynamicAssociations::ActiveRecord
         
     | 
| 
      
 4 
     | 
    
         
            +
            	module Roles
         
     | 
| 
      
 5 
     | 
    
         
            +
            		extend ActiveSupport::Concern
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            		included do
         
     | 
| 
      
 8 
     | 
    
         
            +
            			extend  ClassAndInstanceMethods
         
     | 
| 
      
 9 
     | 
    
         
            +
            			include ClassAndInstanceMethods
         
     | 
| 
      
 10 
     | 
    
         
            +
            		end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            		module ClassAndInstanceMethods
         
     | 
| 
      
 13 
     | 
    
         
            +
            			def roles to: nil, &block
         
     | 
| 
      
 14 
     | 
    
         
            +
            				if block_given? then
         
     | 
| 
      
 15 
     | 
    
         
            +
            					source_relations.instance_eval &block
         
     | 
| 
      
 16 
     | 
    
         
            +
            				else
         
     | 
| 
      
 17 
     | 
    
         
            +
            					source_relations
         
     | 
| 
      
 18 
     | 
    
         
            +
            				end.
         
     | 
| 
      
 19 
     | 
    
         
            +
            					to(to).
         
     | 
| 
      
 20 
     | 
    
         
            +
            						map(&:name).uniq
         
     | 
| 
      
 21 
     | 
    
         
            +
            			end
         
     | 
| 
      
 22 
     | 
    
         
            +
            		end
         
     | 
| 
      
 23 
     | 
    
         
            +
            	end
         
     | 
| 
      
 24 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,9 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rails_dynamic_associations/active_record/associations'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'rails_dynamic_associations/active_record/relations'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'rails_dynamic_associations/active_record/roles'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            ActiveSupport.on_load :active_record do
         
     | 
| 
      
 6 
     | 
    
         
            +
            	include RailsDynamicAssociations::ActiveRecord::Associations
         
     | 
| 
      
 7 
     | 
    
         
            +
            	include RailsDynamicAssociations::ActiveRecord::Relations
         
     | 
| 
      
 8 
     | 
    
         
            +
            	include RailsDynamicAssociations::ActiveRecord::Roles
         
     | 
| 
      
 9 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,35 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rails_model_load_hook'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'rails_dynamic_associations/engine'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'core_ext/string'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            module RailsDynamicAssociations
         
     | 
| 
      
 7 
     | 
    
         
            +
            	mattr_accessor :directions,
         
     | 
| 
      
 8 
     | 
    
         
            +
            	               :self_referential,
         
     | 
| 
      
 9 
     | 
    
         
            +
            	               :self_referential_recursive
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            	self.directions = {
         
     | 
| 
      
 12 
     | 
    
         
            +
            		source: :of,
         
     | 
| 
      
 13 
     | 
    
         
            +
            		target: :to,
         
     | 
| 
      
 14 
     | 
    
         
            +
            	}
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            	self.self_referential = {
         
     | 
| 
      
 17 
     | 
    
         
            +
            		source: :child,
         
     | 
| 
      
 18 
     | 
    
         
            +
            		target: :parent,
         
     | 
| 
      
 19 
     | 
    
         
            +
            	}
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            	self.self_referential_recursive = {
         
     | 
| 
      
 22 
     | 
    
         
            +
            		parents:  :ancestors,
         
     | 
| 
      
 23 
     | 
    
         
            +
            		children: :descendants,
         
     | 
| 
      
 24 
     | 
    
         
            +
            	}
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            	def self.opposite_directions
         
     | 
| 
      
 27 
     | 
    
         
            +
            		directions.each_with_object({}) do |(key, value), hash|
         
     | 
| 
      
 28 
     | 
    
         
            +
            			hash[key] = directions.values.find do |v|
         
     | 
| 
      
 29 
     | 
    
         
            +
            				v != value
         
     | 
| 
      
 30 
     | 
    
         
            +
            			end
         
     | 
| 
      
 31 
     | 
    
         
            +
            		end
         
     | 
| 
      
 32 
     | 
    
         
            +
            	end
         
     | 
| 
      
 33 
     | 
    
         
            +
            end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
            require 'rails_dynamic_associations/active_record'
         
     | 
    
        metadata
    ADDED
    
    | 
         @@ -0,0 +1,104 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- !ruby/object:Gem::Specification
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: rails_dynamic_associations
         
     | 
| 
      
 3 
     | 
    
         
            +
            version: !ruby/object:Gem::Version
         
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.1.0
         
     | 
| 
      
 5 
     | 
    
         
            +
            platform: ruby
         
     | 
| 
      
 6 
     | 
    
         
            +
            authors:
         
     | 
| 
      
 7 
     | 
    
         
            +
            - Alexander Senko
         
     | 
| 
      
 8 
     | 
    
         
            +
            autorequire: 
         
     | 
| 
      
 9 
     | 
    
         
            +
            bindir: bin
         
     | 
| 
      
 10 
     | 
    
         
            +
            cert_chain: []
         
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2015-01-27 00:00:00.000000000 Z
         
     | 
| 
      
 12 
     | 
    
         
            +
            dependencies:
         
     | 
| 
      
 13 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 14 
     | 
    
         
            +
              name: rails
         
     | 
| 
      
 15 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 16 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 17 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 18 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 19 
     | 
    
         
            +
                    version: '3.2'
         
     | 
| 
      
 20 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 21 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 22 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 23 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 24 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 25 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 26 
     | 
    
         
            +
                    version: '3.2'
         
     | 
| 
      
 27 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 28 
     | 
    
         
            +
              name: rails_model_load_hook
         
     | 
| 
      
 29 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 30 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 31 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 32 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 33 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 34 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 35 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 36 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 37 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 38 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 39 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 40 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 41 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 42 
     | 
    
         
            +
              name: sqlite3
         
     | 
| 
      
 43 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 44 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 45 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 46 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 47 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 48 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 49 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 50 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 51 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 52 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 53 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 54 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 55 
     | 
    
         
            +
            description: Define your model associations in the database without changing the schema
         
     | 
| 
      
 56 
     | 
    
         
            +
              or models.
         
     | 
| 
      
 57 
     | 
    
         
            +
            email:
         
     | 
| 
      
 58 
     | 
    
         
            +
            - Alexander.Senko@gmail.com
         
     | 
| 
      
 59 
     | 
    
         
            +
            executables: []
         
     | 
| 
      
 60 
     | 
    
         
            +
            extensions: []
         
     | 
| 
      
 61 
     | 
    
         
            +
            extra_rdoc_files: []
         
     | 
| 
      
 62 
     | 
    
         
            +
            files:
         
     | 
| 
      
 63 
     | 
    
         
            +
            - MIT-LICENSE
         
     | 
| 
      
 64 
     | 
    
         
            +
            - README.md
         
     | 
| 
      
 65 
     | 
    
         
            +
            - Rakefile
         
     | 
| 
      
 66 
     | 
    
         
            +
            - app/models/relation.rb
         
     | 
| 
      
 67 
     | 
    
         
            +
            - app/models/role.rb
         
     | 
| 
      
 68 
     | 
    
         
            +
            - config/initializers/model_associations.rb
         
     | 
| 
      
 69 
     | 
    
         
            +
            - db/migrate/01_create_roles.rb
         
     | 
| 
      
 70 
     | 
    
         
            +
            - db/migrate/02_create_relations.rb
         
     | 
| 
      
 71 
     | 
    
         
            +
            - lib/core_ext/string.rb
         
     | 
| 
      
 72 
     | 
    
         
            +
            - lib/rails_dynamic_associations.rb
         
     | 
| 
      
 73 
     | 
    
         
            +
            - lib/rails_dynamic_associations/active_record.rb
         
     | 
| 
      
 74 
     | 
    
         
            +
            - lib/rails_dynamic_associations/active_record/associations.rb
         
     | 
| 
      
 75 
     | 
    
         
            +
            - lib/rails_dynamic_associations/active_record/relations.rb
         
     | 
| 
      
 76 
     | 
    
         
            +
            - lib/rails_dynamic_associations/active_record/roles.rb
         
     | 
| 
      
 77 
     | 
    
         
            +
            - lib/rails_dynamic_associations/engine.rb
         
     | 
| 
      
 78 
     | 
    
         
            +
            - lib/rails_dynamic_associations/version.rb
         
     | 
| 
      
 79 
     | 
    
         
            +
            - lib/tasks/rails_dynamic_associations_tasks.rake
         
     | 
| 
      
 80 
     | 
    
         
            +
            homepage: https://github.com/softpro/rails_dynamic_associations
         
     | 
| 
      
 81 
     | 
    
         
            +
            licenses:
         
     | 
| 
      
 82 
     | 
    
         
            +
            - MIT
         
     | 
| 
      
 83 
     | 
    
         
            +
            metadata: {}
         
     | 
| 
      
 84 
     | 
    
         
            +
            post_install_message: 
         
     | 
| 
      
 85 
     | 
    
         
            +
            rdoc_options: []
         
     | 
| 
      
 86 
     | 
    
         
            +
            require_paths:
         
     | 
| 
      
 87 
     | 
    
         
            +
            - lib
         
     | 
| 
      
 88 
     | 
    
         
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 89 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 90 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 91 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 92 
     | 
    
         
            +
                  version: '0'
         
     | 
| 
      
 93 
     | 
    
         
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 94 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 95 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 96 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 97 
     | 
    
         
            +
                  version: '0'
         
     | 
| 
      
 98 
     | 
    
         
            +
            requirements: []
         
     | 
| 
      
 99 
     | 
    
         
            +
            rubyforge_project: 
         
     | 
| 
      
 100 
     | 
    
         
            +
            rubygems_version: 2.2.2
         
     | 
| 
      
 101 
     | 
    
         
            +
            signing_key: 
         
     | 
| 
      
 102 
     | 
    
         
            +
            specification_version: 4
         
     | 
| 
      
 103 
     | 
    
         
            +
            summary: DB-driven model associations for Rails.
         
     | 
| 
      
 104 
     | 
    
         
            +
            test_files: []
         
     |