acts_in_relation 0.1.1 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 92a9c127a3f1fb388603b635643e90c4069639bf
4
- data.tar.gz: 67a69244746409b35ada1c5a6e0aed846753f660
3
+ metadata.gz: 98631806c248ec6a232438391598ca3c3b6d1429
4
+ data.tar.gz: 15a8894cde8f8da9d753d647be4220c4c373d0f6
5
5
  SHA512:
6
- metadata.gz: 4d42116922125188f848c9a50abc955bffc5840381b9686f35bd4701ce3bbc1144e2e50f2117d8d69fdfbd9928807fcbfda13282a46523d2f719fe36cc12d96c
7
- data.tar.gz: 1c31f8d090a83f85241becd3878518ed4bd645b8764c78cac3170f90417937c15be2fd6e1804914d4fd4ceb248c8914d876ee01df969327d219143937ec4cd63
6
+ metadata.gz: cab9fb68c574f05868c3abc17c5cd26638ab901041f6008cc8996e231398bc8087d3002201ead3e2f9ba60cbfd98e9d87e4ab6b965ec040c523233f97f8cf297
7
+ data.tar.gz: 2b754e9fb4eacba5be95acbdb2dc7eff4adf15220ab32afd96bd87008b90ba4110356b404db0564727cc30d5c5611d359ea722bd992bd2991dff94b76c0f9ce3
@@ -0,0 +1,9 @@
1
+ .bundle/
2
+ log/*.log
3
+ pkg/
4
+ spec/dummy/db/*.sqlite3
5
+ spec/dummy/db/*.sqlite3-journal
6
+ spec/dummy/log/*.log
7
+ spec/dummy/tmp/
8
+ spec/dummy/.sass-cache
9
+ Gemfile.lock
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,151 @@
1
+ # acts_in_relation
2
+
3
+ [![Build Status](https://travis-ci.org/kami30k/acts_in_relation.svg)](https://travis-ci.org/kami30k/acts_in_relation)
4
+ [![Gem Version](https://badge.fury.io/rb/acts_in_relation.svg)](http://badge.fury.io/rb/acts_in_relation)
5
+
6
+ acts_in_relation adds relational feature to Rails application, such as follow, block, like and so on.
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ ```ruby
13
+ gem 'acts_in_relation'
14
+ ```
15
+
16
+ And then execute:
17
+
18
+ ```
19
+ $ bundle
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ acts_in_relation supports two way to add relational feature.
25
+
26
+ 1. Add feature to oneself
27
+ 2. Add feature to between two models
28
+
29
+ Following example shows about User model, however, you can apply to any models.
30
+
31
+ ### 1. Add follow feature to User
32
+
33
+ This case adds follow feature to User model.
34
+
35
+ At first, generate User and Follow model:
36
+
37
+ ```
38
+ $ bin/rails g model User
39
+ $ bin/rails g model Follow user_id:integer target_user_id:integer
40
+ ```
41
+
42
+ Then migrate:
43
+
44
+ ```
45
+ $ bin/rake db:migrate
46
+ ```
47
+
48
+ At last, add `acts_in_relation` method to each models:
49
+
50
+ ```ruby
51
+ class User < ActiveRecord::Base
52
+ acts_in_relation role: :self, action: :follow
53
+ end
54
+
55
+ class Follow < ActiveRecord::Base
56
+ acts_in_relation role: :action, self: :user
57
+ end
58
+ ```
59
+
60
+ That's it.
61
+ User instance has been added following methods:
62
+
63
+ - user.follow(other_user)
64
+ - user.unfollow(other_user)
65
+ - user.following?(other_user)
66
+ - user.following
67
+ - other_user.followed_by?(user)
68
+ - other_user.followers
69
+
70
+ Example:
71
+
72
+ ```ruby
73
+ user = User.create
74
+ other_user = User.create
75
+
76
+ # Follow
77
+ user.follow other_user
78
+ user.following?(other_user) #=> true
79
+ user.following #=> <ActiveRecord::Associations::CollectionProxy [#<User id: 2, created_at: "2015-01-10 01:57:52", updated_at: "2015-01-10 01:57:52">]>
80
+ other_user.followed_by?(user) #=> true
81
+ other_user.followers #=> <ActiveRecord::Associations::CollectionProxy [#<User id: 1, created_at: "2015-01-10 01:57:42", updated_at: "2015-01-10 01:57:42">]>
82
+
83
+ # Unfollow
84
+ user.unfollow other_user
85
+ user.following?(other_user) #=> false
86
+ user.following #=> <ActiveRecord::Associations::CollectionProxy []>
87
+ other_user.followed_by?(user) #=> false
88
+ other_user.followers #=> <ActiveRecord::Associations::CollectionProxy []>
89
+ ```
90
+
91
+ At the same time, `:action` is able to be passed some actions:
92
+
93
+ ```ruby
94
+ class User < ActiveRecord::Base
95
+ acts_in_relation role: :self, action: [:follow, :block, :mute]
96
+ end
97
+ ```
98
+
99
+ ### 2. Add like feature to User and Post
100
+
101
+ This case adds like feature to User and Post model.
102
+
103
+ ```ruby
104
+ class User < ActiveRecord::Base
105
+ acts_in_relation role: :source, target: :post, action: :like
106
+ end
107
+
108
+ class Post < ActiveRecord::Base
109
+ acts_in_relation role: :target, source: :user, action: :like
110
+ end
111
+
112
+ class Like < ActiveRecord::Base
113
+ acts_in_relation role: :action, source: :user, target: :post
114
+ end
115
+ ```
116
+
117
+ User and Post instance has been added following methods:
118
+
119
+ - user.like(post)
120
+ - user.unlike(post)
121
+ - user.liking?(post)
122
+ - user.liking
123
+ - post.liked_by?(user)
124
+ - post.likers
125
+
126
+ At the same time, some `acts_in_relation` methods are able to be defined:
127
+
128
+ ```ruby
129
+ class User < ActiveRecord::Base
130
+ acts_in_relation role: :self, action: :follow
131
+ acts_in_relation role: :source, target: :post, action: :like
132
+ end
133
+ ```
134
+
135
+ ## Roles
136
+
137
+ acts_in_relation has three roles: source, target and action.
138
+
139
+ | Role | Outline | (1) | (2) |
140
+ | --- | --- | --- | --- |
141
+ | source | The model that performs the action. | User | User |
142
+ | target | The model that receives the action. | User | Post |
143
+ | action | The action performs between two models. | Follow | Like |
144
+
145
+ ## Contributing
146
+
147
+ 1. Fork it ( https://github.com/kami30k/acts_in_relation/fork )
148
+ 2. Create your feature branch (git checkout -b my-new-feature)
149
+ 3. Commit your changes (git commit -am 'Add some feature')
150
+ 4. Push to the branch (git push origin my-new-feature)
151
+ 5. Create a new Pull Request
data/Rakefile CHANGED
@@ -1,21 +1,7 @@
1
- begin
2
- require 'bundler/setup'
3
- rescue LoadError
4
- puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
- end
6
-
7
- require 'rdoc/task'
1
+ require 'bundler'
2
+ require 'rspec/core/rake_task'
8
3
 
9
- RDoc::Task.new(:rdoc) do |rdoc|
10
- rdoc.rdoc_dir = 'rdoc'
11
- rdoc.title = 'ActsInRelation'
12
- rdoc.options << '--line-numbers'
13
- rdoc.rdoc_files.include('README.rdoc')
14
- rdoc.rdoc_files.include('lib/**/*.rb')
15
- end
4
+ Bundler::GemHelper.install_tasks
16
5
 
