Module: Og::Orderable

Defined in:
lib/og/mixin/orderable.rb

Overview

Attach list/ordering methods to the enchanted class.

Class Method Summary collapse

Class Method Details

.append_dynamic_features(base, options) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/og/mixin/orderable.rb', line 9

def self.append_dynamic_features(base, options)
	o = { 
		:position => 'position', 
		:type => Fixnum, 
	}
	o.update(options) if options

	if o[:scope].is_a?(Symbol) && o[:scope].to_s !~ /_oid$/		
		o[:scope] = "#{o[:scope]}_oid".intern 
	end

	position = o[:position]
	scope = o[:scope]

	if scope
		if scope.is_a?(Symbol)
			scope = %{(#{scope} ? "#{scope} = \#{@#{scope}}" : "#{scope} IS NULL")}
		end
	
		cond = 'condition => ' + scope
		cond_and = ':condition => ' + scope + ' + " AND " +'
	else
		cond = ':condition => nil'
		cond_and = ':condition => '
	end		

	code = %{		
		property :#{position}, #{o[:type]}

		pre "add_to_bottom", :on => :og_insert	
		pre "decrement_position_of_lower_items", :on => :og_delete
		
		def move_higher
			if higher = higher_item
				#{base}.transaction do
					higher.increment_position
					decrement_position
				end
			end
		end

		def move_lower
			if lower = lower_item
				#{base}.transaction do
					lower.decrement_position
					increment_position
				end
			end
		end

		def move_to_top
			#{base}.transaction do
				increment_position_of_higher_items
				set_top_position
			end
		end

		def move_to_bottom
			#{base}.transaction do
				decrement_position_of_lower_items
				set_bottom_position
			end											
		end

		def move_to
		end

		def add_to_top
			increment_position_of_all_items
		end

		def add_to_bottom
			@#{position} = bottom_position + 1
		end

		def add_to
		end

		def higher_item
			#{base}.one(#{cond_and}"#{position}=\#\{@#{position} - 1\}")
		end
		alias_method :previous_item, :higher_item

		def lower_item
			#{base}.one(#{cond_and}"#{position}=\#\{@#{position} + 1\}")
		end
		alias_method :next_item, :lower_item

		def top_item
		end
		alias_method :first_item, :top_item

		def bottom_item
			#{base}.one(#{cond}, :order => "#{position} DESC", :limit => 1)
		end
		alias_method :last_item, :last_item

		def top?
			@#{position} == 1
		end
		alias_method :first?, :top?

		def bottom?
			@#{position} == bottom_position
		end
		alias_method :last?, :bottom?

		def increment_position
			@#{position} += 1
			update(:#{position})
		end
	
		def decrement_position
			@#{position} -= 1
			update(:#{position})
		end

		def bottom_position
			item = bottom_item
			item ? item.#{position} : 0
		end

		def set_top_position
			@#{position} = 1
			update(:#{position})
		end

		def set_bottom_position
			@#{position} = bottom_position + 1
			update(:#{position})
		end

		def increment_position_of_higher_items
			#{base}.update_property("#{position}=(#{position} + 1)", #{cond_and}"#{position} < \#\{@#{position}\}")
		end

		def increment_position_of_all_items
			#{base}.update_property("#{position}=(#{position} + 1)", #{cond})
		end
		
		def decrement_position_of_lower_items
			#{base}.update_property("#{position}=(#{position} - 1)", #{cond_and}"#{position} > \#\{@#{position}\}")
		end
	}		
	
	base.module_eval(code)
end