is_positionable 0.0.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.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Michael van Rooijen | Meskyanichi
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,18 @@
1
+ = ip
2
+
3
+ Description goes here.
4
+
5
+ == Note on Patches/Pull Requests
6
+
7
+ * Fork the project.
8
+ * Make your feature addition or bug fix.
9
+ * Add tests for it. This is important so I don't break it in a
10
+ future version unintentionally.
11
+ * Commit, do not mess with rakefile, version, or history.
12
+ (if you want to have your own version, that is fine but
13
+ bump version in a commit by itself I can ignore when I pull)
14
+ * Send me a pull request. Bonus points for topic branches.
15
+
16
+ == Copyright
17
+
18
+ Copyright (c) 2009 meskyanichi. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,61 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "is_positionable"
8
+ gem.summary = %Q{Handles positioning (ordering) your ActiveRecord Objects.}
9
+ gem.description = %Q{
10
+ Handles positioning (ordering) your ActiveRecord Objects.
11
+ Makes use of the "Acts As List" plugin for the optimized background handling of the positioning.
12
+ "Is Positionable" is a front-end that dynamically generates buttons for moving ActiveRecord Objects
13
+ "up", "down", to the "top" and to the "bottom". Setting it up takes just 1 word: "is_positionable".
14
+ }
15
+ gem.email = "meskyan@gmail.com"
16
+ gem.homepage = "http://github.com/meskyanichi/is_positionable"
17
+ gem.authors = ["meskyanichi"]
18
+ gem.add_dependency "acts_as_list"
19
+ # gem.files.include 'lib/**/*'
20
+ end
21
+ rescue LoadError
22
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
23
+ end
24
+
25
+ require 'rake/testtask'
26
+ Rake::TestTask.new(:test) do |test|
27
+ test.libs << 'lib' << 'test'
28
+ test.pattern = 'test/**/*_test.rb'
29
+ test.verbose = true
30
+ end
31
+
32
+ begin
33
+ require 'rcov/rcovtask'
34
+ Rcov::RcovTask.new do |test|
35
+ test.libs << 'test'
36
+ test.pattern = 'test/**/*_test.rb'
37
+ test.verbose = true
38
+ end
39
+ rescue LoadError
40
+ task :rcov do
41
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
42
+ end
43
+ end
44
+
45
+ task :test => :check_dependencies
46
+
47
+ task :default => :test
48
+
49
+ require 'rake/rdoctask'
50
+ Rake::RDocTask.new do |rdoc|
51
+ if File.exist?('VERSION')
52
+ version = File.read('VERSION')
53
+ else
54
+ version = ""
55
+ end
56
+
57
+ rdoc.rdoc_dir = 'rdoc'
58
+ rdoc.title = "ip #{version}"
59
+ rdoc.rdoc_files.include('README*')
60
+ rdoc.rdoc_files.include('lib/**/*.rb')
61
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__), "lib", "is_positionable")
@@ -0,0 +1,56 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{is_positionable}
8
+ s.version = "0.0.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["meskyanichi"]
12
+ s.date = %q{2009-10-05}
13
+ s.description = %q{
14
+ Handles positioning (ordering) your ActiveRecord Objects.
15
+ Makes use of the "Acts As List" plugin for the optimized background handling of the positioning.
16
+ "Is Positionable" is a front-end that dynamically generates buttons for moving ActiveRecord Objects
17
+ "up", "down", to the "top" and to the "bottom". Setting it up takes just 1 word: "is_positionable".
18
+ }
19
+ s.email = %q{meskyan@gmail.com}
20
+ s.extra_rdoc_files = [
21
+ "LICENSE",
22
+ "README.rdoc"
23
+ ]
24
+ s.files = [
25
+ ".document",
26
+ ".gitignore",
27
+ "LICENSE",
28
+ "README.rdoc",
29
+ "Rakefile",
30
+ "VERSION",
31
+ "init.rb",
32
+ "is_positionable.gemspec",
33
+ "lib/is_positionable.rb",
34
+ "lib/is_positionable/base.rb",
35
+ "lib/is_positionable/errors/no_method_error/acts_as_list.rb",
36
+ "lib/is_positionable/interface.rb"
37
+ ]
38
+ s.homepage = %q{http://github.com/meskyanichi/is_positionable}
39
+ s.rdoc_options = ["--charset=UTF-8"]
40
+ s.require_paths = ["lib"]
41
+ s.rubygems_version = %q{1.3.5}
42
+ s.summary = %q{Handles positioning (ordering) your ActiveRecord Objects.}
43
+
44
+ if s.respond_to? :specification_version then
45
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
46
+ s.specification_version = 3
47
+
48
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
49
+ s.add_runtime_dependency(%q<acts_as_list>, [">= 0"])
50
+ else
51
+ s.add_dependency(%q<acts_as_list>, [">= 0"])
52
+ end
53
+ else
54
+ s.add_dependency(%q<acts_as_list>, [">= 0"])
55
+ end
56
+ end
@@ -0,0 +1,11 @@
1
+ module IsPositionable
2
+ class Base
3
+
4
+ attr_accessor :options
5
+
6
+ def initialize(options = {})
7
+ self.options = options
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,24 @@
1
+ module IsPositionable
2
+ module Errors
3
+ module NoMethodError
4
+ class ActsAsList
5
+ def initialize
6
+ raise <<-MSG
7
+ The Acts As List Gem / Plugin has not been installed!
8
+
9
+ To install the gem:
10
+ sudo gem install acts_as_list
11
+
12
+ To install the plugin:
13
+ ./script/plugin install git://github.com/rails/acts_as_list.git
14
+
15
+
16
+ Although this is not "required", I do recommend you (if using the GEM version)
17
+ to add the following line inside of your config/environment.rb file:
18
+ config.gem "acts_as_list"
19
+ MSG
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,117 @@
1
+ module IsPositionable
2
+ class Interface < IsPositionable::Base
3
+
4
+ def initialize(options, controller_name)
5
+ super({
6
+ :column => :position,
7
+ :controller => options[:controller] || controller_name,
8
+ :model => options[:controller] || controller_name,
9
+ :action => :positionable,
10
+ :scope => nil,
11
+ :redirect_to => :back,
12
+ :param => :move,
13
+ :set_default_scope => true
14
+ }.update(options))
15
+ end
16
+
17
+ def build
18
+ self
19
+ end
20
+
21
+ # Finds a single record by id
22
+ # It will determine whether to use a plain find
23
+ # or whether to use a find through an association
24
+ def find(id)
25
+ if scope.nil?
26
+ model.find(id)
27
+ else
28
+ scope.send(model_association_name).find(id)
29
+ end
30
+ end
31
+
32
+ # Finds the last id of a list of records
33
+ # It will determine whether to use a plain find
34
+ # or whether to use a find through an association
35
+ def find_last_id
36
+ if scope.nil?
37
+ model.all.last.id
38
+ else
39
+ scope.send(model_association_name).last.id
40
+ end
41
+ end
42
+
43
+ # Returns the value of the :redirect_to attribute
44
+ def redirect
45
+ options[:redirect_to]
46
+ end
47
+
48
+ # Returns the value of the :scope attribute
49
+ def scope
50
+ options[:scope]
51
+ end
52
+
53
+ # Returns the model Class which can be invoked using class methods
54
+ def model
55
+ Kernel.const_get(options[:model].singularize.camelize)
56
+ end
57
+
58
+ # Returns the controller Class which can be invoked using class methods
59
+ def controller
60
+ Kernel.const_get("#{controller_name.camelize.pluralize}Controller")
61
+ end
62
+
63
+ # Returns the action name of the :action attribute
64
+ def action_name
65
+ options[:action]
66
+ end
67
+
68
+ # Returns the model name of the :model attribute
69
+ # The value will be singularize'd and camelize'd to
70
+ # return the exact name as it is written inside a Ruby file
71
+ def model_name
72
+ options[:model].singularize.camelize
73
+ end
74
+
75
+ # Returns the model name in the form of an association
76
+ # This is the model name, pluralize'd and underscore'd
77
+ def model_association_name
78
+ options[:model].pluralize.underscore
79
+ end
80
+
81
+ # Returns the controller name of the :controller attribute
82
+ def controller_name
83
+ options[:controller]
84
+ end
85
+
86
+ # Returns the param of the :param attribute
87
+ def param
88
+ options[:param]
89
+ end
90
+
91
+ # Returns the column of the :column attribute
92
+ def column
93
+ options[:column]
94
+ end
95
+
96
+ # Returns a boolean
97
+ # Determines whether the :set_default_scope attribute was set
98
+ def set_default_scope?
99
+ true if options[:set_default_scope].eql?(true)
100
+ end
101
+
102
+ # Require additional gems
103
+ # When the "ignore_error" argument is set to "true" (default)
104
+ # an error will not be raised if the gem cannot be found
105
+ def require_gem(gem, ignore_error = true)
106
+ if ignore_error.eql?(true)
107
+ begin
108
+ require "#{gem}"
109
+ rescue MissingSourceFile
110
+ end
111
+ else
112
+ require "#{gem}"
113
+ end
114
+ end
115
+
116
+ end
117
+ end
@@ -0,0 +1,231 @@
1
+ require 'is_positionable/base'
2
+ require 'is_positionable/interface'
3
+ require 'is_positionable/errors/no_method_error/acts_as_list'
4
+
5
+ module IsPositionable
6
+
7
+ def self.included(base)
8
+ base.extend(ClassMethods)
9
+ end
10
+
11
+ module ClassMethods
12
+
13
+ # Is Positionable
14
+ def is_positionable(options = {})
15
+
16
+ # Initialize the interface builer class
17
+ # Passes in the options hash and the controller_name and builds the methods for it
18
+ # Interface will convert ugly multi-dot-syntax to a single object.method wrapper
19
+ interface = IsPositionable::Interface.new(options, controller_name).build
20
+
21
+ # ControllerAction
22
+
23
+ # Requires the acts_as_list gem
24
+ # Ignores "MissingSourceFile" error so that a "nice" error message can be
25
+ # displayed in the browser.
26
+ interface.require_gem('acts_as_list')
27
+
28
+ # Initializes Acts As List on the model
29
+ # Will set up the column, the same that is used by Is Positionable
30
+ # The Acts As List Gem will be provided with the same scope as the Is Positionable Gem uses
31
+ # The default_scope will be set to always sort the items by the specified column (default = :position)
32
+ interface.model.class_eval do
33
+
34
+ # Initializes the Acts As List gem
35
+ # Sets the :column to the specified column attribute, default => :position
36
+ # Sets the :scope attribute to the specified attribute, default => '1 = 1' (like Acts As List)
37
+ # Will display a helpful error when the Acts As List Gem has either not been installed or loaded
38
+ begin
39
+ acts_as_list :column => interface.column,
40
+ :scope => interface.scope || '1 = 1'
41
+ rescue NoMethodError
42
+ raise IsPositionable::Errors::NoMethodError::ActsAsList.new
43
+ end
44
+
45
+ # Sets the default scope to order by the specified column
46
+ default_scope :order => interface.column if interface.set_default_scope?
47
+
48
+ end
49
+
50
+ # Defines the action which will be used to move objects around
51
+ define_method(interface.action_name) do
52
+
53
+ # Finds the object that will be re-positioned
54
+ object = interface.find(params[:id])
55
+
56
+ # Move Object Up 1 Position
57
+ if params[interface.param].eql?('higher')
58
+ object.move_higher
59
+ end
60
+
61
+ # Move Object Down 1 Position
62
+ if params[interface.param].eql?('lower')
63
+ object.move_lower
64
+ end
65
+
66
+ # Move Object To Top Of List
67
+ if params[interface.param].eql?('to_top')
68
+ object.move_to_top
69
+ end
70
+
71
+ # Move Object To Bottom Of List
72
+ if params[interface.param].eql?('to_bottom')
73
+ object.move_to_bottom
74
+ end
75
+
76
+ # Redirects if this is a simple HTML POST request
77
+ # Will do nothing if this is an AJAX request
78
+ respond_to do |format|
79
+ format.html do
80
+
81
+ # If the redirect path has not been set, it will default to :back.
82
+ # If the default is set, but there is no "Referer", it will by default redirect
83
+ # the user to the index action of the current controller.
84
+ # If the :redirect_to attribute was manually set, this will be used.
85
+ # If the :redirect_to attribute was set to :back, it will not change the default attribute
86
+ if interface.redirect.eql?(:back)
87
+ if request.headers["Referer"]
88
+ redirect_to(interface.redirect)
89
+ else
90
+ redirect_to(:action => :index)
91
+ end
92
+ else
93
+ redirect_to(interface.redirect)
94
+ end
95
+ end
96
+
97
+ # If the positioning action was triggered by a AJAX call
98
+ # then do nothing. Only optionally render the RJS file if present.
99
+ format.js do
100
+ # => Nothing
101
+ end
102
+ end
103
+ end # => define_method(interface.action_name)
104
+
105
+
106
+
107
+ # HelperMethods
108
+
109
+ # Include the ActionView::Helpers inside of ActionController::Base
110
+ # This will enable html button parsing
111
+ ActionController::Base.send(:include, ActionView::Helpers)
112
+
113
+ # Injects the "UP" button for the view helpers into the controller
114
+ # This will be available to all views within the specified controller
115
+ define_method "up_button_for_#{interface.controller_name}" do |object, *options|
116
+
117
+ # Set default options and overwrite the existing ones with
118
+ # possible user input
119
+ options = {
120
+ :name => "up",
121
+ :attribute => :id,
122
+ :url => {
123
+ :controller => interface.controller_name,
124
+ :action => interface.action_name,
125
+ :id => object,
126
+ interface.param => "higher" },
127
+ :html => {
128
+ :id => "up_button_for_#{interface.controller_name.singularize}_#{object.id}",
129
+ :class => "up_button_for_#{interface.controller_name}" }
130
+ }.update(options.empty? ? {} : options.first)
131
+
132
+ button_to(options[:name], options[:url], options[:html]) unless object.first?
133
+ end
134
+
135
+ # Injects the "DOWN" button for the view helpers into the controller
136
+ # This will be available to all views within the specified controller
137
+ define_method "down_button_for_#{interface.controller_name}" do |object, *options|
138
+
139
+ # Set default options and overwrite the existing ones with
140
+ # possible user input
141
+ options = {
142
+ :name => "down",
143
+ :attribute => :id,
144
+ :url => {
145
+ :controller => interface.controller_name,
146
+ :action => interface.action_name,
147
+ :id => object,
148
+ interface.param => "lower" },
149
+ :html => {
150
+ :id => "down_button_for_#{interface.controller_name.singularize}_#{object.id}",
151
+ :class => "down_button_for_#{interface.controller_name}" }
152
+ }.update(options.empty? ? {} : options.first)
153
+
154
+ # Ensures that the last id will only be found once
155
+ # and not for each object that comes through the loop
156
+ unless defined?(@ip_last)
157
+ @ip_last = interface.find_last_id
158
+ end
159
+
160
+ # Ensures that the last "Down" button will not be displayed
161
+ # since you can't go lower than the lowest position
162
+ unless @ip_last.eql?(object.id)
163
+ button_to(options[:name], options[:url], options[:html])
164
+ end
165
+ end
166
+
167
+ # Injects the "TOP" button for the view helpers into the controller
168
+ # This will be available to all views within the specified controller
169
+ define_method "top_button_for_#{interface.controller_name}" do |object, *options|
170
+
171
+ # Set default options and overwrite the existing ones with
172
+ # possible user input
173
+ options = {
174
+ :name => "top",
175
+ :attribute => :id,
176
+ :url => {
177
+ :controller => interface.controller_name,
178
+ :action => interface.action_name,
179
+ :id => object,
180
+ interface.param => "to_top" },
181
+ :html => {
182
+ :id => "top_button_for_#{interface.controller_name.singularize}_#{object.id}",
183
+ :class => "top_button_for_#{interface.controller_name}" }
184
+ }.update(options.empty? ? {} : options.first)
185
+
186
+ button_to(options[:name], options[:url], options[:html]) unless object.first?
187
+ end
188
+
189
+ # Injects the "BOTTOM" button for the view helpers into the controller
190
+ # This will be available to all views within the specified controller
191
+ define_method "bottom_button_for_#{interface.controller_name}" do |object, *options|
192
+
193
+ # Set default options and overwrite the existing ones with
194
+ # possible user input
195
+ options = {
196
+ :name => "bottom",
197
+ :attribute => :id,
198
+ :url => {
199
+ :controller => interface.controller_name,
200
+ :action => interface.action_name,
201
+ :id => object,
202
+ interface.param => "to_bottom" },
203
+ :html => {
204
+ :id => "bottom_button_for_#{interface.controller_name.singularize}_#{object.id}",
205
+ :class => "bottom_button_for_#{interface.controller_name}" }
206
+ }.update(options.empty? ? {} : options.first)
207
+
208
+ # Ensures that the last id will only be found once
209
+ # and not for each object that comes through the loop
210
+ unless defined?(@ip_last)
211
+ @ip_last = interface.find_last_id
212
+ end
213
+
214
+ # Ensures that the last "Down" button will not be displayed
215
+ # since you can't go lower than the lowest position
216
+ unless @ip_last.eql?(object.id)
217
+ button_to(options[:name], options[:url], options[:html])
218
+ end
219
+ end
220
+
221
+ # Makes the buttons available to the views that belong to the
222
+ # controller that Is Positional was invoked from
223
+ helper_method "up_button_for_#{interface.controller_name}",
224
+ "down_button_for_#{interface.controller_name}",
225
+ "top_button_for_#{interface.controller_name}",
226
+ "bottom_button_for_#{interface.controller_name}"
227
+ end
228
+ end
229
+ end
230
+
231
+ ActionController::Base.send(:include, IsPositionable)
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: is_positionable
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - meskyanichi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-05 00:00:00 +02:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: acts_as_list
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description: "\n Handles positioning (ordering) your ActiveRecord Objects.\n Makes use of the \"Acts As List\" plugin for the optimized background handling of the positioning.\n \"Is Positionable\" is a front-end that dynamically generates buttons for moving ActiveRecord Objects\n \"up\", \"down\", to the \"top\" and to the \"bottom\". Setting it up takes just 1 word: \"is_positionable\".\n "
26
+ email: meskyan@gmail.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - LICENSE
33
+ - README.rdoc
34
+ files:
35
+ - .document
36
+ - .gitignore
37
+ - LICENSE
38
+ - README.rdoc
39
+ - Rakefile
40
+ - VERSION
41
+ - init.rb
42
+ - is_positionable.gemspec
43
+ - lib/is_positionable.rb
44
+ - lib/is_positionable/base.rb
45
+ - lib/is_positionable/errors/no_method_error/acts_as_list.rb
46
+ - lib/is_positionable/interface.rb
47
+ has_rdoc: true
48
+ homepage: http://github.com/meskyanichi/is_positionable
49
+ licenses: []
50
+
51
+ post_install_message:
52
+ rdoc_options:
53
+ - --charset=UTF-8
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: "0"
61
+ version:
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: "0"
67
+ version:
68
+ requirements: []
69
+
70
+ rubyforge_project:
71
+ rubygems_version: 1.3.5
72
+ signing_key:
73
+ specification_version: 3
74
+ summary: Handles positioning (ordering) your ActiveRecord Objects.
75
+ test_files: []
76
+