17
- require 'rspec/core/rake_task'
18
6
  RSpec::Core::RakeTask.new(:spec)
19
7
  task default: :spec
20
-
21
- Bundler::GemHelper.install_tasks
@@ -0,0 +1,24 @@
1
+ $:.unshift File.expand_path('../lib', __FILE__)
2
+
3
+ require 'acts_in_relation/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'acts_in_relation'
7
+ s.version = ActsInRelation::VERSION
8
+ s.authors = 'kami'
9
+ s.email = 'kami30k@gmail.com'
10
+
11
+ s.summary = 'Add relational feature to Rails (e.g. follow, block and like).'
12
+ s.description = 'Add relational feature to Rails (e.g. follow, block and like).'
13
+ s.homepage = 'https://github.com/kami30k/acts_in_relation'
14
+ s.license = 'MIT'
15
+
16
+ s.files = `git ls-files -z`.split("\x0")
17
+
18
+ s.add_dependency 'rails'
19
+ s.add_dependency 'verbs'
20
+ s.add_dependency 'caller_class'
21
+
22
+ s.add_development_dependency 'sqlite3'
23
+ s.add_development_dependency 'rspec-rails'
24
+ end
@@ -1,14 +1,29 @@
1
1
  require 'acts_in_relation/version'
2
+ require 'acts_in_relation/railtie' if defined?(Rails)
2
3
 
