status_for 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2012 YOURNAME
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.rdoc ADDED
@@ -0,0 +1,3 @@
1
+ = ActsAsStatusFor
2
+
3
+ This project rocks and uses MIT-LICENSE.
data/Rakefile ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ require 'rspec/core/rake_task'
5
+ rescue LoadError
6
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
7
+ end
8
+ begin
9
+ require 'rdoc/task'
10
+ rescue LoadError
11
+ require 'rdoc/rdoc'
12
+ require 'rake/rdoctask'
13
+ RDoc::Task = Rake::RDocTask
14
+ end
15
+
16
+ RDoc::Task.new(:rdoc) do |rdoc|
17
+ rdoc.rdoc_dir = 'rdoc'
18
+ rdoc.title = 'ActsAsStatusFor'
19
+ rdoc.options << '--line-numbers'
20
+ rdoc.rdoc_files.include('README.rdoc')
21
+ rdoc.rdoc_files.include('lib/**/*.rb')
22
+ end
23
+
24
+ RSpec::Core::RakeTask.new(:spec)
25
+
26
+
27
+ task :default => :spec
28
+
29
+
30
+
31
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,176 @@
1
+ module StatusFor
2
+ def self.included(base)
3
+ base.extend StatusFor
4
+ end
5
+
6
+ module StatusFor
7
+
8
+ # Include initialize_status_for in the model class that you want the status_for to exists.
9
+ # Step 1:
10
+ # Example: Defining a deleted_for in Message model
11
+ # In message.rb, include "initialize_status_for (Object)" where subject is the status for
12
+ # in question, like a user.
13
+ # Example: initialize_status_for User
14
+
15
+ # Step 2:
16
+ # In a migration, include a 'status_for' column in the model of interest.
17
+ # This looks something like add_column :messages, :deleted_for, "integer[]"
18
+ # The postgres extension intarray is needed for this, so you may need to add the line
19
+ # execute "CREATE EXTENSION IF NOT EXISTS intarray"
20
+ # in the correct migration
21
+ def initialize_status_for(subject)
22
+ cattr_accessor :status_for_subject
23
+ if !subject.is_a? Class
24
+ raise "Subject must be defined as a proper class!"
25
+ else
26
+ self.status_for_subject = subject.name
27
+ end
28
+
29
+
30
+ def method_missing(method_id, subject)
31
+ # This creates a method for self called 'status_for(subject)' that finds all the
32
+ # self items with the 'status_for' with the subject id.
33
+ # Example: Message.deleted_for(user)
34
+ # Returns array of messages which contains user.id in the message's 'deleted_for'
35
+ if method_id.to_s =~ /^([a-z]+)_for$/
36
+ run_find_status_for($1, subject)
37
+
38
+ # This creates a method for self called 'not_status_for(subject)' that finds all the
39
+ # self items with the 'status_for' THAT DOES NOT HAVE the subject id.
40
+ # Example: Message.deleted_for(user)
41
+ # Returns array of messages which DOES NOT contain user.id in the message's 'deleted_for'
42
+ elsif method_id.to_s =~ /^not_([a-z]+)_for$/
43
+ run_find_not_status_for($1, subject)
44
+ else
45
+ super
46
+ end
47
+ end
48
+
49
+ # Ensuring the method created for the class exists
50
+ def respond_to?(method_id, include_private = false)
51
+ if method_id.to_s =~ /^([a-z]+)_for$/ || method_id.to_s =~ /^not_([a-z]+)_for$/
52
+ true
53
+ else
54
+ super
55
+ end
56
+ end
57
+
58
+ # The action performed when calling Message.status_for(subject). Uses a postgres-extension
59
+ # query
60
+ def run_find_status_for(method_id, subject)
61
+ unless subject.class.name == self.status_for_subject
62
+ raise "Acts_as_status_for is not defined for #{subject.class.name}"
63
+ end
64
+ self.where("idx(#{self.table_name}.#{method_id}_for, #{subject.id})::boolean")
65
+ end
66
+
67
+ # The action performed when calling Message.not_status_for(subject). Uses a postgres-extension
68
+ # query
69
+ def run_find_not_status_for(method_id, subject)
70
+ unless subject.class.name == self.status_for_subject
71
+ raise "Acts_as_status_for is not defined for #{subject.class.name}"
72
+ end
73
+ self.where("idx(#{self.table_name}.#{method_id}_for, #{subject.id}) <> 1")
74
+ end
75
+ include Status_For_Utils
76
+ include StatusInstanceMethods
77
+ end
78
+ end
79
+
80
+ module Status_For_Utils
81
+ # Some conversion is needed to save arrays into the postgresql database tables.
82
+ def status_for_psql_array_to_array(psql_group)
83
+ if psql_group
84
+ eval(psql_group.gsub('NULL', '').gsub('{', '[').gsub('}', ']'))
85
+ else
86
+ []
87
+ end
88
+ end
89
+
90
+ def status_for_array_to_psql_array(group)
91
+ mgroup = group.kind_of?(Array) ? group : [group]
92
+ mgroup.to_s.gsub('[', '{').gsub(']', '}')
93
+ end
94
+ end
95
+
96
+ module StatusInstanceMethods
97
+
98
+ def method_missing(method_id, subject_ids)
99
+ # This creates a method for instanced object called 'mark_as_status_for(subject)' that
100
+ # adds the subject id into relevant database column.
101
+ # Example: @message.mark_as_deleted_for(user)
102
+ # Returns a message with the deleted_for containing the subject id
103
+ if method_id.to_s =~ /^mark_as_([a-z]+)_for\!$/
104
+ run_mark_as_status_for!($1, subject_ids)
105
+ # This creates a method for instanced object called 'mark_as_not_ status_for(subject)' that
106
+ # removes the subject id into relevant database column.
107
+ # Example: @message.mark_as_not_deleted_for(user)
108
+ # Returns a message with the subject_id in the deleted_for column removed.
109
+ elsif method_id.to_s =~ /^mark_as_not_([a-z]+)_for\!$/
110
+ run_mark_as_not_status_for!($1, subject_ids)
111
+ # This creates a method for instanced object called 'check_status_for(subject)' that
112
+ # checks if the subject id is contained in the object.
113
+ # Example: @message.check_deleted_for(user)
114
+ # Returns true or false
115
+ elsif method_id.to_s =~ /^check_([a-z]+)_for\?$/
116
+ run_check_status_for($1, subject_ids)
117
+ else
118
+ super
119
+ end
120
+ end
121
+
122
+ # Ensuring the method created for the instanced class exists
123
+ def respond_to?(method_id, include_private = false)
124
+ if method_id.to_s =~ /^mark_as_([a-z]+)_for\!$/ || method_id.to_s =~ /^mark_as_not_([a-z]+)_for\!$/ || method_id.to_s =~ /^check_([a-z]+)_for\?$/
125
+ true
126
+ else
127
+ super
128
+ end
129
+ end
130
+
131
+ # The action performed when calling @object.mark_as_status_for(subject). Uses a postgres-extension
132
+ # query
133
+ def run_mark_as_status_for!(method_id, subject_ids)
134
+ if !self.class.column_names.include?(method_id + '_for')
135
+ raise "need to include the #{method_id}_for column in #{self.class.table_name} table"
136
+ end
137
+ if subject_ids.is_a? Integer
138
+ subject_ids = [subject_ids]
139
+ end
140
+ status_for_subjects = status_for_psql_array_to_array(self.send ((method_id +'_for').to_sym))
141
+ status_for_subjects = (status_for_subjects + subject_ids).flatten.uniq
142
+ self.update_attribute(method_id + '_for', status_for_array_to_psql_array(status_for_subjects))
143
+ self
144
+ end
145
+
146
+ # The action performed when calling @object.mark_as_not_status_for(subject). Uses a postgres-extension
147
+ # query
148
+ def run_mark_as_not_status_for!(method_id, subject_ids)
149
+ if !self.class.column_names.include?(method_id + '_for')
150
+ raise "need to include the #{method_id}_for column in #{self.class.table_name} table"
151
+ end
152
+ if subject_ids.is_a? Integer
153
+ subject_ids = [subject_ids]
154
+ end
155
+ status_for_subjects = status_for_psql_array_to_array(self.send ((method_id +'_for').to_sym))
156
+ status_for_subjects = (status_for_subjects - subject_ids).flatten.uniq
157
+ self.update_attribute(method_id + '_for', status_for_array_to_psql_array(status_for_subjects))
158
+ self
159
+ end
160
+
161
+ # The action performed when calling @object.check_status_for(subject). Uses a postgres-extension
162
+ # query
163
+ def run_check_status_for(method_id, subject_id)
164
+ if !self.class.column_names.include?(method_id + '_for')
165
+ raise "need to include the #{method_id}_for column in #{self.class.table_name} table"
166
+ end
167
+ unless subject_id.is_a? Integer
168
+ raise "subject_id must be an Integer!"
169
+ end
170
+ return status_for_psql_array_to_array(self.send ((method_id +'_for').to_sym)).include?(subject_id)
171
+ end
172
+ end
173
+
174
+ end
175
+
176
+ ActiveRecord::Base.send :include, StatusFor
@@ -0,0 +1,3 @@
1
+ module ActsAsStatusFor
2
+ VERSION = "0.0.1"
3
+ end
data/lib/status_for.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'status_for/version'
2
+ require 'status_for/acts_as_statusable_for'
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: status_for
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - David Leung
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-09-10 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rails
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 3.2.8
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 3.2.8
30
+ - !ruby/object:Gem::Dependency
31
+ name: pg
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec-rails
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '2.0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '2.0'
62
+ description: Include this in the module which will allow you to search for status
63
+ for a class.
64
+ email:
65
+ - davleun@gmail.com
66
+ executables: []
67
+ extensions: []
68
+ extra_rdoc_files: []
69
+ files:
70
+ - lib/status_for/version.rb
71
+ - lib/status_for/acts_as_statusable_for.rb
72
+ - lib/status_for.rb
73
+ - MIT-LICENSE
74
+ - Rakefile
75
+ - README.rdoc
76
+ homepage: ''
77
+ licenses: []
78
+ post_install_message:
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 1.8.24
97
+ signing_key:
98
+ specification_version: 3
99
+ summary: Allows tailored status like 'read' or 'deleted' for a class, like a user
100
+ or message.
101
+ test_files: []