manveru-ramaze 2008.08 → 2008.09

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. data/Rakefile +1 -1
  2. data/bin/ramaze +1 -0
  3. data/doc/CHANGELOG +966 -0
  4. data/doc/tutorial/todolist.html +421 -313
  5. data/doc/tutorial/todolist.mkd +26 -9
  6. data/examples/helpers/paginate.rb +71 -0
  7. data/examples/misc/simple_auth.rb +20 -8
  8. data/lib/proto/controller/init.rb +10 -0
  9. data/lib/proto/controller/main.rb +1 -3
  10. data/lib/proto/model/init.rb +4 -0
  11. data/lib/proto/spec/main.rb +2 -1
  12. data/lib/proto/start.rb +3 -3
  13. data/lib/ramaze.rb +6 -1
  14. data/lib/ramaze/action.rb +2 -2
  15. data/lib/ramaze/adapter.rb +0 -5
  16. data/lib/ramaze/adapter/base.rb +24 -7
  17. data/lib/ramaze/contrib/gzip_filter.rb +22 -9
  18. data/lib/ramaze/contrib/maruku_uv.rb +59 -0
  19. data/lib/ramaze/contrib/profiling.rb +1 -1
  20. data/lib/ramaze/contrib/sequel/create_join.rb +25 -0
  21. data/lib/ramaze/contrib/sequel/form_field.rb +129 -0
  22. data/lib/ramaze/contrib/sequel/image.rb +198 -0
  23. data/lib/ramaze/contrib/sequel/relation.rb +82 -0
  24. data/lib/ramaze/controller/resolve.rb +1 -1
  25. data/lib/ramaze/current.rb +60 -20
  26. data/lib/ramaze/current/response.rb +15 -3
  27. data/lib/ramaze/dispatcher.rb +9 -3
  28. data/lib/ramaze/dispatcher/action.rb +2 -3
  29. data/lib/ramaze/dispatcher/directory.rb +1 -1
  30. data/lib/ramaze/dispatcher/error.rb +1 -1
  31. data/lib/ramaze/dispatcher/file.rb +1 -1
  32. data/lib/ramaze/helper/formatting.rb +33 -0
  33. data/lib/ramaze/helper/paginate.rb +234 -0
  34. data/lib/ramaze/option.rb +2 -2
  35. data/lib/ramaze/reloader.rb +2 -2
  36. data/lib/ramaze/snippets.rb +13 -0
  37. data/lib/ramaze/snippets/array/put_within.rb +31 -24
  38. data/lib/ramaze/snippets/binding/locals.rb +23 -11
  39. data/lib/ramaze/snippets/kernel/constant.rb +36 -21
  40. data/lib/ramaze/snippets/kernel/pretty_inspect.rb +12 -6
  41. data/lib/ramaze/snippets/numeric/filesize_format.rb +24 -17
  42. data/lib/ramaze/snippets/numeric/time.rb +63 -56
  43. data/lib/ramaze/snippets/object/__dir__.rb +29 -0
  44. data/lib/ramaze/snippets/object/acquire.rb +40 -0
  45. data/lib/ramaze/snippets/object/instance_variable_defined.rb +16 -5
  46. data/lib/ramaze/snippets/object/pretty.rb +14 -4
  47. data/lib/ramaze/snippets/object/scope.rb +14 -7
  48. data/lib/ramaze/snippets/ordered_set.rb +4 -0
  49. data/lib/ramaze/snippets/proc/locals.rb +17 -9
  50. data/lib/ramaze/snippets/ramaze/struct.rb +45 -0
  51. data/lib/ramaze/snippets/string/camel_case.rb +13 -8
  52. data/lib/ramaze/snippets/string/color.rb +24 -20
  53. data/lib/ramaze/snippets/string/each.rb +14 -3
  54. data/lib/ramaze/snippets/string/end_with.rb +17 -6
  55. data/lib/ramaze/snippets/string/esc.rb +26 -18
  56. data/lib/ramaze/snippets/string/ord.rb +12 -6
  57. data/lib/ramaze/snippets/string/snake_case.rb +13 -7
  58. data/lib/ramaze/snippets/string/start_with.rb +16 -6
  59. data/lib/ramaze/snippets/string/unindent.rb +23 -15
  60. data/lib/ramaze/snippets/thread/into.rb +3 -3
  61. data/lib/ramaze/spec/helper/snippets.rb +8 -0
  62. data/lib/ramaze/template/ezamar/textpow.syntax +34 -0
  63. data/lib/ramaze/tool/create.rb +27 -53
  64. data/lib/ramaze/tool/project_creator.rb +110 -0
  65. data/lib/ramaze/version.rb +1 -1
  66. data/rake_tasks/gem.rake +2 -1
  67. data/rake_tasks/maintenance.rake +38 -0
  68. data/rake_tasks/release.rake +6 -2
  69. data/rake_tasks/spec.rake +1 -2
  70. data/ramaze.gemspec +69 -78
  71. data/spec/examples/simple_auth.rb +2 -2
  72. data/spec/examples/templates/template_haml.rb +0 -2
  73. data/spec/ramaze/current/session.rb +1 -1
  74. data/spec/ramaze/dispatcher/file.rb +2 -2
  75. data/spec/ramaze/helper/formatting.rb +13 -0
  76. data/spec/ramaze/rewrite.rb +1 -1
  77. data/spec/ramaze/struct.rb +47 -0
  78. data/spec/ramaze/template/markaby.rb +1 -1
  79. data/spec/snippets/{kernel → object}/__dir__.rb +0 -0
  80. data/spec/snippets/{kernel → object}/acquire.rb +0 -0
  81. metadata +69 -78
  82. data/examples/app/rammit/spec/rammit.rb +0 -31
  83. data/examples/app/rammit/src/controller/main.rb +0 -3
  84. data/examples/app/rammit/src/controller/page.rb +0 -16
  85. data/examples/app/rammit/src/model.rb +0 -33
  86. data/examples/app/rammit/start.rb +0 -8
  87. data/examples/app/rammit/template/index.xhtml +0 -14
  88. data/examples/app/rammit/template/page/view.xhtml +0 -4
  89. data/lib/ramaze/snippets/kernel/__dir__.rb +0 -23
  90. data/lib/ramaze/snippets/kernel/acquire.rb +0 -34
  91. data/lib/ramaze/snippets/struct/fill.rb +0 -23
  92. data/lib/ramaze/snippets/struct/values_at.rb +0 -39
  93. data/lib/ramaze/snippets/symbol/to_proc.rb +0 -24
  94. data/lib/ramaze/sourcereload.rb +0 -183
  95. data/spec/snippets/struct/fill.rb +0 -26
  96. data/spec/snippets/struct/values_at.rb +0 -52
  97. data/spec/snippets/symbol/to_proc.rb +0 -13