3
4
  module ActsInRelation
4
- autoload :Core, 'acts_in_relation/core'
5
- autoload :Source, 'acts_in_relation/source'
6
- autoload :Target, 'acts_in_relation/target'
7
- autoload :Action, 'acts_in_relation/action'
5
+ class MissingRoleError < StandardError; end
6
+
7
+ class UnknownRoleError < StandardError
8
+ def initialize(role)
9
+ @role = role
10
+ end
11
+
12
+ def to_s
13
+ ":role should be one of :source, :target, :action or :self (#{@role} is passed)"
14
+ end
15
+ end
16
+
17
+ autoload :Core, 'acts_in_relation/core'
18
+
19
+ module Roles
20
+ autoload :Base, 'acts_in_relation/roles/base'
21
+ autoload :Source, 'acts_in_relation/roles/source'
22
+ autoload :Target, 'acts_in_relation/roles/target'
23
+ autoload :Action, 'acts_in_relation/roles/action'
24
+ end
8
25
 
9
26
  module Supports
10
27
  autoload :Verb, 'acts_in_relation/supports/verb'
11
28
  end
12
-
13
- require 'acts_in_relation/railtie' if defined?(Rails)
14
29
  end
@@ -1,54 +1,73 @@
1
- require 'caller_class'
2
-
3
1
  module ActsInRelation
4
2
  module Core
5
- def self.included(base)
6
- base.extend ClassMethods
7
- end
8
-
9
- module ClassMethods
10
- include CallerClass
11
-
12
- def acts_in_relation(position = :self, params)
13
- relation = Relation.new(position, params, caller_class.downcase)
14
- relation.define
3
+ class << self
4
+ def included(base)
5
+ base.extend ClassMethods
15
6
  end
16
7
  end
17
8
 
18
- class Relation
19
- def initialize(position, params, class_name)
20
- @position = position
21
- @params = params
22
- @class_name = class_name
23
- end
9
+ module ClassMethods
10
+ # DSL called to a subclass of ActiveRecord::Base
11
+ #
12
+ # @param [Hash] args Define relation with :role, :action, :source, :target or :self.
13
+ #
14
+ # @example Define self relation
15
+ # class User < ActiveRecord::Base
16
+ # acts_in_relation role: :self, action: [:follow, :block]
17
+ # end
18
+ #
19
+ # class Follow < ActiveRecord::Base
20
+ # acts_in_relation role: :action, self: :user
21
+ # end
22
+ #
23
+ # class Block < ActiveRecord::Base
24
+ # acts_in_relation role: :action, self: :user
25
+ # end
26
+ #
27
+ # @example Define relation of each models
28
+ # class User < ActiveRecord::Base
29
+ # acts_in_relation role: :source, target: :post, action: :like
30
+ # end
31
+ #
32
+ # class Post < ActiveRecord::Base
33
+ # acts_in_relation role: :target, source: :user, action: :like
34
+ # end
35
+ #
36
+ # class Like < ActiveRecord::Base
37
+ # acts_in_relation role: :action, source: :user, target: :post
38
+ # end
39
+ def acts_in_relation(**args)
40
+ @args = args
24
41
 
