acts_in_relation 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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