respondo 2.0.0 → 2.1.1

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.
@@ -0,0 +1,350 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ module Respondo
6
+ module Generators
7
+ class InstallGenerator < Rails::Generators::Base
8
+ desc "Interactive setup — creates config/initializers/respondo.rb with your preferences."
9
+
10
+ # We bypass Thor's `say` entirely for all display output and use
11
+ # $stdout.puts / print directly. This prevents Thor from re-echoing
12
+ # buffered output and causing duplicate lines in the terminal.
13
+
14
+ def run_interactive_setup
15
+ # out LOGO
16
+ out logo_with_version
17
+ out divider
18
+ out line(" This wizard will generate config/initializers/respondo.rb")
19
+ out line(" tailored to your project — no need to read the full README.")
20
+ out blank
21
+ out line(yellow(" All settings can be changed later by editing the initializer."))
22
+ out divider
23
+ out blank
24
+
25
+ unless confirm(" Ready to configure Respondo? (y/n) ")
26
+ out blank
27
+ out line(yellow(" Skipped. Run this again any time:"))
28
+ out line(" rails generate respondo:install")
29
+ out blank
30
+ return
31
+ end
32
+
33
+ @cfg = {}
34
+
35
+ step_project_info
36
+ step_messages
37
+ step_request_id
38
+ step_camelize
39
+ step_default_meta
40
+ step_serializer
41
+
42
+ print_summary
43
+ write_initializer
44
+ print_done
45
+ end
46
+
47
+ private
48
+
49
+ # =========================================================================
50
+ # Steps
51
+ # =========================================================================
52
+
53
+ def step_project_info
54
+ out section("Project Info")
55
+ out line(" Project / app name")
56
+ out line(yellow(" (Used as a comment header in the initializer)"))
57
+ @cfg[:project_name] = prompt_default(Rails.application.class.module_parent_name)
58
+
59
+ out blank
60
+ out line(" API version")
61
+ out line(yellow(" (e.g. v1 — added to every response meta block)"))
62
+ @cfg[:api_version] = prompt_default("v1")
63
+ end
64
+
65
+ def step_messages
66
+ out section("Response Messages")
67
+ out line(" Fallback messages used when you don't pass message: explicitly.")
68
+ out blank
69
+
70
+ out line(" Default success message")
71
+ @cfg[:default_success_message] = prompt_default("Success")
72
+
73
+ out blank
74
+ out line(" Default error message")
75
+ @cfg[:default_error_message] = prompt_default("An error occurred")
76
+ end
77
+
78
+ def step_request_id
79
+ out section("Request ID")
80
+ out line(" When enabled, Rails request.request_id is included in every")
81
+ out line(" response meta block — useful for log correlation and debugging.")
82
+ out blank
83
+ @cfg[:include_request_id] = confirm(" Include request_id in every response? (y/n) ")
84
+ end
85
+
86
+ def step_camelize
87
+ out section("Key Format")
88
+ out line(" When enabled, all JSON keys are camelCased:")
89
+ out line(yellow(' { "createdAt": "...", "userId": 1 }'))
90
+ out line(" Recommended for Flutter, React, and JavaScript clients.")
91
+ out blank
92
+ @cfg[:camelize_keys] = confirm(" Camelize all response keys? (y/n) ")
93
+ end
94
+
95
+ def step_default_meta
96
+ out section("Global Meta Fields")
97
+ out line(" Static key=value pairs merged into the meta block of EVERY response.")
98
+ out line(" Example: platform=mobile environment=production")
99
+ out blank
100
+ out line(yellow(" Note: api_version from above is already included automatically."))
101
+ out blank
102
+
103
+ @cfg[:default_meta] = {}
104
+ return unless confirm(" Add extra global meta fields? (y/n) ")
105
+
106
+ out blank
107
+ out line(" Enter key=value one at a time. Blank line to finish.")
108
+ out blank
109
+
110
+ loop do
111
+ $stdout.print cyan(" key=value › ")
112
+ raw = $stdin.gets.to_s.strip
113
+ break if raw.empty?
114
+
115
+ unless raw.include?("=")
116
+ out line(yellow(" Use key=value format (e.g. platform=mobile). Skipping."))
117
+ next
118
+ end
119
+
120
+ key, value = raw.split("=", 2)
121
+
122
+ next out line(yellow(" Use key=value format.")) if key.nil? || key.strip.empty?
123
+
124
+ k = key.strip
125
+ v = (value || "").strip
126
+ @cfg[:default_meta][k] = v
127
+ out line(green(" ✓ #{k}: #{v.inspect}"))
128
+ end
129
+ end
130
+
131
+ def step_serializer
132
+ out section("Custom Serializer")
133
+ out line(" By default Respondo serializes ActiveRecord models, collections,")
134
+ out line(" hashes, and arrays automatically.")
135
+ out blank
136
+ out line(" You can override with any callable: ->(obj) { MySerializer.new(obj).as_json }")
137
+ out blank
138
+ @cfg[:custom_serializer] = confirm(" Add a custom serializer stub? (y/n) ")
139
+ end
140
+
141
+ # =========================================================================
142
+ # Summary
143
+ # =========================================================================
144
+
145
+ def print_summary
146
+ out blank
147
+ out divider
148
+ out line(cyan(" Configuration Summary"))
149
+ out divider
150
+ out blank
151
+ summary_row "Project", @cfg[:project_name]
152
+ summary_row "API version", @cfg[:api_version]
153
+ summary_row "Success message", @cfg[:default_success_message]
154
+ summary_row "Error message", @cfg[:default_error_message]
155
+ summary_row "Include request_id", @cfg[:include_request_id]
156
+ summary_row "Camelize keys", @cfg[:camelize_keys]
157
+ summary_row "Custom serializer", @cfg[:custom_serializer]
158
+
159
+ unless @cfg[:default_meta].empty?
160
+ out blank
161
+ out line(" Global meta:")
162
+ @cfg[:default_meta].each { |k, v| out line(" #{k}: #{v.inspect}") }
163
+ end
164
+
165
+ out blank
166
+ out divider
167
+ out blank
168
+ end
169
+
170
+ def summary_row(label, value)
171
+ bool_true = value == true
172
+ val_str = bool_true ? green(value.inspect) : yellow(value.inspect)
173
+ out " #{("#{label}:").ljust(24)}#{val_str}\n"
174
+ end
175
+
176
+ # =========================================================================
177
+ # Write file
178
+ # =========================================================================
179
+
180
+ def write_initializer
181
+ dir = File.join(destination_root, "config", "initializers")
182
+ path = File.join(dir, "respondo.rb")
183
+ FileUtils.mkdir_p(dir)
184
+ File.write(path, build_content)
185
+ out line(green(" ✅ Created config/initializers/respondo.rb"))
186
+ out blank
187
+ end
188
+
189
+ def build_content
190
+ meta = { "api_version" => @cfg[:api_version] }.merge(@cfg[:default_meta])
191
+ b = Lines.new
192
+
193
+ b << "# frozen_string_literal: true"
194
+ b << ""
195
+ b << "# Respondo initializer — #{@cfg[:project_name]}"
196
+ b << "# Generated by: rails generate respondo:install"
197
+ b << "# Respondo version: #{Respondo::VERSION}"
198
+ b << "# Docs: https://github.com/your-org/respondo"
199
+ b << ""
200
+ b << "Respondo.configure do |config|"
201
+ b << ""
202
+ b << " # ── Messages ─────────────────────────────────────────────────────────"
203
+ b << " # Fallback when render_success / render_error is called without message:"
204
+ b << " config.default_success_message = #{@cfg[:default_success_message].inspect}"
205
+ b << " config.default_error_message = #{@cfg[:default_error_message].inspect}"
206
+ b << ""
207
+ b << " # ── Request ID ───────────────────────────────────────────────────────"
208
+ b << " # Includes Rails request.request_id in every response meta block."
209
+ b << " config.include_request_id = #{@cfg[:include_request_id]}"
210
+ b << ""
211
+ b << " # ── Key Format ───────────────────────────────────────────────────────"
212
+ b << " # CamelCase all JSON keys — recommended for Flutter / JS clients."
213
+ b << " config.camelize_keys = #{@cfg[:camelize_keys]}"
214
+ b << ""
215
+ b << " # ── Global Meta ──────────────────────────────────────────────────────"
216
+ b << " # Static fields merged into the meta block of every response."
217
+
218
+ if meta.empty?
219
+ b << " config.default_meta = {}"
220
+ else
221
+ b << " config.default_meta = {"
222
+ meta.each_with_index do |(k, v), i|
223
+ comma = i < meta.size - 1 ? "," : ""
224
+ b << " #{k}: #{v.inspect}#{comma}"
225
+ end
226
+ b << " }"
227
+ end
228
+
229
+ if @cfg[:custom_serializer]
230
+ b << ""
231
+ b << " # ── Custom Serializer ────────────────────────────────────────────────"
232
+ b << " # Replace the lambda body with your own serialization logic."
233
+ b << " # Examples:"
234
+ b << " # ActiveModelSerializers: ->(obj) { SomeSerializer.new(obj).as_json }"
235
+ b << " # Blueprinter: ->(obj) { UserBlueprint.render_as_hash(obj) }"
236
+ b << " #"
237
+ b << " # config.serializer = ->(obj) { MySerializer.new(obj).as_json }"
238
+ end
239
+
240
+ b << ""
241
+ b << "end"
242
+ b << ""
243
+ b.to_s
244
+ end
245
+
246
+ # =========================================================================
247
+ # Done
248
+ # =========================================================================
249
+
250
+ def print_done
251
+ out divider
252
+ out blank
253
+ out line(cyan(" 🎉 Respondo is ready!"))
254
+ out blank
255
+ out line(" Next steps:")
256
+ out line(" 1. Review config/initializers/respondo.rb")
257
+ out line(" 2. Use render_success / render_error in your controllers")
258
+ out line(" 3. Re-run rails generate respondo:install to regenerate")
259
+ out blank
260
+ out divider
261
+ out blank
262
+ end
263
+
264
+ # =========================================================================
265
+ # Output primitives — all output goes through $stdout, never through Thor
266
+ # =========================================================================
267
+
268
+ def out(str)
269
+ $stdout.print str
270
+ $stdout.flush
271
+ end
272
+
273
+ def line(str) = "#{str}\n"
274
+ def blank = "\n"
275
+
276
+ def divider
277
+ " #{cyan("─" * 68)}\n"
278
+ end
279
+
280
+ def section(title)
281
+ dashes = "─" * [0, 54 - title.length].max
282
+ "\n #{cyan("┌─ #{title} #{dashes}┐")}\n\n"
283
+ end
284
+
285
+ def prompt_default(default)
286
+ $stdout.print " #{cyan("›")} #{yellow("[#{default}]")}: "
287
+ $stdout.flush
288
+ result = $stdin.gets.to_s.strip
289
+ result.empty? ? default.to_s : result
290
+ end
291
+
292
+ def confirm(question)
293
+ $stdout.print question
294
+ $stdout.flush
295
+ $stdin.gets.to_s.strip.downcase.start_with?("y")
296
+ end
297
+
298
+ # =========================================================================
299
+ # ANSI colors
300
+ # =========================================================================
301
+
302
+ def cyan(t) = "\e[36m#{t}\e[0m"
303
+ def green(t) = "\e[32m#{t}\e[0m"
304
+ def yellow(t) = "\e[33m#{t}\e[0m"
305
+
306
+ # =========================================================================
307
+ # ASCII logo
308
+ # =========================================================================
309
+
310
+ LOGOS = <<~'LOGO'
311
+
312
+ ██████╗ ███████╗███████╗██████╗ ██████╗ ███╗ ██╗██████╗ ██████╗
313
+ ██╔══██╗██╔════╝██╔════╝██╔══██╗██╔═══██╗████╗ ██║██╔══██╗██╔═══██╗
314
+ ██████╔╝█████╗ ███████╗██████╔╝██║ ██║██╔██╗ ██║██║ ██║██║ ██║
315
+ ██╔══██╗██╔══╝ ╚════██║██╔═══╝ ██║ ██║██║╚██╗██║██║ ██║██║ ██║
316
+ ██║ ██║███████╗███████║██║ ╚██████╔╝██║ ╚████║██████╔╝╚██████╔╝
317
+ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝ ╚═════╝ ╚═╝ ╚═══╝╚═════╝ ╚═════╝
318
+
319
+ Smart JSON API Response Formatter for Rails
320
+ ─── v#{Respondo::VERSION} ───
321
+
322
+ LOGO
323
+
324
+ def logo_with_version
325
+ green(<<~LOGO)
326
+
327
+ ██████╗ ███████╗███████╗██████╗ ██████╗ ███╗ ██╗██████╗ ██████╗
328
+ ██╔══██╗██╔════╝██╔════╝██╔══██╗██╔═══██╗████╗ ██║██╔══██╗██╔═══██╗
329
+ ██████╔╝█████╗ ███████╗██████╔╝██║ ██║██╔██╗ ██║██║ ██║██║ ██║
330
+ ██╔══██╗██╔══╝ ╚════██║██╔═══╝ ██║ ██║██║╚██╗██║██║ ██║██║ ██║
331
+ ██║ ██║███████╗███████║██║ ╚██████╔╝██║ ╚████║██████╔╝╚██████╔╝
332
+ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝ ╚═════╝ ╚═╝ ╚═══╝╚═════╝ ╚═════╝
333
+
334
+ Smart JSON API Response Formatter for Rails
335
+ ─── v#{Respondo::VERSION} ───
336
+
337
+ LOGO
338
+ end
339
+ # =========================================================================
340
+ # Simple line buffer for building file content
341
+ # =========================================================================
342
+
343
+ class Lines
344
+ def initialize = (@buf = [])
345
+ def <<(str) = @buf << str
346
+ def to_s = @buf.join("\n") + "\n"
347
+ end
348
+ end
349
+ end
350
+ end
@@ -146,7 +146,7 @@ module Respondo
146
146
  # 204 No Content — deletions, actions with no response body
147
147
  # Note: we still return our standard JSON structure for consistency
148
148
  def render_no_content(message: "Deleted successfully", meta: {}, pagination: nil)
149
- render_success(data: nil, message: message, meta: meta, pagination: pagination, code: 204, status: :ok)
149
+ render_success(data: nil, message: message, meta: meta, pagination: pagination, code: 204, status: :no_content)
150
150
  end
151
151
 
152
152
  # 205 Reset Content — tell the client to reset the document view
@@ -97,28 +97,6 @@ module Respondo
97
97
  meta
98
98
  end
99
99
 
100
- # def build_meta
101
- # meta = { timestamp: current_timestamp }
102
-
103
- # # Only extract pagination when caller has not explicitly disabled it
104
- # if @pagination
105
- # pagination = if @pagy
106
- # Pagination.extract(@pagy)
107
- # else
108
- # Pagination.extract(@raw_data)
109
- # end
110
- # meta[:pagination] = pagination if pagination
111
- # end
112
-
113
- # # Request ID (Rails only, opt-in via config)
114
- # if Respondo.config.include_request_id && @request&.respond_to?(:request_id)
115
- # meta[:request_id] = @request.request_id
116
- # end
117
-
118
- # # Merge any caller-supplied meta last (allows overriding)
119
- # meta.merge(@extra_meta)
120
- # end
121
-
122
100
  def current_timestamp
123
101
  if defined?(Time.current)
124
102
  Time.current.iso8601
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Respondo
4
- VERSION = "2.0.0"
4
+ VERSION = "2.1.1"
5
5
  end
data/respondo.gemspec CHANGED
@@ -19,11 +19,20 @@ Gem::Specification.new do |spec|
19
19
  spec.license = "MIT"
20
20
  spec.required_ruby_version = ">= 2.7.0"
21
21
 
22
+ spec.metadata = {
23
+ "homepage_uri" => spec.homepage,
24
+ "source_code_uri" => spec.homepage,
25
+ "changelog_uri" => "#{spec.homepage}/blob/main/CHANGELOG.md",
26
+ "bug_tracker_uri" => "#{spec.homepage}/issues",
27
+ "rubygems_mfa_required" => "true"
28
+ }
29
+
22
30
  spec.files = Dir["lib/**/*.rb", "README.md", "LICENSE.txt", "CHANGELOG.md", "respondo.gemspec"]
23
31
  spec.require_paths = ["lib"]
24
32
 
25
- spec.add_development_dependency "rspec", "~> 3.12"
26
- spec.add_development_dependency "rake", "~> 13.0"
27
- spec.add_development_dependency "activesupport","~> 7.0"
28
- spec.add_development_dependency 'simplecov', '~> 0.22'
33
+ spec.add_development_dependency "railties", "~> 8.1.3"
34
+ spec.add_development_dependency "rspec", "~> 3.12"
35
+ spec.add_development_dependency "rake", "~> 13.0"
36
+ spec.add_development_dependency "activesupport", "~> 8.1.3"
37
+ spec.add_development_dependency 'simplecov', "~> 0.22"
29
38
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: respondo
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - shailendra Kumar
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-04-08 00:00:00.000000000 Z
11
+ date: 2026-04-21 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: railties
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 8.1.3
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 8.1.3
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: rspec
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -44,14 +58,14 @@ dependencies:
44
58
  requirements:
45
59
  - - "~>"
46
60
  - !ruby/object:Gem::Version
47
- version: '7.0'
61
+ version: 8.1.3
48
62
  type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
- version: '7.0'
68
+ version: 8.1.3
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: simplecov
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -80,10 +94,10 @@ files:
80
94
  - CHANGELOG.md
81
95
  - LICENSE.txt
82
96
  - README.md
97
+ - lib/generators/respondo/install/install_generator.rb
83
98
  - lib/respondo.rb
84
99
  - lib/respondo/configuration.rb
85
100
  - lib/respondo/controller_helpers.rb
86
- - lib/respondo/pagination.rb
87
101
  - lib/respondo/railtie.rb
88
102
  - lib/respondo/response_builder.rb
89
103
  - lib/respondo/serializer.rb
@@ -92,7 +106,12 @@ files:
92
106
  homepage: https://github.com/spatelpatidar/respondo
93
107
  licenses:
94
108
  - MIT
95
- metadata: {}
109
+ metadata:
110
+ homepage_uri: https://github.com/spatelpatidar/respondo
111
+ source_code_uri: https://github.com/spatelpatidar/respondo
112
+ changelog_uri: https://github.com/spatelpatidar/respondo/blob/main/CHANGELOG.md
113
+ bug_tracker_uri: https://github.com/spatelpatidar/respondo/issues
114
+ rubygems_mfa_required: 'true'
96
115
  post_install_message:
97
116
  rdoc_options: []
98
117
  require_paths:
@@ -1,152 +0,0 @@
1
- # # frozen_string_literal: true
2
-
3
- # module Respondo
4
- # # Extracts pagination metadata from Kaminari, Pagy, or WillPaginate collections.
5
- # #
6
- # # --- How pagination works in Respondo ---
7
- # #
8
- # # Respondo does NOT paginate data for you. Pagination is always performed by
9
- # # your chosen library (Kaminari, Pagy, or WillPaginate) in your controller
10
- # # BEFORE you call render_success / render_ok.
11
- # #
12
- # # Respondo's role is purely to DETECT that the collection is paginated and
13
- # # EXTRACT the metadata so it appears in the `meta.pagination` block.
14
- # #
15
- # # --- Usage patterns by library ---
16
- # #
17
- # # Kaminari (pagination lives on the collection itself):
18
- # # @users = User.page(params[:page]).per(params[:per_page] || 10)
19
- # # render_ok(data: @users) # ← just pass the collection; Respondo detects Kaminari
20
- # #
21
- # # WillPaginate (same — pagination lives on the collection):
22
- # # @users = User.paginate(page: params[:page], per_page: 10)
23
- # # render_ok(data: @users) # ← same pattern
24
- # #
25
- # # Pagy (metadata lives on a SEPARATE Pagy object, not the collection):
26
- # # @pagy, @users = pagy(User.all, items: 10)
27
- # # render_ok(data: @users, pagy: @pagy) # ← pass the Pagy object explicitly
28
- # #
29
- # # Alternatively, if you decorate your collection with pagy_metadata:
30
- # # render_ok(data: @pagy) # ← pass the Pagy object as data (unusual)
31
- # #
32
- # # --- Returned hash shape (same regardless of library) ---
33
- # # {
34
- # # current_page: Integer,
35
- # # per_page: Integer,
36
- # # total_pages: Integer,
37
- # # total_count: Integer,
38
- # # next_page: Integer | nil,
39
- # # prev_page: Integer | nil
40
- # # }
41
- # #
42
- # # --- Disabling pagination meta ---
43
- # # Pass pagination: false to any render_* helper to suppress the block entirely:
44
- # # render_ok(data: @users, pagination: false)
45
- # #
46
- # module Pagination
47
- # module_function
48
-
49
- # # @param collection [Object] any object — returns nil if not a paginated collection
50
- # # @return [Hash, nil]
51
- # def extract(collection)
52
- # return nil if collection.nil?
53
-
54
- # if pagy?(collection)
55
- # from_pagy(collection)
56
- # elsif kaminari?(collection)
57
- # from_kaminari(collection)
58
- # elsif will_paginate?(collection)
59
- # from_will_paginate(collection)
60
- # else
61
- # nil
62
- # end
63
- # end
64
-
65
- # private
66
-
67
- # module_function
68
-
69
- # # -------------------------------------------------------------------------
70
- # # Pagy
71
- # # -------------------------------------------------------------------------
72
- # # Pagy stores metadata on a SEPARATE Pagy object, not the collection.
73
- # # You must pass it explicitly via the `pagy:` keyword in render_success/render_ok.
74
- # #
75
- # # Example in controller:
76
- # # @pagy, @records = pagy(User.all, items: 10)
77
- # # render_ok(data: @records, pagy: @pagy)
78
- # #
79
- # def pagy?(object)
80
- # defined?(Pagy) && object.is_a?(Pagy)
81
- # end
82
-
83
- # def from_pagy(pagy)
84
- # {
85
- # current_page: pagy.page,
86
- # per_page: pagy.items,
87
- # total_pages: pagy.pages,
88
- # total_count: pagy.count,
89
- # next_page: pagy.next,
90
- # prev_page: pagy.prev
91
- # }
92
- # end
93
-
94
- # # -------------------------------------------------------------------------
95
- # # Kaminari
96
- # # -------------------------------------------------------------------------
97
- # # Kaminari attaches pagination directly to the ActiveRecord relation.
98
- # # No extra argument needed — just pass the collection.
99
- # #
100
- # # Example in controller:
101
- # # @records = User.page(params[:page]).per(10)
102
- # # render_ok(data: @records)
103
- # #
104
- # def kaminari?(object)
105
- # object.respond_to?(:current_page) &&
106
- # object.respond_to?(:total_pages) &&
107
- # object.respond_to?(:limit_value)
108
- # end
109
-
110
- # def from_kaminari(collection)
111
- # {
112
- # current_page: collection.current_page,
113
- # per_page: collection.limit_value,
114
- # total_pages: collection.total_pages,
115
- # total_count: collection.total_count,
116
- # next_page: collection.next_page,
117
- # prev_page: collection.prev_page
118
- # }
119
- # end
120
-
121
- # # -------------------------------------------------------------------------
122
- # # WillPaginate
123
- # # -------------------------------------------------------------------------
124
- # # WillPaginate also attaches pagination to the collection.
125
- # # No extra argument needed — just pass the collection.
126
- # #
127
- # # Example in controller:
128
- # # @records = User.paginate(page: params[:page], per_page: 10)
129
- # # render_ok(data: @records)
130
- # #
131
- # # We distinguish WillPaginate from Kaminari by the absence of #limit_value.
132
- # #
133
- # def will_paginate?(object)
134
- # object.respond_to?(:current_page) &&
135
- # object.respond_to?(:total_pages) &&
136
- # object.respond_to?(:per_page) &&
137
- # !object.respond_to?(:limit_value)
138
- # end
139
-
140
- # def from_will_paginate(collection)
141
- # {
142
- # current_page: collection.current_page,
143
- # per_page: collection.per_page,
144
- # total_pages: collection.total_pages,
145
- # total_count: collection.total_entries,
146
- # next_page: collection.next_page,
147
- # prev_page: collection.previous_page
148
- # }
149
- # end
150
- # end
151
- # end
152
-