25
- def define
26
- positions = (@position == :self) ? [:source, :target] : [@position]
27
- positions.each do |position|
28
- extend "ActsInRelation::#{position.capitalize}".constantize
29
- define
42
+ case @args[:role]
43
+ when nil
44
+ raise ActsInRelation::MissingRoleError
45
+ when :source
46
+ define_source
47
+ when :target
48
+ define_target
49
+ when :action
50
+ define_action
51
+ when :self
52
+ define_source
53
+ define_target
54
+ else
55
+ raise ActsInRelation::UnknownRoleError, @args[:role]
30
56
  end
31
57
  end
32
58
 
33
59
  private
34
60
 
35
- def source
36
- @source ||= @params[:source] || @class_name
37
- end
38
-
39
- def target
40
- @target ||= @params[:target] || @class_name
61
+ def define_source
62
+ ActsInRelation::Roles::Source.new(@args).define
41
63
  end
42
64
 
43
- # TODO: Return instance if exists
44
- def with
45
- with = @params[:with]
46
- with = with.kind_of?(Array) ? with : [with]
47
- with.map(&:to_s)
65
+ def define_target
66
+ ActsInRelation::Roles::Target.new(@args).define
48
67
  end
49
68
 
50
- def class_object
51
- @class_object ||= @class_name.to_s.capitalize.constantize
69
+ def define_action
70
+ ActsInRelation::Roles::Action.new(@args).define
52
71
  end
53
72
  end
54
73
  end
@@ -1,8 +1,6 @@
1
- require 'rails'
2
-
3
1
  module ActsInRelation
4
2
  class Railtie < Rails::Railtie
5
- initializer 'acts_in_relation' do |app|
3
+ initializer 'acts_in_relation' do
6
4
  ActiveSupport.on_load :active_record do
7
5
  include ActsInRelation::Core
8
6
  end