@@ -0,0 +1,82 @@
1
+ # Copyright (c) 2008 Michael Fellinger m.fellinger@gmail.com
2
+ # All files in this distribution are subject to the terms of the Ruby license.
3
+
4
+ # Pretty DSL to express Sequel relations
5
+ #
6
+ # Usage:
7
+ # SequelRelation.relations do
8
+ # the User do
9
+ # has_many Article
10
+ # has_one Avatar
11
+ # end
12
+ #
13
+ # the Article do
14
+ # belongs_to User
15
+ # end
16
+ #
17
+ # the Avatar do
18
+ # belongs_to User
19
+ # end
20
+ # end
21
+
22
+ module SequelRelation
23
+ def self.relations(&block)
24
+ rema = RelationshipManager.new(&block)
25
+ rema.finalize
26
+ end
27
+
28
+ class RelationshipManager
29
+ TODO = {}
30
+
31
+ def initialize(&block)
32
+ instance_eval(&block)
33
+ end
34
+
35
+ def finalize
36
+ TODO.keys.each do |model|
37
+ model.create_table unless model.table_exists?
38
+ end
39
+
40
+ TODO.each do |model, instructions|
41
+ instructions.each do |args|
42
+ model.send(*args)
43
+ end
44
+ end
45
+
46
+ return # remove this line for debugging
47
+
48
+ pp TODO
49
+
50
+ TODO.keys.each do |model|
51
+ puts "the #{model}"
52
+ assoc = model.send(:association_reflections)
53
+ assoc.each do |key, reflection|
54
+ puts " #{reflection[:type]} => #{key}"
55
+ end
56
+ end
57
+ end
58
+
59
+ def the(left_model, &block)
60
+ @left = left_model
61
+ TODO[@left] = []
62
+ instance_eval(&block)
63
+ end
64
+
65
+ def belongs_to(model)
66
+ todo :belongs_to, model.to_s.downcase.to_sym
67
+ end
68
+
69
+ def has_many(model)
70
+ todo :create_join, model
71
+ todo :many_to_many, model.to_s.downcase.pluralize.to_sym
72
+ end
73
+
74
+ def has_one(model)
75
+ todo :belongs_to, model.to_s.downcase.to_sym
76
+ end
77
+
78
+ def todo(method, *args)
79
+ TODO[@left] << [method, *args]
80
+ end
81
+ end
82
+ end
@@ -250,7 +250,7 @@ module Ramaze
250
250
  # Raises Ramaze::Error::NoFilter
