bootstrap_pager 0.9.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.
Files changed (109) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +18 -0
  3. data/.idea/encodings.xml +5 -0
  4. data/.idea/misc.xml +5 -0
  5. data/.idea/modules.xml +9 -0
  6. data/.idea/pager.iml +50 -0
  7. data/.idea/scopes/scope_settings.xml +5 -0
  8. data/.idea/vcs.xml +7 -0
  9. data/Gemfile +4 -0
  10. data/LICENSE +20 -0
  11. data/MIT-LICENSE +20 -0
  12. data/README.rdoc +307 -0
  13. data/Rakefile +42 -0
  14. data/app/assets/javascripts/infinitescroll.js +8 -0
  15. data/app/helpers/pager_helper.rb +5 -0
  16. data/app/views/pager/_first_page.html.erb +11 -0
  17. data/app/views/pager/_first_page.html.haml +9 -0
  18. data/app/views/pager/_first_page.html.slim +10 -0
  19. data/app/views/pager/_gap.html.erb +8 -0
  20. data/app/views/pager/_gap.html.haml +8 -0
  21. data/app/views/pager/_gap.html.slim +10 -0
  22. data/app/views/pager/_last_page.html.erb +11 -0
  23. data/app/views/pager/_last_page.html.haml +9 -0
  24. data/app/views/pager/_last_page.html.slim +10 -0
  25. data/app/views/pager/_next_page.html.erb +11 -0
  26. data/app/views/pager/_next_page.html.haml +9 -0
  27. data/app/views/pager/_next_page.html.slim +10 -0
  28. data/app/views/pager/_page.html.erb +14 -0
  29. data/app/views/pager/_page.html.haml +11 -0
  30. data/app/views/pager/_page.html.slim +13 -0
  31. data/app/views/pager/_paginator.html.erb +25 -0
  32. data/app/views/pager/_paginator.html.haml +19 -0
  33. data/app/views/pager/_paginator.html.slim +20 -0
  34. data/app/views/pager/_prev_page.html.erb +11 -0
  35. data/app/views/pager/_prev_page.html.haml +9 -0
  36. data/app/views/pager/_prev_page.html.slim +10 -0
  37. data/bootstrap_pager.gemspec +36 -0
  38. data/config/locales/pager.yml +19 -0
  39. data/gemfiles/active_record_30.gemfile +9 -0
  40. data/gemfiles/active_record_31.gemfile +7 -0
  41. data/gemfiles/active_record_32.gemfile +10 -0
  42. data/gemfiles/active_record_40.gemfile +8 -0
  43. data/gemfiles/active_record_edge.gemfile +11 -0
  44. data/gemfiles/data_mapper_12.gemfile +15 -0
  45. data/gemfiles/mongo_mapper.gemfile +10 -0
  46. data/gemfiles/mongoid_24.gemfile +7 -0
  47. data/gemfiles/mongoid_30.gemfile +12 -0
  48. data/gemfiles/sinatra_13.gemfile +13 -0
  49. data/gemfiles/sinatra_14.gemfile +13 -0
  50. data/lib/bootstrap_pager/config.rb +51 -0
  51. data/lib/bootstrap_pager/grape.rb +4 -0
  52. data/lib/bootstrap_pager/helpers/action_view_extension.rb +152 -0
  53. data/lib/bootstrap_pager/helpers/paginator.rb +186 -0
  54. data/lib/bootstrap_pager/helpers/sinatra_helpers.rb +144 -0
  55. data/lib/bootstrap_pager/helpers/tags.rb +96 -0
  56. data/lib/bootstrap_pager/hooks.rb +41 -0
  57. data/lib/bootstrap_pager/models/active_record_extension.rb +22 -0
  58. data/lib/bootstrap_pager/models/active_record_model_extension.rb +20 -0
  59. data/lib/bootstrap_pager/models/active_record_relation_methods.rb +29 -0
  60. data/lib/bootstrap_pager/models/array_extension.rb +58 -0
  61. data/lib/bootstrap_pager/models/configuration_methods.rb +48 -0
  62. data/lib/bootstrap_pager/models/data_mapper_collection_methods.rb +15 -0
  63. data/lib/bootstrap_pager/models/data_mapper_extension.rb +48 -0
  64. data/lib/bootstrap_pager/models/mongo_mapper_extension.rb +18 -0
  65. data/lib/bootstrap_pager/models/mongoid_criteria_methods.rb +23 -0
  66. data/lib/bootstrap_pager/models/mongoid_extension.rb +33 -0
  67. data/lib/bootstrap_pager/models/page_scope_methods.rb +70 -0
  68. data/lib/bootstrap_pager/models/plucky_criteria_methods.rb +18 -0
  69. data/lib/bootstrap_pager/railtie.rb +7 -0
  70. data/lib/bootstrap_pager/sinatra.rb +5 -0
  71. data/lib/bootstrap_pager/version.rb +3 -0
  72. data/lib/bootstrap_pager.rb +38 -0
  73. data/lib/generators/pager/config_generator.rb +16 -0
  74. data/lib/generators/pager/templates/pager_config.rb +10 -0
  75. data/lib/generators/pager/views_generator.rb +118 -0
  76. data/spec/config/config_spec.rb +91 -0
  77. data/spec/fake_app/active_record/config.rb +3 -0
  78. data/spec/fake_app/active_record/models.rb +57 -0
  79. data/spec/fake_app/data_mapper/config.rb +7 -0
  80. data/spec/fake_app/data_mapper/models.rb +27 -0
  81. data/spec/fake_app/log/development.log +832 -0
  82. data/spec/fake_app/mongo_mapper/config.rb +2 -0
  83. data/spec/fake_app/mongo_mapper/models.rb +9 -0
  84. data/spec/fake_app/mongoid/config.rb +16 -0
  85. data/spec/fake_app/mongoid/models.rb +22 -0
  86. data/spec/fake_app/rails_app.rb +67 -0
  87. data/spec/fake_app/sinatra_app.rb +22 -0
  88. data/spec/fake_gem.rb +4 -0
  89. data/spec/helpers/action_view_extension_spec.rb +292 -0
  90. data/spec/helpers/helpers_spec.rb +135 -0
  91. data/spec/helpers/sinatra_helpers_spec.rb +170 -0
  92. data/spec/helpers/tags_spec.rb +140 -0
  93. data/spec/models/active_record/active_record_relation_methods_spec.rb +47 -0
  94. data/spec/models/active_record/default_per_page_spec.rb +32 -0
  95. data/spec/models/active_record/max_pages_spec.rb +23 -0
  96. data/spec/models/active_record/max_per_page_spec.rb +32 -0
  97. data/spec/models/active_record/scopes_spec.rb +242 -0
  98. data/spec/models/array_spec.rb +150 -0
  99. data/spec/models/data_mapper/data_mapper_spec.rb +207 -0
  100. data/spec/models/mongo_mapper/mongo_mapper_spec.rb +84 -0
  101. data/spec/models/mongoid/mongoid_spec.rb +126 -0
  102. data/spec/requests/users_spec.rb +53 -0
  103. data/spec/spec_helper.rb +33 -0
  104. data/spec/spec_helper_for_sinatra.rb +34 -0
  105. data/spec/support/database_cleaner.rb +16 -0
  106. data/spec/support/matchers.rb +52 -0
  107. data/vendor/assets/javascripts/jquery.infinitescroll.js +814 -0
  108. data/vendor/assets/javascripts/jquery.infinitescroll.min.js +1 -0
  109. metadata +311 -0