@@ -0,0 +1,15 @@
1
+ module ActsInRelation
2
+ module Roles
3
+ class Action < Base
4
+ def define
5
+ @class.class_eval <<-RUBY
6
+ belongs_to :"#{source}"
7
+
8
+ belongs_to :"target_#{target}",
9
+ class_name: "#{target.capitalize}",
10
+ foreign_key: :"target_#{target}_id"
11
+ RUBY
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,46 @@
1
+ require 'caller_class'
2
+
3
+ module ActsInRelation
4
+ module Roles
5
+ class Base
6
+ include CallerClass
7
+ include ActsInRelation::Supports::Verb
8
+
9
+ def initialize(args)
10
+ @class = caller_class.constantize
11
+ @args = recursive_to_s(args)
12
+ end
13
+
14
+ def source
15
+ @source ||= @args[:source] || @args[:self] || @class.to_s.downcase
16
+ end
17
+
18
+ def target
19
+ @target ||= @args[:target] || @args[:self] || @class.to_s.downcase
20
+ end
21
+
22
+ def actions
23
+ @actions ||= [@args[:action]].flatten
24
+ end
25
+
26
+ def define
27
+ raise NotImplementedError
28
+ end
29
+
30
+ private
31
+
32
+ def recursive_to_s(object)
33
+ case object
34
+ when Hash
35
+ object.each do |k, v|
36
+ object[k] = recursive_to_s(v)
37
+ end
38
+ when Array
39
+ object.map { |o| recursive_to_s(o) }
40
+ else
41
+ object.to_s unless object.nil?
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,35 @@
1
+ module ActsInRelation
2
+ module Roles
3
+ class Source < Base
4
+ def define
5
+ actions.each do |action|
6
+ @class.class_eval <<-RUBY
7
+ has_many :"#{action.pluralize}",
8
+ foreign_key: :"#{source}_id",
9
+ dependent: :destroy
10
+
11
+ has_many :"#{progressize(action)}",
12
+ through: :"#{action.pluralize}",
13
+ source: :"target_#{target}"
14
+
15
+ def #{action}(target)
16
+ return if #{progressize(action)}?(target) || (self == target)
17
+
18
+ #{action.pluralize}.create(target_#{target}_id: target.id)
19
+ end
20
+
21
+ def un#{action}(target)
22
+ return unless #{progressize(action)}?(target)
23
+
24
+ #{action.pluralize}.find_by(target_#{target}_id: target.id).destroy
25
+ end
26
+
27
+ def #{progressize(action)}?(target)
28
+ #{action.pluralize}.exists?(target_#{target}_id: target.id)
29
+ end
30
+ RUBY
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,24 @@
1
+ module ActsInRelation
2
+ module Roles
3
+ class Target < Base
4
+ def define
5
+ actions.each do |action|
6
+ @class.class_eval <<-RUBY
7
+ has_many :"#{action.pluralize}_as_target",
8
+ foreign_key: :"target_#{target}_id",
9
+ class_name: action.capitalize,
10
+ dependent: :destroy
11
+
12
+ has_many :"#{peoplize(action)}",
13
+ through: :"#{action.pluralize}_as_target",
14
+ source: :"#{source}"
15
+
16
+ def #{pastize(action)}_by?(source)
17
+ source.#{action.pluralize}.exists?(#{source}_id: source.id)
18
+ end
19
+ RUBY
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -7,20 +7,19 @@ module ActsInRelation
7
7
  'follow' => 'following'
8
8
  }
9
9
 
10
- def pastize
11
- verb.conjugate(tense: :past).split(' ').last
10
+ def pastize(object)
11
+ object.verb.conjugate(tense: :past).split(' ').last
12
12
  end
13
13
 
14
- def progressize
15
- return PATCHES[self] if PATCHES.has_key?(self)
14
+ def progressize(object)
15
+ return PATCHES[object] if PATCHES.has_key?(object)
16
16
 
17
- verb.conjugate(aspect: :progressive).split(' ').last
17
+ object.verb.conjugate(aspect: :progressive).split(' ').last
18
18
  end
19
19
 
20
- # TODO: Implement this method more logically
21
- def peoplize
22
- action = (last == 'e') ? chop : self
23
- action + 'ers'
20
+ # @todo Implement more logically
21
+ def peoplize(object)
22
+ (object.last == 'e' ? object.chop : object) + 'ers'
24
23
  end
25
24
  end
26
25
  end
@@ -1,3 +1,3 @@
1
1
  module ActsInRelation
2
- VERSION = "0.1.1"
2
+ VERSION = '0.2.0'
3
3
  end