251
251
  # TODO:
252
252
  # * is this called at all for anybody?
253
- # I think everybody does have filters.
253
+ # I think everybody has filters.
254
254
 
255
255
  def raise_no_filter(path)
256
256
  raise Ramaze::Error::NoFilter, "No Filter found for `#{path}'"
@@ -3,6 +3,54 @@ require 'ramaze/current/response'
3
3
  require 'ramaze/current/session'
4
4
 
5
5
  module Ramaze
6
+ class Current
7
+ include Trinity
8
+ extend Trinity
9
+
10
+ def initialize(app)
11
+ @app = app
12
+ end
13
+
14
+ def call(env)
15
+ setup(env)
16
+ before_call
17
+ record
18
+
19
+ @app.call(env)
20
+ finish
21
+ ensure
22
+ after_call
23
+ end
24
+
25
+ def record
26
+ return unless filter = Global.record
27
+ request = Current.request
28
+ Record << request if filter.call(request)
29
+ end
30
+
31
+ def setup(env)
32
+ self.request = Request.new(env)
33
+ self.response = Response.new
34
+ self.session = Session.new
35
+ end
36
+
37
+ def finish
38
+ session.finish if session
39
+ response.finish
40
+ end
41
+
42
+ def self.call(env)
43
+ end
44
+
45
+ def before_call
46
+ end
47
+
48
+ def after_call
49
+ end
50
+ end
51
+ end
52
+ __END__
53
+
6
54
  module Current
7
55
  class << self
8
56
  include Trinity
@@ -35,35 +83,27 @@ module Ramaze
35
83
  end
36
84
 
37
85
  def before(&block)
38
- @before = block if block
39
- @before
86
+ @before = block_given? ? block : @before
40
87
  end
41
88
 
42
89
  def before_call
43
- if before
44
- begin
45
- before.call
46
- rescue Object => e
47
- Ramaze::Log.error e
48
- raise
49
- end
50
- end
90
+ return unless before
91
+ before.call
92
+ rescue Object => e
93
+ Ramaze::Log.error e
94
+ raise e
51
95
  end
52
96
 
53
97
  def after(&block)
54
- @after = block if block
55
- @after
98
+ @after = block_given? ? block : @after
56
99
  end
57
100
 
58
101
  def after_call
59
- if after
60
- begin
61
- after.call
62
- rescue Object => e
63
- Ramaze::Log.error e
64
- raise
65
- end
66
- end
102
+ return unless after
103
+ after.call
104
+ rescue Object => e
105
+ Ramaze::Log.error e
106
+ raise e
67
107
  end
68
108
  end
69
109
  end
@@ -15,13 +15,25 @@ module Ramaze
15
15
  end
16
16
 
17
17
  # Build/replace this responses data
18
- def build(body = body, status = status, header = header)
18
+ def build(new_body = body, status = status, header = header)
19
19
  header.each do |key, value|
20
20
  self[key] = value
21
21
  end
22
22
 
23
- self.body, self.status = body, status
24
- self
23
+ self.body, self.status = new_body, status
24
+ end
25
+
26
+ def body=(obj)
27
+ if obj.respond_to?(:stat)
28
+ @length = obj.stat.size
29
+ @body = obj
30
+ elsif obj.respond_to?(:size)
31
+ @body = []
32
+ @length = 0
33
+ write(obj)
34
+ else
35
+ raise(ArgumentError, "Invalid body: %p" % obj)
36
+ end
25
37
  end
26
38
  end
27
39
  end
@@ -14,10 +14,13 @@ module Ramaze
14
14
  # The Dispatcher receives requests from adapters and sets up the proper environment
