From 1da155b15befe9b16cf7b05973072c5f8729017e Mon Sep 17 00:00:00 2001 From: Uchio Kondo Date: Mon, 21 Nov 2011 20:14:03 +0900 Subject: [PATCH] make it to work well with Sinatra/Padrino, thanks to #161 & #174 --- kaminari.gemspec | 7 +- lib/kaminari.rb | 54 ++++++++++- lib/kaminari/helpers/paginator.rb | 5 +- lib/kaminari/helpers/sinatra_helper.rb | 126 +++++++++++++++++++++++++ lib/kaminari/hooks.rb | 37 ++++++++ lib/kaminari/models/array_extension.rb | 1 + lib/kaminari/railtie.rb | 44 +-------- lib/kaminari/sinatra.rb | 8 ++ 8 files changed, 235 insertions(+), 47 deletions(-) create mode 100644 lib/kaminari/helpers/sinatra_helper.rb create mode 100644 lib/kaminari/hooks.rb create mode 100644 lib/kaminari/sinatra.rb diff --git a/kaminari.gemspec b/kaminari.gemspec index 98e6366..3236be7 100644 --- a/kaminari.gemspec +++ b/kaminari.gemspec @@ -21,9 +21,14 @@ Gem::Specification.new do |s| s.licenses = ['MIT'] - s.add_dependency 'railties', ['>= 3.0.0'] + %w{ activesupport actionpack railties }.each do |gem| + s.add_dependency gem, ['>= 3.0.0'] + end s.add_development_dependency 'bundler', ['>= 1.0.0'] s.add_development_dependency 'sqlite3', ['>= 0'] + %w{ activerecord activemodel }.each do |gem| + s.add_development_dependency gem, ['>= 3.0.0'] + end s.add_development_dependency 'mongoid', ['>= 2'] s.add_development_dependency 'mongo_mapper', ['>= 0.9'] s.add_development_dependency 'dm-core', ['>= 1.1.0'] diff --git a/lib/kaminari.rb b/lib/kaminari.rb index 727b227..82bcedb 100644 --- a/lib/kaminari.rb +++ b/lib/kaminari.rb @@ -1,2 +1,52 @@ -require 'kaminari/railtie' -require 'kaminari/engine' +module Kaminari + + def self.frameworks + frameworks = [] + case + when defined?(::Rails) then frameworks << 'rails' + when defined?(::Sinatra) then frameworks << 'sinatra/base' + end + frameworks + end + + def self.load_framework! + raise "No framework specified!" if frameworks.empty? + frameworks.each do |framework| + begin + require framework + rescue NameError => e + raise "can\'t load framework #{framework.inspect}. Have you added it to Gemfile?" + end + end + end + + + def self.load_kaminari! + require 'kaminari/config' + require 'kaminari/helpers/action_view_extension' + require 'kaminari/helpers/paginator' + require 'kaminari/models/page_scope_methods' + require 'kaminari/models/configuration_methods' + end + + def self.hook! + load_framework! + load_kaminari! + require 'kaminari/hooks' + if defined?(::Rails) + require 'kaminari/railtie' + require 'kaminari/engine' + elsif defined?(::Sinatra) + require 'kaminari/sinatra' + else + Kaminari::Hooks.init! + end + end + + def self.load! + hook! + end + +end + +Kaminari.load! diff --git a/lib/kaminari/helpers/paginator.rb b/lib/kaminari/helpers/paginator.rb index dc8a912..5232b3c 100644 --- a/lib/kaminari/helpers/paginator.rb +++ b/lib/kaminari/helpers/paginator.rb @@ -1,5 +1,8 @@ -require 'kaminari/helpers/tags' +require 'active_support/inflector' +require 'action_view' +require 'action_view/log_subscriber' require 'action_view/context' +require 'kaminari/helpers/tags' module Kaminari module Helpers diff --git a/lib/kaminari/helpers/sinatra_helper.rb b/lib/kaminari/helpers/sinatra_helper.rb new file mode 100644 index 0000000..a36d951 --- /dev/null +++ b/lib/kaminari/helpers/sinatra_helper.rb @@ -0,0 +1,126 @@ +require 'active_support/core_ext/object' +require 'active_support/core_ext/string' + +begin + +require 'padrino-helpers' +module Kaminari::Helpers + module SinatraHelper + class << self + def registered(app) + app.register Padrino::Helpers + app.helpers HelperMethods + end + + alias included registered + end + + class ActionViewTemplateProxy + def initialize(opts={}) + @current_path = opts[:current_path] + @param_name = (opts[:param_name] || :page).to_sym + @current_params = opts[:current_params] + @current_params.delete(@param_name) + end + + def render(*args) + base = ActionView::Base.new.tap do |a| + a.view_paths << File.expand_path('../../../../app/views', __FILE__) + end + base.render(*args) + end + + def url_for(params) + extra_params = {} + if page = params[@param_name] and page != 1 + extra_params[@param_name] = page + end + query = @current_params.merge(extra_params) + @current_path + (query.empty? ? '' : "?#{query.to_query}") + end + + def params + @current_params + end + end + + module HelperMethods + # A quick backport from Rails' link_to_unless helper + def link_to_unless(condition, *args, &blk) + unless condition + link_to *args + else + block_given? ? blk.call : nil + end + end + + # A helper that renders the pagination links - for Sinatra. + # + # <%= paginate @articles %> + # + # ==== Options + # * :window - The "inner window" size (4 by default). + # * :outer_window - The "outer window" size (0 by default). + # * :left - The "left outer window" size (0 by default). + # * :right - The "right outer window" size (0 by default). + # * :params - url_for parameters for the links (:controller, :action, etc.) + # * :param_name - parameter name for page number in the links (:page by default) + # * :remote - Ajax? (false by default) + # * :ANY_OTHER_VALUES - Any other hash key & values would be directly passed into each tag as :locals value. + def paginate(scope, options = {}, &block) + current_path = env['PATH_INFO'] rescue nil + current_params = Rack::Utils.parse_query(env['QUERY_STRING']).symbolize_keys rescue {} + paginator = Kaminari::Helpers::Paginator.new( + ActionViewTemplateProxy.new(:current_params => current_params, :current_path => current_path, :param_name => options[:param_name] || Kaminari.config.param_name), + options.reverse_merge(:current_page => scope.current_page, :num_pages => scope.num_pages, :per_page => scope.limit_value, :param_name => Kaminari.config.param_name, :remote => false) + ) + paginator.to_s + end + + # A simple "Twitter like" pagination link that creates a link to the next page. + # Works on Sinatra. + # + # ==== Examples + # Basic usage: + # + # <%= link_to_next_page @items, 'Next Page' %> + # + # Ajax: + # + # <%= link_to_next_page @items, 'Next Page', :remote => true %> + # + # By default, it renders nothing if there are no more results on the next page. + # You can customize this output by passing a block. + # + # <%= link_to_next_page @users, 'Next Page' do %> + # No More Pages + # <% end %> + def link_to_next_page(scope, name, options = {}, &block) + params = options.delete(:params) || (Rack::Utils.parse_query(env['QUERY_STRING']).symbolize_keys rescue {}) + param_name = options.delete(:param_name) || Kaminari.config.param_name + query = params.merge(param_name => (scope.current_page + 1)) + link_to_unless scope.last_page?, name, env['PATH_INFO'] + (query.empty? ? '' : "?#{query.to_query}"), options.merge(:rel => 'next') do + block.call; nil if block + end + end + end + end +end + +if defined? I18n + I18n.load_path += Dir.glob(File.expand_path('../../../../config/locales/*.yml', __FILE__)) +end + +rescue LoadError + +$stderr.puts "[!]You shold install `padrino-helpers' gem if you want to use kaminari's pagination helpers with Sinatra." +$stderr.puts "[!]Kaminari::Helpers::SinatraHelper does nothing now..." + +module Kaminari::Helpers + module SinatraHelper + def self.registered(*) + end + end +end + +end diff --git a/lib/kaminari/hooks.rb b/lib/kaminari/hooks.rb new file mode 100644 index 0000000..2a1a1f4 --- /dev/null +++ b/lib/kaminari/hooks.rb @@ -0,0 +1,37 @@ +module Kaminari + class Hooks + def self.init! + ActiveSupport.on_load(:active_record) do + require 'kaminari/models/active_record_extension' + ::ActiveRecord::Base.send :include, Kaminari::ActiveRecordExtension + end + + if defined? ::Mongoid + require 'kaminari/models/mongoid_extension' + ::Mongoid::Document.send :include, Kaminari::MongoidExtension::Document + ::Mongoid::Criteria.send :include, Kaminari::MongoidExtension::Criteria + end + + ActiveSupport.on_load(:mongo_mapper) do + require 'kaminari/models/mongo_mapper_extension' + ::MongoMapper::Document.send :include, Kaminari::MongoMapperExtension::Document + ::Plucky::Query.send :include, Kaminari::PluckyCriteriaMethods + ::Plucky::Query.send :include, Kaminari::PageScopeMethods + end + + if defined? ::DataMapper + require 'kaminari/models/data_mapper_extension' + ::DataMapper::Collection.send :include, Kaminari::DataMapperExtension::Collection + ::DataMapper::Model.append_extensions Kaminari::DataMapperExtension::Model + # ::DataMapper::Model.send :extend, Kaminari::DataMapperExtension::Model + end + require 'kaminari/models/array_extension' + + require File.join(File.dirname(__FILE__), 'models/array_extension') + + ActiveSupport.on_load(:action_view) do + ::ActionView::Base.send :include, Kaminari::ActionViewExtension + end + end + end +end diff --git a/lib/kaminari/models/array_extension.rb b/lib/kaminari/models/array_extension.rb index 58f3d20..5454da0 100644 --- a/lib/kaminari/models/array_extension.rb +++ b/lib/kaminari/models/array_extension.rb @@ -1,3 +1,4 @@ +require 'active_support/core_ext/module' module Kaminari # Kind of Array that can paginate class PaginatableArray < Array diff --git a/lib/kaminari/railtie.rb b/lib/kaminari/railtie.rb index 240ab90..a5d908a 100644 --- a/lib/kaminari/railtie.rb +++ b/lib/kaminari/railtie.rb @@ -1,49 +1,7 @@ -require 'rails' -# ensure ORMs are loaded *before* initializing Kaminari -begin; require 'mongoid'; rescue LoadError; end -begin; require 'mongo_mapper'; rescue LoadError; end -begin; require 'dm-core'; require 'dm-aggregates'; rescue LoadError; end - -require 'kaminari/config' -require 'kaminari/helpers/action_view_extension' -require 'kaminari/helpers/paginator' -require 'kaminari/models/page_scope_methods' -require 'kaminari/models/configuration_methods' - module Kaminari class Railtie < ::Rails::Railtie #:nodoc: initializer 'kaminari' do |app| - ActiveSupport.on_load(:active_record) do - require 'kaminari/models/active_record_extension' - ::ActiveRecord::Base.send :include, Kaminari::ActiveRecordExtension - end - - if defined? ::Mongoid - require 'kaminari/models/mongoid_extension' - ::Mongoid::Document.send :include, Kaminari::MongoidExtension::Document - ::Mongoid::Criteria.send :include, Kaminari::MongoidExtension::Criteria - end - - ActiveSupport.on_load(:mongo_mapper) do - require 'kaminari/models/mongo_mapper_extension' - ::MongoMapper::Document.send :include, Kaminari::MongoMapperExtension::Document - ::Plucky::Query.send :include, Kaminari::PluckyCriteriaMethods - ::Plucky::Query.send :include, Kaminari::PageScopeMethods - end - - if defined? ::DataMapper - require 'kaminari/models/data_mapper_extension' - ::DataMapper::Collection.send :include, Kaminari::DataMapperExtension::Collection - ::DataMapper::Model.append_extensions Kaminari::DataMapperExtension::Model -# ::DataMapper::Model.send :extend, Kaminari::DataMapperExtension::Model - end - require 'kaminari/models/array_extension' - - require File.join(File.dirname(__FILE__), 'models/array_extension') - - ActiveSupport.on_load(:action_view) do - ::ActionView::Base.send :include, Kaminari::ActionViewExtension - end + Kaminari::Hooks.init! end end end diff --git a/lib/kaminari/sinatra.rb b/lib/kaminari/sinatra.rb new file mode 100644 index 0000000..37623f6 --- /dev/null +++ b/lib/kaminari/sinatra.rb @@ -0,0 +1,8 @@ +require 'kaminari' +module Kaminari + module Helpers + autoload :SinatraHelper, 'kaminari/helpers/sinatra_helper' + end +end +Kaminari::Hooks.init! +