@@ -0,0 +1,86 @@
1
+ require 'action_controller/railtie'
2
+ require 'active_record'
3
+
4
+ require 'acts_in_relation'
5
+
6
+ module Dummy
7
+ class Application < Rails::Application
8
+ config.secret_token = 'abcdefghijklmnopqrstuvwxyz0123456789'
9
+ config.session_store :cookie_store, key: '_dummy_session'
10
+ config.eager_load = false
11
+ config.active_support.deprecation = :log
12
+ end
13
+ end
14
+
15
+ Dummy::Application.initialize!
16
+
17
+ ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
18
+
19
+ #
20
+ # Models
21
+ #
22
+
23
+ class User < ActiveRecord::Base
24
+ acts_in_relation role: :self, action: [:follow, :block, :mute]
25
+
26
+ acts_in_relation role: :source, target: :post, action: :like
27
+ end
28
+
29
+ class Post < ActiveRecord::Base
30
+ acts_in_relation role: :target, source: :user, action: :like
31
+ end
32
+
33
+ class Follow < ActiveRecord::Base
34
+ acts_in_relation role: :action, self: :user
35
+ end
36
+
37
+ class Like < ActiveRecord::Base
38
+ acts_in_relation role: :action, source: :user, target: :post
39
+ end
40
+
41
+ #
42
+ # Migrates
43
+ #
44
+
45
+ class CreateUsers < ActiveRecord::Migration
46
+ def change
47
+ create_table :users do |t|
48
+ t.timestamps null: false
49
+ end
50
+ end
51
+ end
52
+
53
+ class CreatePosts < ActiveRecord::Migration
54
+ def change
55
+ create_table :posts do |t|
56
+ t.timestamps null: false
57
+ end
58
+ end
59
+ end
60
+
61
+ class CreateFollows < ActiveRecord::Migration
62
+ def change
63
+ create_table :follows do |t|
64
+ t.integer :user_id
65
+ t.integer :target_user_id
66
+
67
+ t.timestamps null: false
68
+ end
69
+ end
70
+ end
71
+
72
+ class CreateLikes < ActiveRecord::Migration
73
+ def change
74
+ create_table :likes do |t|
75
+ t.integer :user_id
76
+ t.integer :target_post_id
77
+
78
+ t.timestamps null: false
79
+ end
80
+ end
81
+ end
82
+
83
+ CreateUsers.new.change
84
+ CreatePosts.new.change
85
+ CreateFollows.new.change
86
+ CreateLikes.new.change
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ APP_PATH = File.expand_path('../../application', __FILE__)
4
+
5
+ require 'rails/commands'
@@ -0,0 +1 @@
1
+ run Rails.application
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ describe Post, type: :model do
4
+ let(:user) { User.create }
5
+ let(:post) { Post.create }
6
+
7
+ describe 'instance methods' do
8
+ it 'should be defined' do
9
+ # source: :user, action: :like
10
+ expect(post).not_to respond_to(:like)
11
+ expect(post).not_to respond_to(:unlike)
12
+ expect(post).not_to respond_to(:liking?)
13
+ expect(post).not_to respond_to(:liking)
14
+ expect(post).to respond_to(:liked_by?)
15
+ expect(post).to respond_to(:likers)
16
+ end
17
+ end
18
+
19
+ describe '#liked_by?' do
20
+ before { user.like post }
21
+
22
+ it 'should be liked by user' do
23
+ expect(post).to be_liked_by(user)
24
+ end
25
+ end
26
+
27
+ describe '#likers' do
28
+ before { user.like post }
29
+
30
+ it 'should be included user' do
31
+ expect(post.likers).to be_exists(id: user.id)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,122 @@
1
+ require 'spec_helper'
2
+
3
+ describe User, type: :model do
4
+ let(:user) { User.create }
5
+ let(:other_user) { User.create }
6
+
7
+ describe 'instance methods' do
8
+ it 'should be defined' do
9
+ # action: :follow
10
+ expect(user).to respond_to(:follow)
11
+ expect(user).to respond_to(:unfollow)
12
+ expect(user).to respond_to(:following?)
13
+ expect(user).to respond_to(:following)
14
+ expect(user).to respond_to(:followed_by?)
15
+ expect(user).to respond_to(:followers)
16
+
17
+ # action: :block
18
+ expect(user).to respond_to(:block)
19
+ expect(user).to respond_to(:unblock)
20
+ expect(user).to respond_to(:blocking?)
21
+ expect(user).to respond_to(:blocking)
22
+ expect(user).to respond_to(:blocked_by?)
23
+ expect(user).to respond_to(:blockers)
24
+
25
+ # action: :mute
26
+ expect(user).to respond_to(:mute)
27
+ expect(user).to respond_to(:unmute)
28
+ expect(user).to respond_to(:muting?)
29
+ expect(user).to respond_to(:muting)
30
+ expect(user).to respond_to(:muted_by?)
31
+ expect(user).to respond_to(:muters)
32
+
33
+ # target: :post, action: :like
34
+ expect(user).to respond_to(:like)
35
+ expect(user).to respond_to(:unlike)
36
+ expect(user).to respond_to(:liking?)
37
+ expect(user).to respond_to(:liking)
38
+ expect(user).not_to respond_to(:liked_by?)
39
+ expect(user).not_to respond_to(:likers)
40
+ end
41
+ end
42
+
43
+ describe '#follow' do
44
+ context 'unfollow user' do
45
+ before { user.follow other_user }
46
+
47
+ it 'should be followed' do
48
+ expect(user.follows).to be_exists(target_user_id: other_user.id)
49
+ end
50
+ end
51
+
52
+ context 'following user' do
53
+ before do
54
+ user.follow other_user
55
+ user.follow other_user
56
+ end
57
+
58
+ it 'should be followed only once' do
59
+ expect(user.follows.count).to eq(1)
60
+ end
61
+ end
62
+
63
+ context 'user-self' do
64
+ before { user.follow user }
65
+
66
+ it 'should not be followed' do
67
+ expect(user.follows).not_to be_exists(target_user_id: user.id)
68
+ end
69
+ end
70
+ end
71
+
72
+ describe '#unfollow' do
73
+ context 'following user' do
74
+ before do
75
+ user.follow other_user
76
+ user.unfollow other_user
77
+ end
78
+
79
+ it 'should be unfollowed' do
80
+ expect(user.follows).not_to be_exists(target_user_id: other_user.id)
81
+ end
82
+ end
83
+
84
+ context 'unfollow user' do
85
+ it 'should not raise error' do
86
+ expect { user.unfollow other_user }.not_to raise_error
87
+ end
88
+ end
89
+ end
90
+
91
+ describe '#following?' do
92
+ before { user.follow other_user }
93
+
94
+ it 'should be followed' do
95
+ expect(user).to be_following(other_user)
96
+ end
97
+ end
98
+
99
+ describe '#following' do
100
+ before { user.follow other_user }
101
+
102
+ it 'should be included other user' do
103
+ expect(user.following).to be_exists(other_user.id)
104
+ end
105
+ end
106
+
107
+ describe '#followed_by?' do
108
+ before { other_user.follow user }
109
+
110
+ it 'should be followed by other user' do
111
+ expect(user).to be_followed_by(other_user)
112
+ end
113
+ end
114
+
115
+ describe '#followers' do
116
+ before { other_user.follow user }
117
+
118
+ it 'should be included other user' do
119
+ expect(user.followers).to be_exists(other_user.id)
120
+ end
121
+ end
122
+ end
@@ -0,0 +1 @@
1
+ require 'dummy/application'
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts_in_relation
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - kami
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-20 00:00:00.000000000 Z
11
+ date: 2015-04-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 4.2.0
19
+ version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 4.2.0
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: verbs
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -80,24 +80,34 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
- description: Rails plugin that adds a relational feature to Model, such as follow,
84
- block, mute, or like and so on.
85
- email:
86
- - kami30k@gmail.com
83
+ description: Add relational feature to Rails (e.g. follow, block and like).
84
+ email: kami30k@gmail.com
87
85
  executables: []