15
15
  # to process them and respond.
16
16
 
17
- module Dispatcher
17
+ class Dispatcher
18
+ def initialize(*args)
19
+ Dispatcher.call(*args)
20
+ end
18
21
 
19
22
  # requests are passed to every
20
- FILTER = [ Dispatcher::File, Dispatcher::Action ] unless defined?(FILTER)
23
+ FILTER = OrderedSet[ Dispatcher::File, Dispatcher::Action, ]
21
24
 
22
25
  # Response codes to cache the output of for repeated requests.
23
26
  trait :shielded => [ STATUS_CODE["Not Found"] ]
@@ -28,7 +31,9 @@ module Ramaze
28
31
  # Entry point for Adapter#respond, takes a Rack::Request and
29
32
  # Rack::Response, sets up the environment and the goes on to dispatch
30
33
  # for the given path from rack_request.
31
- def handle
34
+ #
35
+ # +env+ will be ignored, it's just for compatibility with rack middleware
36
+ def call(env = nil)
32
37
  path = request.path_info.squeeze('/')
33
38
  path.sub!(/^#{Regexp.escape(Global.prefix)}/, '/')
34
39
  path.squeeze!('/')
@@ -49,6 +54,7 @@ module Ramaze
49
54
  rescue Object => exception
50
55
  error(exception)
51
56
  end
57
+ alias handle call
52
58
 
53
59
  # protects against recursive dispatch and reassigns the path_info in the
54
60
  # request, the rest of the request is kept intact.
@@ -2,7 +2,7 @@
2
2
  # All files in this distribution are subject to the terms of the Ruby license.
3
3
 
4
4
  module Ramaze
5
- module Dispatcher
5
+ class Dispatcher
6
6
 
7
7
  # This dispatcher is responsible for relaying requests to Controller::handle
8
8
  # and filtering the results using FILTER.
@@ -26,8 +26,7 @@ module Ramaze
26
26
  log(path)
27
27
 
28
28
  catch(:respond) {
29
- body = Controller.handle(path)
30
- Response.current.build(body)
29
+ response.write Controller.handle(path)
31
30
  }
32
31
 
33
32
  FILTER.each{|f| f.call(response)}
@@ -2,7 +2,7 @@
2
2
  # All files in this distribution are subject to the terms of the Ruby license.
3
3
 
4
4
  module Ramaze
5
- module Dispatcher
5
+ class Dispatcher
6
6
 
7
7
  # Generates a directory listing, see Ramaze::Controller::Directory for more
8
8
  # information and how to create your own directory listing page
@@ -2,7 +2,7 @@
2
2
  # All files in this distribution are subject to the terms of the Ruby license.
3
3
 
4
4
  module Ramaze
5
- module Dispatcher
5
+ class Dispatcher
6
6
 
7
7
  # Last resort dispatcher, tries to recover as much information as possible
8
8
  # from the past request and takes the appropiate actions.
@@ -5,7 +5,7 @@ require "time"
5
5
  require 'digest/md5'
6
6
 
7
7
  module Ramaze
8
- module Dispatcher
8
+ class Dispatcher
9
9
 
10
10
  # First of the dispatchers, looks up the public path and serves the
11
11
  # file if found.
@@ -104,6 +104,7 @@ module Ramaze
104
104
  all
105
105
  else
106
106
  text = b + c
107
+ text = yield(text) if block_given?
107
108
  %(#{a}<a href="#{b=="www."?"http://www.":b}#{c}"#{html_options}>#{text}</a>#{d})
108
109
  end
109
110
  end
@@ -121,5 +122,37 @@ module Ramaze
121
122
  text = string.each_byte.map{|c| "&#%03d" % c}.join
122
123
  %(<a href="mailto:#{string}">#{text}</a>)
123
124
  end
125
+
126
+ # Returns Hash with tags as keys and their weight as value.
127
+ #
128
+ # Example:
129
+ # tags = %w[ruby ruby code ramaze]
130
+ # tagcloud(tags)
131
+ # # => {"code"=>0.75, "ramaze"=>0.75, "ruby"=>1.0}
132
+ #
133
+ # The weight can be influenced by adjusting the +min+ and +max+ parameters,
134
+ # please make sure that +max+ is larger than +min+ to get meaningful output.
135
+ #
136
+ # This is not thought as immediate output to your template but rather to
137
+ # help either implementing your own algorithm or using the result as input
138
+ # for your tagcloud.
139
+ #
140
+ # Example:
141
+ # - tagcloud(tags).each do |tag, weight|
142
+ # - style = "font-size: %0.2fem" % weight
143
+ # %a{:style => style, :href => Rs(tag)}= h(tag)
144
+
145
+ def tagcloud(tags, min = 0.5, max = 1.5)
146
+ result = {}
147
+ total = tags.size.to_f
148
+ diff = max - min
149
+
150
+ tags.uniq.each do |tag|
151
+ count = tags.count(tag)
152
+ result[tag] = ((count / total) * diff) + min
153
+ end
154
+
155
+ result
156
+ end
124
157
  end
125
158
  end
@@ -0,0 +1,234 @@
1
+ require 'ramaze/gestalt'
2
+
3
+ module Ramaze
4
+ module Helper
5
+
6
+ # Helper for pagination and pagination-navigation.
7
+ #
8
+ # See detailed API docs for Paginator below.
9
+ # Also have a look at the examples/helpers/paginate.rb
10
+
11
+ module Paginate
12
+
13
+ # Define default options in your Controller, they are being retrieved by
14
+ # ancestral_trait, so you can also put it into a common superclass
15
+
16
+ trait :paginate => {
17
+ :limit => 10,
18
+ :var => 'pager',
19
+ }
20
+
21
+ # Returns a new Paginator instance.
22
+ #
23
+ # Note that the pagination relies on being inside a Ramaze request to
24
+ # gain necessary metadata about the page it resides on, you cannot use it
25
+ # outside of Ramaze yet.
26
+ #
27
+ # The examples below are meant to be used within your controller or view.
28
+ #
29
+ # Usage with Array:
30
+ # data = (1..100).to_a
31
+ # @pager = paginate(data, :limit => 30, :page => 2)
32
+ # @pager.navigation
33
+ # @pager.each{|e| puts(e) }
34
+ #
35
+ # Usage with Sequel:
36
+ # data = Article.filter(:public => true)
37
+ # @pager = paginate(data, :limit => 5)
38
+ # @pager.navigation
39
+ # @pager.each{|e| puts(e)
40
+ #
41
+ # +dataset+ may be a Sequel dataset or Array
42
+ # +options+ Takes precedence to trait[:paginate] and may contain
43
+ # following pairs:
44
+ # :limit The number of elements used when you call #each on the
45
+ # paginator
46
+ # :var The variable name being used in the request, this is helpful
47
+ # if you want to use two or more independent paginations on the
48
+ # same page.
49
+ # :page The page you are currently on, if not given it will be
50
+ # retrieved from current request variables. Defaults to 1 if
51
+ # neither exists.
52
+
53
+ def paginate(dataset, options = {})
54
+ options = ancestral_trait[:paginate].merge(options)
55
+ limit = options[:limit]
56
+ var = options[:var]
57
+ page = options[:page] || (request[var] || 1).to_i
58
+
59
+ Paginator.new(dataset, page, limit, var)
60
+ end
61
+
62
+ # Provides easy pagination and navigation
63
+
64
+ class Paginator
65
+ include Ramaze::Helper::Link
66
+ include Ramaze::Helper::CGI
67
+
68
+ def initialize(data = [], page = 1, limit = 10, var = 'pager')
69
+ @data, @page, @limit, @var = data, page, limit, var
70
+ @pager = pager_for(data)
71
+ @page = @page > page_count ? page_count : @page
72
+ @pager = pager_for(data)
73
+ end
74
+
75
+ # Returns String with navigation div.
76
+ #
77
+ # This cannot be customized very nicely, but you can style it easily
78
+ # with CSS.
79
+ #
80
+ # Output with 5 elements, page 1, limit 3:
81
+ # <div class="pager">
82
+ # <span class="first grey">&lt;&lt;</span>
83
+ # <span class="previous grey">&lt;</span>
84
+ # <a class="current" href="/index?pager=1">1</a>
85
+ # <a href="/index?pager=2">2</a>
86
+ # <a class="next" href="/index?pager=2">&gt;</a>
87
+ # <a class="last" href="/index?pager=2">&gt;&gt;</a>
88
+ # </div>
89
+ #
90
+ # Output with 5 elements, page 2, limit 3:
91
+ # <div class="pager" />
92
+ # <a class="first" href="/index?user_page=1">&lt;&lt;</a>
93
+ # <a class="previous" href="/index?user_page=1">&lt;</a>
94
+ # <a href="/index?user_page=1">1</a>
95
+ # <a class="current" href="/index?user_page=2">2</a>
96
+ # <span class="next grey">&gt;</span>
97
+ # <span class="last grey">&gt;&gt;</span>
98
+ # </div>
99
+
100
+
101
+ def navigation(limit = 8)
102
+ out = [ g.div(:class => :pager) ]
103
+
104
+ if first_page?
105
+ out << g.span(:class => 'first grey'){ h('<<') }
106
+ out << g.span(:class => 'previous grey'){ h('<') }
107
+ else
108
+ out << link(1, '<<', :class => :first)
109
+ out << link(prev_page, '<', :class => :previous)
110
+ end
111
+
112
+ lower = limit ? (current_page - limit) : 1
113
+ lower = lower < 1 ? 1 : lower
114
+
115
+ (lower...current_page).each do |n|
116
+ out << link(n)
117
+ end
118
+
119
+ out << link(current_page, current_page, :class => :current)
120
+
121
+ if last_page?
122
+ out << g.span(:class => 'next grey'){ h('>') }
123
+ out << g.span(:class => 'last grey'){ h('>>') }
124
+ elsif next_page
125
+ higher = limit ? (next_page + limit) : page_count
126
+ higher = [higher, page_count].min
127
+ (next_page..higher).each do |n|
128
+ out << link(n)
129
+ end
130
+
131
+ out << link(next_page, '>', :class => :next)
132
+ out << link(page_count, '>>', :class => :last)
133
+ end
134
+
135
+ out << '</div>'
136
+ out.map{|e| e.to_s}.join("\n")
137
+ end
138
+
139
+ # Useful to omit pager if it's of no use.
140
+
141
+ def needed?
142
+ @pager.page_count > 1
143
+ end
144
+
145
+ # Forward everything to the inner @pager
146
+
147
+ def method_missing(meth, *args, &block)
148
+ @pager.send(meth, *args, &block)
149
+ end
150
+
151
+ private
152
+
153
+ def pager_for(obj)
154
+ @page = @page < 1 ? 1 : @page
155
+
156
+ case obj
157
+ when Array
158
+ ArrayPager.new(obj, @page, @limit)
159
+ else
160
+ obj.paginate(@page, @limit)
161
+ end
162
+ end
163
+
164
+ def link(n, text = n, hash = {})
165
+ text = h(text.to_s)
166
+
167
+ params = Ramaze::Request.current.params.merge(@var.to_s => n)
168
+ name = Ramaze::Action.stack.first.name
169
+ name = '/' if name == 'index' # make nicer...
170
+ hash[:href] = Rs(name, params)
171
+
172
+ g.a(hash){ text }
173
+ end
174
+
175
+ def g
176
+ Ramaze::Gestalt.new
177
+ end
178
+
179
+ # Wrapper for Array to behave like the Sequel pagination
180
+
181
+ class ArrayPager
182
+ def initialize(array, page, limit)
183
+ @array, @page, @limit = array, page, limit
184
+ @page = page_count if @page > page_count
185
+ end
186
+
187
+ def size
188
+ @array.size
189
+ end
190
+
191
+ def empty?
192
+ @array.empty?
193
+ end
194
+
195
+ def page_count
196
+ pages, rest = @array.size.divmod(@limit)
197
+ rest == 0 ? pages : pages + 1
198
+ end
199
+
200
+ def current_page
201
+ @page
202
+ end
203
+
204
+ def next_page
205
+ page_count == @page ? nil : @page + 1
206
+ end
207
+
208
+ def prev_page
209
+ @page <= 1 ? nil : @page - 1
210
+ end
211
+
212
+ def first_page?
213
+ @page <= 1
214
+ end
215
+
216
+ def last_page?
217
+ page_count == @page
218
+ end
219
+
220
+ def each(&block)
221
+ from = ((@page - 1) * @limit)
222
+ to = from + @limit
223
+
224
+ a = @array[from...to] || []
225
+ a.each(&block)
226
+ end
227
+
228
+ include Enumerable
229
+ end
230
+
231
+ end
232
+ end
233
+ end
234
+ end