@@ -0,0 +1,48 @@
1
+ require 'bootstrap_pager/models/data_mapper_collection_methods'
2
+
3
+ module BootstrapPager
4
+ module DataMapperExtension
5
+ module Paginatable
6
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
7
+ def #{BootstrapPager.config.page_method_name}(num = 1)
8
+ num = [num.to_i, 1].max - 1
9
+ all(:limit => default_per_page, :offset => default_per_page * num).extend Paginating
10
+ end
11
+ RUBY
12
+ end
13
+
14
+ module Paginating
15
+ include BootstrapPager::PageScopeMethods
16
+
17
+ def all(options={})
18
+ super.extend Paginating
19
+ end
20
+
21
+ def per(num)
22
+ super.extend Paginating
23
+ end
24
+ end
25
+
26
+ module Collection
27
+ extend ActiveSupport::Concern
28
+ included do
29
+ include BootstrapPager::ConfigurationMethods::ClassMethods
30
+ include BootstrapPager::DataMapperCollectionMethods
31
+ include Paginatable
32
+ end
33
+ end
34
+
35
+ module Model
36
+ include BootstrapPager::ConfigurationMethods::ClassMethods
37
+ include Paginatable
38
+
39
+ def limit(val)
40
+ all(:limit => val)
41
+ end
42
+
43
+ def offset(val)
44
+ all(:offset => val)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,18 @@
1
+ require 'bootstrap_pager/models/plucky_criteria_methods'
2
+
3
+ module BootstrapPager
4
+ module MongoMapperExtension
5
+ module Document
6
+ extend ActiveSupport::Concern
7
+ include BootstrapPager::ConfigurationMethods
8
+
9
+ included do
10
+ # Fetch the values at the specified page number
11
+ # Model.page(5)
12
+ scope BootstrapPager.config.page_method_name, Proc.new {|num|
13
+ limit(default_per_page).offset(default_per_page * ([num.to_i, 1].max - 1))
14
+ }
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,23 @@
1
+ module BootstrapPager
2
+ module MongoidCriteriaMethods
3
+ def limit_value #:nodoc:
4
+ options[:limit]
5
+ end
6
+
7
+ def offset_value #:nodoc:
8
+ options[:skip]
9
+ end
10
+
11
+ def total_count #:nodoc:
12
+ embedded? ? unpage.count : count
13
+ end
14
+
15
+ private
16
+ def unpage
17
+ clone.tap do |crit|
18
+ crit.options.delete :limit
19
+ crit.options.delete :skip
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,33 @@
1
+ require 'bootstrap_pager/models/mongoid_criteria_methods'
2
+
3
+ module BootstrapPager
4
+ module MongoidExtension
5
+ module Criteria
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
10
+ def #{BootstrapPager.config.page_method_name}(*args)
11
+ super(*args).criteria.merge(self)
12
+ end
13
+ RUBY
14
+ end
15
+ end
16
+
17
+ module Document
18
+ extend ActiveSupport::Concern
19
+ include BootstrapPager::ConfigurationMethods
20
+
21
+ included do
22
+ # Fetch the values at the specified page number
23
+ # Model.page(5)
24
+ scope BootstrapPager.config.page_method_name, Proc.new {|num|
25
+ limit(default_per_page).offset(default_per_page * ([num.to_i, 1].max - 1))
26
+ } do
27
+ include BootstrapPager::MongoidCriteriaMethods
28
+ include BootstrapPager::PageScopeMethods
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,70 @@
1
+ module BootstrapPager
2
+ module PageScopeMethods
3
+ # Specify the <tt>per_page</tt> value for the preceding <tt>page</tt> scope
4
+ # Model.page(3).per(10)
5
+ def per(num)
6
+ if (n = num.to_i) <= 0
7
+ self
8
+ elsif max_per_page && max_per_page < n
9
+ limit(max_per_page).offset(offset_value / limit_value * max_per_page)
10
+ else
11
+ limit(n).offset(offset_value / limit_value * n)
12
+ end
13
+ end
14
+
15
+ def padding(num)
16
+ @_padding = num
17
+ offset(offset_value + num.to_i)
18
+ end
19
+
20
+ # Total number of pages
21
+ def total_pages
22
+ count_without_padding = total_count
23
+ count_without_padding -= @_padding if defined?(@_padding) && @_padding
24
+ count_without_padding = 0 if count_without_padding < 0
25
+
26
+ total_pages_count = (count_without_padding.to_f / limit_value).ceil
27
+ if max_pages.present? && max_pages < total_pages_count
28
+ max_pages
29
+ else
30
+ total_pages_count
31
+ end
32
+ end
33
+ #FIXME for compatibility. remove num_pages at some time in the future
34
+ alias num_pages total_pages
35
+
36
+ # Current page number
37
+ def current_page
38
+ offset_without_padding = offset_value
39
+ offset_without_padding -= @_padding if defined?(@_padding) && @_padding
40
+ offset_without_padding = 0 if offset_without_padding < 0
41
+
42
+ (offset_without_padding / limit_value) + 1
43
+ end
44
+
45
+ # Next page number in the collection
46
+ def next_page
47
+ current_page + 1 unless last_page?
48
+ end
49
+
50
+ # Previous page number in the collection
51
+ def prev_page
52
+ current_page - 1 unless first_page?
53
+ end
54
+
55
+ # First page of the collection?
56
+ def first_page?
57
+ current_page == 1
58
+ end
59
+
60
+ # Last page of the collection?
61
+ def last_page?
62
+ current_page >= total_pages
63
+ end
64
+
65
+ # Out of range of the collection?
66
+ def out_of_range?
67
+ current_page > total_pages
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,18 @@
1
+ module BootstrapPager
2
+ module PluckyCriteriaMethods
3
+ include BootstrapPager::PageScopeMethods
4
+ include BootstrapPager::ConfigurationMethods::ClassMethods
5
+
6
+ def limit_value #:nodoc:
7
+ options[:limit]
8
+ end
9
+
10
+ def offset_value #:nodoc:
11
+ options[:skip]
12
+ end
13
+
14
+ def total_count #:nodoc:
15
+ count
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,7 @@
1
+ module BootstrapPager
2
+ class Railtie < ::Rails::Railtie #:nodoc:
3
+ initializer 'bootstrap_pager' do |_app|
4
+ BootstrapPager::Hooks.init
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ require 'sinatra/base'
2
+ require 'bootstrap_pager'
3
+ require 'bootstrap_pager/helpers/sinatra_helpers'
4
+
5
+ BootstrapPager::Hooks.init
@@ -0,0 +1,3 @@
1
+ module BootstrapPager
2
+ VERSION = '0.9.0'
3
+ end
@@ -0,0 +1,38 @@
1
+ module BootstrapPager
2
+ end
3
+
4
+ # load Rails/Railtie
5
+ begin
6
+ require 'rails'
7
+ rescue LoadError
8
+ #do nothing
9
+ end
10
+
11
+ $stderr.puts <<-EOC if !defined?(Rails) && !defined?(Sinatra) && !defined?(Grape)
12
+ warning: no framework detected.
13
+
14
+ Your Gemfile might not be configured properly.
15
+ ---- e.g. ----
16
+ Rails:
17
+ gem 'bootstrap_pager'
18
+
19
+ Sinatra/Padrino:
20
+ gem 'bootstrap_pager', :require => 'bootstrap_pager/sinatra'
21
+
22
+ Grape:
23
+ gem 'bootstrap_pager', :require => 'bootstrap_pager/grape'
24
+
25
+ EOC
26
+
27
+ # load BootstrapPager components
28
+ require 'bootstrap_pager/config'
29
+ require 'bootstrap_pager/helpers/paginator'
30
+ require 'bootstrap_pager/models/page_scope_methods'
31
+ require 'bootstrap_pager/models/configuration_methods'
32
+ require 'bootstrap_pager/hooks'
33
+
34
+ # if not using Railtie, call `BootstrapPager::Hooks.init` directly
35
+ if defined? Rails
36
+ require 'bootstrap_pager/railtie'
37
+ require 'bootstrap_pager/engine'
38
+ end
@@ -0,0 +1,16 @@
1
+ module BootstrapPager
2
+ module Generators
3
+ class ConfigGenerator < Rails::Generators::Base
4
+ source_root File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
5
+
6
+ desc <<DESC
7
+ Description:
8
+ Copies BootstrapPager configuration file to your application's initializer directory.
9
+ DESC
10
+
11
+ def copy_config_file
12
+ template 'bootstrap_pager_config.rb', 'config/initializers/bootstrap_pager_config.rb'
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,10 @@
1
+ BootstrapPager.configure do |config|
2
+ # config.default_per_page = 25
3
+ # config.max_per_page = nil
4
+ # config.window = 4
5
+ # config.outer_window = 0
6
+ # config.left = 0
7
+ # config.right = 0
8
+ # config.page_method_name = :page
9
+ # config.param_name = :page
10
+ end
@@ -0,0 +1,118 @@
1
+ module BootstrapPager
2
+ module Generators
3
+
4
+ class ViewsGenerator < Rails::Generators::NamedBase
5
+ source_root File.expand_path('../../../../app/views/bootstrap_pager', __FILE__)
6
+
7
+ class_option :template_engine, :type => :string, :aliases => '-e', :desc => 'Template engine for the views. Available options are "erb", "haml", and "slim".'
8
+
9
+ def self.banner #:nodoc:
10
+ <<-BANNER.chomp
11
+ rails g bootstrap_pager:views THEME [options]
12
+
13
+ Copies all paginator partial templates to your application.
14
+ You can choose a template THEME by specifying one from the list below:
15
+
16
+ - default
17
+ The default one.
18
+ This one is used internally while you don't override the partials.
19
+ #{themes.map {|t| " - #{t.name}\n#{t.description}"}.join("\n")}
20
+ BANNER
21
+ end
22
+
23
+ desc ''
24
+ def copy_or_fetch #:nodoc:
25
+ return copy_default_views if file_name == 'default'
26
+
27
+ themes = self.class.themes
28
+ if theme = themes.detect {|t| t.name == file_name}
29
+ download_templates theme
30
+ else
31
+ say %Q[no such theme: #{file_name}\n avaliable themes: #{themes.map(&:name).join ", "}]
32
+ end
33
+ end
34
+
35
+ private
36
+ def self.themes
37
+ begin
38
+ @themes ||= GitHubApiHelper.get_files_in_master.group_by {|fn, _| fn[0...(fn.index('/') || 0)]}.delete_if {|fn, _| fn.blank?}.map do |name, files|
39
+ Theme.new name, files
40
+ end
41
+ rescue SocketError
42
+ []
43
+ end
44
+ end
45
+
46
+ def download_templates(theme)
47
+ theme.templates_for(template_engine).each do |template|
48
+ say " downloading #{template.name} from bootstrap_pager_themes..."
49
+ create_file template.name, GitHubApiHelper.get_content_for("#{theme.name}/#{template.name}")
50
+ end
51
+ end
52
+
53
+ def copy_default_views
54
+ filename_pattern = File.join self.class.source_root, "*.html.#{template_engine}"
55
+ Dir.glob(filename_pattern).map {|f| File.basename f}.each do |f|
56
+ copy_file f, "app/views/bootstrap_pager/#{f}"
57
+ end
58
+ end
59
+
60
+ def template_engine
61
+ options[:template_engine].try(:to_s).try(:downcase) || 'erb'
62
+ end
63
+ end
64
+
65
+ Template = Struct.new(:name, :sha) do
66
+ def description?
67
+ name == 'DESCRIPTION'
68
+ end
69
+
70
+ def view?
71
+ name =~ /^app\/views\//
72
+ end
73
+
74
+ def engine #:nodoc:
75
+ File.extname(name).sub /^\./, ''
76
+ end
77
+ end
78
+
79
+ class Theme
80
+ attr_accessor :name
81
+ def initialize(name, templates) #:nodoc:
82
+ @name, @templates = name, templates.map {|fn, sha| Template.new fn.sub(/^#{name}\//, ''), sha}
83
+ end
84
+
85
+ def description #:nodoc:
86
+ file = @templates.detect(&:description?)
87
+ return "#{' ' * 12}#{name}" unless file
88
+ GitHubApiHelper.get_content_for("#{@name}/#{file.name}").chomp.gsub(/^/, ' ' * 12)
89
+ end
90
+
91
+ def templates_for(template_engine) #:nodoc:
92
+ @templates.select {|t| !t.description?}.select {|t| !t.view? || (t.engine == template_engine)}
93
+ end
94
+ end
95
+
96
+ module GitHubApiHelper
97
+ def get_files_in_master
98
+ master_tree_sha = open('https://api.github.com/repos/amatsuda/bootstrap_pager_themes/git/refs/heads/master') do |json|
99
+ ActiveSupport::JSON.decode(json)['object']['sha']
100
+ end
101
+ open('https://api.github.com/repos/amatsuda/bootstrap_pager_themes/git/trees/' + master_tree_sha + '?recursive=1') do |json|
102
+ blobs = ActiveSupport::JSON.decode(json)['tree'].find_all {|i| i['type'] == 'blob' }
103
+ blobs.map do |blob|
104
+ [blob['path'], blob['sha']]
105
+ end
106
+ end
107
+ end
108
+ module_function :get_files_in_master
109
+
110
+ def get_content_for(path)
111
+ open('https://api.github.com/repos/amatsuda/bootstrap_pager_themes/contents/' + path) do |json|
112
+ Base64.decode64(ActiveSupport::JSON.decode(json)['content'])
113
+ end
114
+ end
115
+ module_function :get_content_for
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,91 @@
1
+ require 'spec_helper'
2
+
3
+ describe BootstrapPager::Configuration do
4
+ subject { BootstrapPager.config }
5
+ describe 'default_per_page' do
6
+ context 'by default' do
7
+ its(:default_per_page) { should == 25 }
8
+ end
9
+ context 'configured via config block' do
10
+ before do
11
+ BootstrapPager.configure {|c| c.default_per_page = 17}
12
+ end
13
+ its(:default_per_page) { should == 17 }
14
+ after do
15
+ BootstrapPager.configure {|c| c.default_per_page = 25}
16
+ end
17
+ end
18
+ end
19
+
20
+ describe 'max_per_page' do
21
+ context 'by default' do
22
+ its(:max_per_page) { should == nil }
23
+ end
24
+ context 'configure via config block' do
25
+ before do
26
+ BootstrapPager.configure {|c| c.max_per_page = 100}
27
+ end
28
+ its(:max_per_page) { should == 100 }
29
+ after do
30
+ BootstrapPager.configure {|c| c.max_per_page = nil}
31
+ end
32
+ end
33
+ end
34
+
35
+ describe 'window' do
36
+ context 'by default' do
37
+ its(:window) { should == 4 }
38
+ end
39
+ end
40
+
41
+ describe 'outer_window' do
42
+ context 'by default' do
43
+ its(:outer_window) { should == 0 }
44
+ end
45
+ end
46
+
47
+ describe 'left' do
48
+ context 'by default' do
49
+ its(:left) { should == 0 }
50
+ end
51
+ end
52
+
53
+ describe 'right' do
54
+ context 'by default' do
55
+ its(:right) { should == 0 }
56
+ end
57
+ end
58
+
59
+ describe 'param_name' do
60
+ context 'by default' do
61
+ its(:param_name) { should == :page }
62
+ end
63
+
64
+ context 'configured via config block' do
65
+ before do
66
+ BootstrapPager.configure {|c| c.param_name = lambda { :test } }
67
+ end
68
+
69
+ its(:param_name) { should == :test }
70
+
71
+ after do
72
+ BootstrapPager.configure {|c| c.param_name = :page }
73
+ end
74
+ end
75
+ end
76
+
77
+ describe 'max_pages' do
78
+ context 'by default' do
79
+ its(:max_pages) { should == nil }
80
+ end
81
+ context 'configure via config block' do
82
+ before do
83
+ BootstrapPager.configure {|c| c.max_pages = 5}
84
+ end
85
+ its(:max_pages) { should == 5 }
86
+ after do
87
+ BootstrapPager.configure {|c| c.max_pages = nil}
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,3 @@
1
+ # database
2
+ ActiveRecord::Base.configurations = {'test' => {:adapter => 'sqlite3', :database => ':memory:'}}
3
+ ActiveRecord::Base.establish_connection('test')
@@ -0,0 +1,57 @@
1
+ # models
2
+ class User < ActiveRecord::Base
3
+ has_many :authorships
4
+ has_many :readerships
5
+ has_many :books_authored, :through => :authorships, :source => :book
6
+ has_many :books_read, :through => :readerships, :source => :book
7
+ has_many :addresses, :class_name => 'User::Address'
8
+
9
+ def readers
10
+ User.joins(:books_read => :authors).where(:authors_books => {:id => self})
11
+ end
12
+
13
+ scope :by_name, order(:name)
14
+ scope :by_read_count, lambda {
15
+ cols = if connection.adapter_name == "PostgreSQL"
16
+ column_names.map { |column| %{"users"."#{column}"} }.join(", ")
17
+ else
18
+ '"users"."id"'
19
+ end
20
+ group(cols).select("count(readerships.id) AS read_count, #{cols}").order('read_count DESC')
21
+ }
22
+ end
23
+ class Authorship < ActiveRecord::Base
24
+ belongs_to :user
25
+ belongs_to :book
26
+ end
27
+ class Readership < ActiveRecord::Base
28
+ belongs_to :user
29
+ belongs_to :book
30
+ end
31
+ class Book < ActiveRecord::Base
32
+ has_many :authorships
33
+ has_many :readerships
34
+ has_many :authors, :through => :authorships, :source => :user
35
+ has_many :readers, :through => :readerships, :source => :user
36
+ end
37
+ # a model that is a descendant of AR::Base but doesn't directly inherit AR::Base
38
+ class Admin < User
39
+ end
40
+ # a model with namespace
41
+ class User::Address < ActiveRecord::Base
42
+ belongs_to :user
43
+ end
44
+
45
+ #migrations
46
+ class CreateAllTables < ActiveRecord::Migration
47
+ def self.up
48
+ create_table(:gem_defined_models) { |t| t.string :name; t.integer :age }
49
+ create_table(:users) {|t| t.string :name; t.integer :age}
50
+ create_table(:books) {|t| t.string :title}
51
+ create_table(:readerships) {|t| t.integer :user_id; t.integer :book_id }
52
+ create_table(:authorships) {|t| t.integer :user_id; t.integer :book_id }
53
+ create_table(:user_addresses) {|t| t.string :street; t.integer :user_id }
54
+ end
55
+ end
56
+ ActiveRecord::Migration.verbose = false
57
+ CreateAllTables.up
@@ -0,0 +1,7 @@
1
+ DataMapper.setup(:default, 'sqlite::memory:')
2
+
3
+ class DataMapper::Collection
4
+ def default_per_page
5
+ model.default_per_page
6
+ end
7
+ end
@@ -0,0 +1,27 @@
1
+ class User
2
+ include ::DataMapper::Resource
3
+
4
+ property :id, Serial
5
+ property :name, String, :required => true
6
+ property :age, Integer
7
+
8
+ has n, :projects, :through => Resource
9
+ end
10
+
11
+ class User::Address
12
+ include ::DataMapper::Resource
13
+
14
+ property :id, Serial
15
+ end
16
+
17
+ class Project
18
+ include ::DataMapper::Resource
19
+
20
+ property :id, Serial
21
+ property :name, String, :required => true
22
+
23
+ has n, :users, :through => Resource
24
+ end
25
+
26
+ DataMapper.finalize
27
+ DataMapper.auto_migrate!