88
86
  extensions: []
89
87
  extra_rdoc_files: []
90
88
  files:
89
+ - ".gitignore"
90
+ - ".travis.yml"
91
+ - Gemfile
91
92
  - MIT-LICENSE
93
+ - README.md
92
94
  - Rakefile
95
+ - acts_in_relation.gemspec
93
96
  - lib/acts_in_relation.rb
94
- - lib/acts_in_relation/action.rb
95
97
  - lib/acts_in_relation/core.rb
96
98
  - lib/acts_in_relation/railtie.rb
97
- - lib/acts_in_relation/source.rb
99
+ - lib/acts_in_relation/roles/action.rb
100
+ - lib/acts_in_relation/roles/base.rb
101
+ - lib/acts_in_relation/roles/source.rb
102
+ - lib/acts_in_relation/roles/target.rb
98
103
  - lib/acts_in_relation/supports/verb.rb
99
- - lib/acts_in_relation/target.rb
100
104
  - lib/acts_in_relation/version.rb
105
+ - spec/dummy/application.rb
106
+ - spec/dummy/bin/rails
107
+ - spec/dummy/config.ru
108
+ - spec/models/post_spec.rb
109
+ - spec/models/user_spec.rb
110
+ - spec/spec_helper.rb
101
111
  homepage: https://github.com/kami30k/acts_in_relation
