smart_list 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/lib/add_order_bit.rb +10 -0
  2. data/lib/smart_list.rb +204 -0
  3. metadata +47 -0
@@ -0,0 +1,10 @@
1
+ # -*- encoding : utf-8 -*-
2
+ class AddOrderBit < ActiveRecord::Migration
3
+
4
+ ORDER_BIT_DEFAULT = 100
5
+
6
+ def self.add_to_table(table_name)
7
+ add_column table_name, :order_bit, :integer, :default => ORDER_BIT_DEFAULT
8
+ end
9
+
10
+ end
data/lib/smart_list.rb ADDED
@@ -0,0 +1,204 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ require "smart_list"
4
+ require "add_order_bit"
5
+ require "smart_list_helper"
6
+ require "digest/sha1"
7
+
8
+ $active_smart_lists = {}
9
+
10
+ module SmartList
11
+
12
+ def self.included(base)
13
+ base.extend ClassMethods
14
+ end
15
+
16
+ module ClassMethods
17
+ def smart_list(options = {:order_bit => "order_bit", :group => nil, :scope_conditions => nil})
18
+ # Check if order_bit exists
19
+ options[:order_bit] ||= "order_bit"
20
+ options[:fixed] ||= false
21
+ if self.column_names.index(options[:order_bit].to_s).nil?
22
+ ::AddOrderBit.add_to_table(self.table_name)
23
+ else
24
+ unless is_smart_list?
25
+ cattr_accessor :group_col, :order_bit_name, :base_class, :fixed_list
26
+ send :include, InstanceMethods
27
+
28
+ $active_smart_lists.merge!(Digest::SHA1.hexdigest(self.name) => self.name)
29
+ end
30
+ self.send(:default_scope, :order => "#{options[:order_bit].to_s} ASC")
31
+ self.send(:before_create, :set_order_bit)
32
+ self.group_col = (options[:group].to_sym) rescue nil
33
+ self.order_bit_name = options[:order_bit].to_sym
34
+ self.base_class = options[:base_class].constantize rescue self.name.constantize
35
+ self.fixed_list = options[:fixed]
36
+ end
37
+ end
38
+
39
+ def grouped_list(group_name)
40
+ if self.group_col.nil? || self.group_col.blank?
41
+ self.find(:all)
42
+ else
43
+ self.find(:all, :conditions => {self.group_col => group_name})
44
+ end
45
+ end
46
+
47
+ def groups
48
+ if self.group_col.nil? || self.group_col.blank?
49
+ raise "This is not a grouped list - use options[:group] set colummn to group lists"
50
+ else
51
+ puts self.group_col.inspect
52
+ self.find(:all, :group => self.group_col).map {|x| x.group_name }
53
+ end
54
+ end
55
+
56
+ def group_list
57
+ self.groups.map {|group| self.find(:all, :conditions => {self.group_col => group})}
58
+ end
59
+
60
+ def is_smart_list?
61
+ self.included_modules.include?(InstanceMethods)
62
+ end
63
+
64
+ def reorder_group(group_name, options = {:order_by => :created_at})
65
+ if self.group_col.nil? || self.group_col.blank?
66
+ raise "Only grouped lists could be reordered"
67
+ else
68
+ transaction do
69
+ group = self.grouped_list(group_name)
70
+ order_mode = options[:order_by].to_s
71
+ ordered = group.sort_by {|item| item.send(order_mode)}
72
+ ordered.each_with_index do |item, i|
73
+ item[self.base_class.order_bit_name] = AddOrderBit::ORDER_BIT_DEFAULT+i
74
+ item.send(:update_without_callbacks)
75
+ end
76
+
77
+ new_group = self.grouped_list(group_name).map {|item| item.id}
78
+ if new_group == ordered.map {|item| item.id}
79
+ return true
80
+ else
81
+ raise ActiveRecord::Rollback
82
+ return false
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ module InstanceMethods
90
+ def move_up!
91
+ if self.base_class.fixed_list == false
92
+ unless self.order_position == 0
93
+ old_pos = self.order_bit_pos
94
+ pre_item = self.pre
95
+ if old_pos != pre_item.order_bit_pos
96
+ self.update_attributes(self.base_class.order_bit_name => pre_item.order_bit_pos)
97
+ pre_item.update_attributes(self.base_class.order_bit_name => old_pos)
98
+ else
99
+ self.update_attributes(self.base_class.order_bit_name => old_pos-1)
100
+ end
101
+ end
102
+ end
103
+ end
104
+
105
+ def move_down!
106
+ if self.base_class.fixed_list == false
107
+ if self.base_class.group_col.nil?
108
+ all = self.base_class.find(:all)
109
+ else
110
+ all = self.base_class.find(:all, :conditions => {self.base_class.group_col => self.send(self.base_class.group_col)})
111
+ end
112
+ unless self.order_position == all.size-1
113
+ old_pos = self.order_bit_pos
114
+ post_item = self.post
115
+ if old_pos != post_item.order_bit_pos
116
+ self.update_attributes(self.base_class.order_bit_name => post_item.order_bit_pos)
117
+ post_item.update_attributes(self.base_class.order_bit_name => old_pos)
118
+ else
119
+ self.update_attributes(self.base_class.order_bit_name => old_pos+1)
120
+ end
121
+ end
122
+ end
123
+ end
124
+
125
+ def group_list_items(conditions = {})
126
+ if self.base_class.group_col.nil? || self.base_class.group_col.blank?
127
+ self.base_class.find(:all)
128
+ else
129
+ self.base_class.find_by_sql("SELECT * from #{self.base_class.table_name} where #{self.base_class.group_col} = '#{self[self.base_class.group_col].to_s}' order by #{self.base_class.order_bit_name} ASC")
130
+ end
131
+ end
132
+
133
+ # Previos Item
134
+ def pre
135
+ pos = (self.order_position == 0 ? 0 : (self.order_position - 1 rescue 0))
136
+ all = self.group_list_items[pos]
137
+ end
138
+
139
+ # Next Item
140
+ def post
141
+ all = self.group_list_items
142
+ pos = (self.order_position == all.size-1 ? self.order_position : self.order_position + 1)
143
+ all[pos]
144
+ end
145
+
146
+ def order_position
147
+ all = self.group_list_items.map {|x| x.id}
148
+ all.index(self.id)
149
+ end
150
+
151
+ def order_bit_pos
152
+ self.attributes[self.base_class.order_bit_name.to_s]
153
+ end
154
+
155
+ def group_name
156
+ if self.base_class.group_col.nil?
157
+ ""
158
+ else
159
+ self.send(self.base_class.group_col.to_s)
160
+ end
161
+ end
162
+
163
+ def set_order_bit
164
+ if self.base_class.fixed_list == false
165
+ self[self.base_class.order_bit_name] = self.base_class.last[self.base_class.order_bit_name] + 1 rescue 100
166
+ end
167
+ end
168
+
169
+ def followers(options = {})
170
+ if self.base_class.group_col.nil?
171
+ self.base_class.find_by_sql("SELECT * from #{self.base_class.table_name} where #{self.base_class.order_bit_name} #{options[:include_self] == true ? '>=' : '>'} #{self.order_bit}")
172
+ else
173
+ self.base_class.find_by_sql("SELECT * from #{self.base_class.table_name} where #{self.base_class.order_bit_name} #{options[:include_self] == true ? '>=' : '>'} #{self.order_bit} and #{self.base_class.group_col.to_s} = '#{self.group_name}'")
174
+ end
175
+ end
176
+
177
+ def previous_items(options = {})
178
+ if self.base_class.group_col.nil?
179
+ self.base_class.find_by_sql("SELECT * from #{self.base_class.table_name} where #{self.base_class.order_bit_name} #{options[:include_self] == true ? '<=' : '<'} #{self.order_bit}")
180
+ else
181
+ self.base_class.find_by_sql("SELECT * from #{self.base_class.table_name} where #{self.base_class.order_bit_name} #{options[:include_self] == true ? '<=' : '<'} #{self.order_bit} and #{self.base_class.group_col.to_s} = '#{self.group_name}'")
182
+ end
183
+ end
184
+
185
+ def class_name_sha
186
+ Digest::SHA1(self.class.name)
187
+ end
188
+
189
+ end
190
+
191
+ class Engine < Rails::Engine
192
+ end
193
+
194
+ SmartList::Engine.routes.draw do
195
+ get "/smart_list/move_up/:type/:id", :controller => "smart_list", :action => "move_up"
196
+ get "/smart_list/move_down/:type/:id", :controller => "smart_list", :action => "move_down"
197
+ end
198
+
199
+
200
+ end
201
+
202
+ ActiveRecord::Base.send(:include, SmartList)
203
+ ActionController::Base.helper SmartListHelper
204
+
metadata ADDED
@@ -0,0 +1,47 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: smart_list
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Florian Eck
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-11 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Easy to use list behavior for ActiveRecord models, includes grouping
15
+ of items by column content, order, reorder and helpers for ActionView
16
+ email: it-support@friends-systems.de
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - lib/smart_list.rb
22
+ - lib/add_order_bit.rb
23
+ homepage: https://github.com/florianeck/smart_list
24
+ licenses: []
25
+ post_install_message:
26
+ rdoc_options: []
27
+ require_paths:
28
+ - lib
29
+ required_ruby_version: !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ! '>='
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ required_rubygems_version: !ruby/object:Gem::Requirement
36
+ none: false
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ requirements: []
42
+ rubyforge_project:
43
+ rubygems_version: 1.8.25
44
+ signing_key:
45
+ specification_version: 3
46
+ summary: List-style behavior for ActiveRecordt
47
+ test_files: []