102
112
  licenses:
103
113
  - MIT
@@ -118,9 +128,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
118
128
  version: '0'
119
129
  requirements: []
120
130
  rubyforge_project:
121
- rubygems_version: 2.2.2
131
+ rubygems_version: 2.4.6
122
132
  signing_key:
123
133
  specification_version: 4
124
- summary: Rails plugin that adds a relational feature to Model, such as follow, block,
125
- mute, or like and so on.
134
+ summary: Add relational feature to Rails (e.g. follow, block and like).
126
135
  test_files: []
@@ -1,10 +0,0 @@
1
- module ActsInRelation
2
- module Action
3
- def define
4
- class_object.class_eval <<-RUBY
5
- belongs_to :"#{source}"
6
- belongs_to :"target_#{target}", class_name: "#{target.capitalize}", foreign_key: :"target_#{target}_id"
7
- RUBY
8
- end
9
- end
10
- end
@@ -1,35 +0,0 @@
1
- module ActsInRelation
2
- module Source
3
- def define
4
- with.each do |action|
5
- action.extend ActsInRelation::Supports::Verb
6
-
7
- class_object.class_eval <<-RUBY
8
- has_many :"#{action.pluralize}",
9
- foreign_key: :"#{source}_id",
10
- dependent: :destroy
11
-
12
- has_many :"#{action.progressize}",
13
- through: :"#{action.pluralize}",
14
- source: :"target_#{target}"
15
-
16
- def #{action}(target)
17
- return if #{action.progressize}?(target) || (self == target)
18
-
19
- #{action.pluralize}.create(target_#{target}_id: target.id)
20
- end
21
-
22
- def un#{action}(target)
23
- return unless #{action.progressize}?(target)
24
-
25
- #{action.pluralize}.find_by(target_#{target}_id: target.id).destroy
26
- end
27
-
28
- def #{action.progressize}?(target)
29
- #{action.pluralize}.exists?(target_#{target}_id: target.id)
30
- end
31
- RUBY
32
- end
33
- end
34
- end
35
- end
@@ -1,24 +0,0 @@
1
- module ActsInRelation
2
- module Target
3
- def define
4
- with.each do |action|
5
- action.extend ActsInRelation::Supports::Verb
6
-
7
- class_object.class_eval <<-RUBY
8
- has_many :"#{action.pluralize}_as_target",
9
- foreign_key: :"target_#{target}_id",
10
- class_name: action.capitalize,
11
- dependent: :destroy
12
-
13
- has_many :"#{action.peoplize}",
14
- through: :"#{action.pluralize}_as_target",
15
- source: :"#{source}"
16
-
17
- def #{action.pastize}_by?(source)
18
- source.#{action.pluralize}.exists?(#{source}_id: source.id)
19
- end
20
- RUBY
21
- end
22
- end
23
- end
24
- end