ramaze 2008.06 → 2008.11

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 (184) hide show
  1. data/README.markdown +6 -6
  2. data/Rakefile +33 -3
  3. data/bin/ramaze +18 -0
  4. data/doc/CHANGELOG +960 -0
  5. data/doc/LEGAL +5 -1
  6. data/doc/meta/announcement.txt +20 -36
  7. data/doc/tutorial/todolist.html +421 -313
  8. data/doc/tutorial/todolist.mkd +33 -16
  9. data/examples/app/blog/spec/blog.rb +3 -3
  10. data/examples/app/rapaste/controller/paste.rb +8 -1
  11. data/examples/app/rapaste/model/paste.rb +3 -0
  12. data/examples/app/rapaste/spec/rapaste.rb +3 -1
  13. data/examples/app/rapaste/start.rb +3 -2
  14. data/examples/app/sourceview/public/sourceview.js +2 -2
  15. data/examples/app/todolist/spec/todolist.rb +6 -6
  16. data/examples/app/todolist/template/index.xhtml +1 -1
  17. data/examples/app/whywiki/spec/whywiki.rb +2 -2
  18. data/examples/app/wikore/spec/wikore.rb +2 -2
  19. data/examples/app/wikore/src/model.rb +4 -3
  20. data/examples/app/wiktacular/spec/wiktacular.rb +7 -7
  21. data/examples/basic/simple.rb +2 -2
  22. data/examples/helpers/paginate.rb +71 -0
  23. data/examples/misc/simple_auth.rb +20 -8
  24. data/lib/proto/controller/init.rb +10 -0
  25. data/lib/proto/controller/main.rb +1 -3
  26. data/lib/proto/model/init.rb +4 -0
  27. data/lib/proto/public/dispatch.fcgi +1 -1
  28. data/lib/proto/spec/main.rb +2 -1
  29. data/lib/proto/start.rb +3 -3
  30. data/lib/proto/start.ru +1 -1
  31. data/lib/proto/view/error.xhtml +4 -4
  32. data/lib/ramaze.rb +8 -3
  33. data/lib/ramaze/action.rb +6 -6
  34. data/lib/ramaze/adapter.rb +1 -6
  35. data/lib/ramaze/adapter/base.rb +30 -27
  36. data/lib/ramaze/adapter/cgi.rb +1 -0
  37. data/lib/ramaze/cache.rb +1 -3
  38. data/lib/ramaze/cache/memcached.rb +3 -5
  39. data/lib/ramaze/contrib/auto_params.rb +2 -2
  40. data/lib/ramaze/contrib/auto_params/get_args.rb +2 -1
  41. data/lib/ramaze/contrib/gems.rb +17 -18
  42. data/lib/ramaze/contrib/gzip_filter.rb +22 -9
  43. data/lib/ramaze/contrib/maruku_uv.rb +59 -0
  44. data/lib/ramaze/contrib/profiling.rb +1 -1
  45. data/lib/ramaze/contrib/rest.rb +16 -13
  46. data/lib/ramaze/contrib/sequel/create_join.rb +25 -0
  47. data/lib/ramaze/contrib/sequel/form_field.rb +129 -0
  48. data/lib/ramaze/contrib/sequel/image.rb +198 -0
  49. data/lib/ramaze/contrib/sequel/relation.rb +82 -0
  50. data/lib/ramaze/controller.rb +33 -34
  51. data/lib/ramaze/controller/resolve.rb +29 -9
  52. data/lib/ramaze/current.rb +60 -20
  53. data/lib/ramaze/current/request.rb +8 -7
  54. data/lib/ramaze/current/response.rb +15 -3
  55. data/lib/ramaze/current/session/flash.rb +8 -0
  56. data/lib/ramaze/dispatcher.rb +17 -9
  57. data/lib/ramaze/dispatcher/action.rb +4 -5
  58. data/lib/ramaze/dispatcher/directory.rb +1 -1
  59. data/lib/ramaze/dispatcher/error.rb +4 -4
  60. data/lib/ramaze/dispatcher/file.rb +4 -4
  61. data/lib/ramaze/gestalt.rb +15 -20
  62. data/lib/ramaze/helper/cgi.rb +7 -15
  63. data/lib/ramaze/helper/formatting.rb +41 -1
  64. data/lib/ramaze/helper/httpdigest.rb +20 -7
  65. data/lib/ramaze/helper/link.rb +4 -6
  66. data/lib/ramaze/helper/paginate.rb +233 -0
  67. data/lib/ramaze/helper/redirect.rb +1 -1
  68. data/lib/ramaze/helper/rest.rb +1 -1
  69. data/lib/ramaze/helper/thread.rb +17 -0
  70. data/lib/ramaze/helper/ultraviolet.rb +44 -0
  71. data/lib/ramaze/helper/user.rb +4 -9
  72. data/lib/ramaze/log.rb +2 -2
  73. data/lib/ramaze/log/analogger.rb +21 -23
  74. data/lib/ramaze/log/growl.rb +21 -23
  75. data/lib/ramaze/log/hub.rb +1 -1
  76. data/lib/ramaze/log/informer.rb +97 -99
  77. data/lib/ramaze/log/knotify.rb +14 -16
  78. data/lib/ramaze/log/logger.rb +11 -13
  79. data/lib/ramaze/log/logging.rb +61 -63
  80. data/lib/ramaze/log/rotatinginformer.rb +168 -0
  81. data/lib/ramaze/log/syslog.rb +41 -31
  82. data/lib/ramaze/log/xosd.rb +70 -72
  83. data/lib/ramaze/option.rb +9 -6
  84. data/lib/ramaze/option/holder.rb +5 -27
  85. data/lib/ramaze/reloader.rb +186 -0
  86. data/lib/ramaze/setup.rb +1 -1
  87. data/lib/ramaze/snippets.rb +13 -0
  88. data/lib/ramaze/snippets/array/put_within.rb +31 -24
  89. data/lib/ramaze/snippets/binding/locals.rb +23 -11
  90. data/lib/ramaze/snippets/dictionary.rb +2 -2
  91. data/lib/ramaze/snippets/fiber.rb +63 -0
  92. data/lib/ramaze/snippets/kernel/constant.rb +36 -21
  93. data/lib/ramaze/snippets/kernel/pretty_inspect.rb +12 -6
  94. data/lib/ramaze/snippets/numeric/filesize_format.rb +24 -17
  95. data/lib/ramaze/snippets/numeric/time.rb +63 -0
  96. data/lib/ramaze/snippets/object/__dir__.rb +29 -0
  97. data/lib/ramaze/snippets/object/acquire.rb +40 -0
  98. data/lib/ramaze/snippets/object/instance_variable_defined.rb +16 -5
  99. data/lib/ramaze/snippets/object/pretty.rb +14 -4
  100. data/lib/ramaze/snippets/object/scope.rb +14 -7
  101. data/lib/ramaze/snippets/ordered_set.rb +25 -14
  102. data/lib/ramaze/snippets/proc/locals.rb +17 -9
  103. data/lib/ramaze/snippets/ramaze/deprecated.rb +13 -0
  104. data/lib/ramaze/snippets/ramaze/fiber.rb +24 -0
  105. data/lib/ramaze/snippets/ramaze/state.rb +86 -0
  106. data/lib/ramaze/snippets/ramaze/struct.rb +45 -0
  107. data/lib/ramaze/snippets/string/camel_case.rb +13 -8
  108. data/lib/ramaze/snippets/string/color.rb +24 -20
  109. data/lib/ramaze/snippets/string/each.rb +14 -3
  110. data/lib/ramaze/snippets/string/end_with.rb +20 -0
  111. data/lib/ramaze/snippets/string/esc.rb +26 -21
  112. data/lib/ramaze/snippets/string/ord.rb +12 -6
  113. data/lib/ramaze/snippets/string/snake_case.rb +13 -7
  114. data/lib/ramaze/snippets/string/start_with.rb +16 -5
  115. data/lib/ramaze/snippets/string/unindent.rb +23 -15
  116. data/lib/ramaze/snippets/thread/into.rb +3 -3
  117. data/lib/ramaze/spec/helper/bacon.rb +5 -5
  118. data/lib/ramaze/spec/helper/mock_http.rb +1 -1
  119. data/lib/ramaze/spec/helper/pretty_output.rb +2 -2
  120. data/lib/ramaze/spec/helper/snippets.rb +8 -0
  121. data/lib/ramaze/template.rb +4 -1
  122. data/lib/ramaze/template/ezamar/textpow.syntax +34 -0
  123. data/lib/ramaze/template/maruku.rb +34 -0
  124. data/lib/ramaze/template/tagz.rb +2 -2
  125. data/lib/ramaze/template/xslt.rb +2 -2
  126. data/lib/ramaze/tool/create.rb +27 -53
  127. data/lib/ramaze/tool/localize.rb +8 -4
  128. data/lib/ramaze/tool/mime.rb +11 -1
  129. data/lib/ramaze/tool/project_creator.rb +110 -0
  130. data/lib/ramaze/trinity.rb +4 -1
  131. data/lib/ramaze/version.rb +1 -1
  132. data/lib/vendor/bacon.rb +323 -0
  133. data/rake_tasks/gem.rake +10 -1
  134. data/rake_tasks/maintenance.rake +40 -2
  135. data/rake_tasks/metric.rake +24 -0
  136. data/rake_tasks/release.rake +17 -4
  137. data/rake_tasks/spec.rake +1 -2
  138. data/ramaze.gemspec +549 -495
  139. data/spec/contrib/auto_params.rb +3 -3
  140. data/spec/contrib/profiling.rb +2 -2
  141. data/spec/examples/simple_auth.rb +2 -2
  142. data/spec/examples/templates/template_haml.rb +0 -2
  143. data/spec/ramaze/action/file_cache.rb +22 -0
  144. data/spec/ramaze/adapter.rb +2 -2
  145. data/spec/ramaze/controller/actionless_templates.rb +1 -1
  146. data/spec/ramaze/controller/subclass.rb +15 -0
  147. data/spec/ramaze/controller/template_resolving.rb +1 -1
  148. data/spec/ramaze/controller/view/bar.xhtml +1 -0
  149. data/spec/ramaze/controller/view/base/another.xhtml +1 -0
  150. data/spec/ramaze/current/session.rb +1 -1
  151. data/spec/ramaze/dispatcher/file.rb +2 -2
  152. data/spec/ramaze/helper/aspect.rb +26 -17
  153. data/spec/ramaze/helper/formatting.rb +13 -0
  154. data/spec/ramaze/log/informer.rb +10 -10
  155. data/spec/ramaze/log/syslog.rb +67 -4
  156. data/spec/ramaze/rewrite.rb +1 -1
  157. data/spec/ramaze/route.rb +1 -1
  158. data/spec/ramaze/struct.rb +47 -0
  159. data/spec/ramaze/template/markaby.rb +1 -1
  160. data/spec/ramaze/template/tagz.rb +1 -1
  161. data/spec/snippets/binding/locals.rb +9 -0
  162. data/spec/snippets/numeric/time.rb +12 -0
  163. data/spec/snippets/{kernel → object}/__dir__.rb +0 -0
  164. data/spec/snippets/{kernel → object}/acquire.rb +0 -0
  165. metadata +90 -81
  166. data/cache.yaml +0 -7
  167. data/examples/app/rammit/spec/rammit.rb +0 -31
  168. data/examples/app/rammit/src/controller/main.rb +0 -3
  169. data/examples/app/rammit/src/controller/page.rb +0 -16
  170. data/examples/app/rammit/src/model.rb +0 -33
  171. data/examples/app/rammit/start.rb +0 -8
  172. data/examples/app/rammit/template/index.xhtml +0 -14
  173. data/examples/app/rammit/template/page/view.xhtml +0 -4
  174. data/lib/ramaze/snippets/kernel/__dir__.rb +0 -23
  175. data/lib/ramaze/snippets/kernel/acquire.rb +0 -34
  176. data/lib/ramaze/snippets/object/thread_accessor.rb +0 -5
  177. data/lib/ramaze/snippets/ramaze/thread_accessor.rb +0 -58
  178. data/lib/ramaze/snippets/struct/fill.rb +0 -23
  179. data/lib/ramaze/snippets/struct/values_at.rb +0 -39
  180. data/lib/ramaze/snippets/symbol/to_proc.rb +0 -24
  181. data/lib/ramaze/sourcereload.rb +0 -176
  182. data/spec/snippets/struct/fill.rb +0 -26
  183. data/spec/snippets/struct/values_at.rb +0 -52
  184. data/spec/snippets/symbol/to_proc.rb +0 -13
@@ -95,16 +95,6 @@ module Ramaze
95
95
  ].find{|path| File.directory?(path) } || @view_root
96
96
  end
97
97
 
98
- def template_root=(tr)
99
- Ramaze::deprecated "Global.template_root=", "Global.view_root="
100
- self.view_root = tr
101
- end
102
-
103
- def template_root
104
- Ramaze::deprecated "Global.template_root", "Global.view_root"
105
- self.view_root
106
- end
107
-
108
98
  def adapter
109
99
  find_from_aliases(@adapter, :adapter_aliases, Ramaze::Adapter, "ramaze/adapter")
110
100
  end
@@ -114,17 +104,7 @@ module Ramaze
114
104
  end
115
105
 
116
106
  def sourcereload=(interval)
117
- if interval
118
- if interval.is_a?(Numeric)
119
- @sourcereload = interval
120
- Ramaze::SourceReload.restart
121
- else
122
- Log.warn("sourcereload= %p not Numeric, ignoring." % interval)
123
- end
124
- else
125
- @sourcereload = interval
126
- Ramaze::SourceReload.shutdown
127
- end
107
+ Ramaze::Reloader::OPTIONS[:cooldown] = interval
128
108
  end
129
109
 
130
110
  private
@@ -133,17 +113,15 @@ module Ramaze
133
113
  case name
134
114
  when String, Symbol
135
115
  name = name.to_s
136
- name = self[alias_key][name] || name
137
- find_require(name, mod, path)
116
+ class_name = self[alias_key][name] || name
117
+ find_require(name, class_name, mod, path)
138
118
  else
139
119
  name
140
120
  end
141
121
  end
142
122
 
143
- def find_require(name, mod, path)
144
- class_name = name.to_s
145
- file_path = File.join(path, class_name.downcase)
146
-
123
+ def find_require(name, class_name, mod, path)
124
+ file_path = File.join(path, name)
147
125
  require(file_path) unless mod.const_defined?(class_name)
148
126
 
149
127
  mod.const_get(class_name)
@@ -0,0 +1,186 @@
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
+ module Ramaze
5
+
6
+ # High performant source reloader
7
+ #
8
+ # This class acts as Rack middleware.
9
+ #
10
+ # It does not depend on Ramaze itself, but you might have to adjust the
11
+ # Reloader::Hooks module or include your own module to override the hooks.
12
+ # You also might have to set the Log constant.
13
+ #
14
+ # What makes it especially suited for use in a production environment is that
15
+ # any file will only be checked once and there will only be made one system
16
+ # call stat(2).
17
+ #
18
+ # Please note that this will not reload files in the background, it does so
19
+ # only when actively called
20
+ # In case of Ramaze it is performing a check/reload cycle at the start of
21
+ # every request, but also respects a cool down time, during which nothing will
22
+ # be done.
23
+ #
24
+ # After every reload the OPTIONS hash will be checked for changed options and
25
+ # assigned to the instance, so you may change options during the lifetime of
26
+ # your application.
27
+ #
28
+ # A number of hooks will be executed during the reload cycle, see
29
+ # Ramaze::ReloaderHooks for more information.
30
+
31
+ class Reloader
32
+ OPTIONS = {
33
+ # At most check every n seconds
34
+ # nil/false will never trigger the reload cycle
35
+ # 0 will cycle on every call
36
+ :cooldown => 2,
37
+
38
+ # Compiled files cannot be reloaded during runtime
39
+ :ignore => /\.so$/,
40
+
41
+ # Run cycle in a Thread.exclusive, by default no threads are used.
42
+ :thread => false,
43
+
44
+ # If you assign a block here it will be instance_evaled instead of
45
+ # calling cycle. This allows you to use for example EventMachine for
46
+ # well performing asynchronous cycling.
47
+ :control => nil, # lambda{ cycle },
48
+ }
49
+
50
+ def initialize(app)
51
+ @app = app
52
+ @last = Time.now
53
+ @mtimes = {}
54
+ @cache = {}
55
+ options_reload
56
+ end
57
+
58
+ def options_reload
59
+ @cooldown, @ignore, @control, @thread =
60
+ OPTIONS.values_at(:cooldown, :ignore, :control, :thread)
61
+ end
62
+
63
+ def call(env)
64
+ options_reload
65
+
66
+ if @cooldown and Time.now > @last + @cooldown
67
+ if @control
68
+ instance_eval(&@control)
69
+ elsif @thread
70
+ Thread.exclusive{ cycle }
71
+ else
72
+ cycle
73
+ end
74
+
75
+ @last = Time.now
76
+ end
77
+
78
+ @app.call(env)
79
+ end
80
+
81
+ def cycle
82
+ before_cycle
83
+
84
+ rotation do |file, stat|
85
+ if mtime = stat.mtime
86
+ if mtime > (@mtimes[file] ||= mtime)
87
+ safe_load(file)
88
+ @mtimes[file] = mtime
89
+ end
90
+ else
91
+ @cache.delete(file)
92
+ end
93
+ end
94
+
95
+ after_cycle
96
+ end
97
+
98
+ # A safe Kernel::load, issuing the hooks depending on the results
99
+ def safe_load(file)
100
+ before_safe_load(file)
101
+ load(file)
102
+ after_safe_load_succeed(file)
103
+ rescue Object => ex
104
+ Log.error(ex)
105
+ after_safe_load_failed(file, ex)
106
+ end
107
+
108
+ def rotation
109
+ files = [$0, __FILE__, *$LOADED_FEATURES].uniq
110
+ paths = ['./', *$LOAD_PATH].uniq
111
+
112
+ files.each do |file|
113
+ next if file =~ @ignore
114
+ path, stat = figure_path(file, paths)
115
+
116
+ if path and stat
117
+ @cache[file] = path
118
+ yield(path, stat)
119
+ else
120
+ # Quite harmless, we just couldn't figure out path for #{file}
121
+ end
122
+ end
123
+ end
124
+
125
+ def figure_path(file, paths)
126
+ if cached = @cache[file]
127
+ stat = File.stat(cached)
128
+ return cached, stat if stat.file?
129
+ elsif Pathname.new(file).absolute?
130
+ stat = File.stat(file)
131
+ return file, stat if stat.file? # do directories really end up in $" ?
132
+ end
133
+
134
+ paths.each do |possible_path|
135
+ path = File.join(possible_path, file)
136
+
137
+ begin
138
+ stat = File.stat(path)
139
+ return path, stat if stat.file?
140
+ rescue Errno::ENOENT, Errno::ENOTDIR
141
+ end
142
+ end
143
+
144
+ return nil
145
+ end
146
+
147
+
148
+ # Holds hooks that are called before and after #cycle and #safe_load
149
+ module Hooks
150
+ # Overwrite to add actions before the reload rotation is started.
151
+ def before_cycle
152
+ end
153
+
154
+ # Overwrite to add actions after the reload rotation has ended.
155
+ def after_cycle
156
+ end
157
+
158
+ # Overwrite to add actions before a file is Kernel::load-ed
159
+ def before_safe_load(file)
160
+ Log.debug("reload #{file}")
161
+ end
162
+
163
+ # Overwrite to add actions after a file is Kernel::load-ed successfully,
164
+ # by default we clean the Cache for compiled templates and resolved actions.
165
+ def after_safe_load_succeed(file)
166
+ Ramaze::Cache.compiled.clear
167
+ Ramaze::Cache.resolved.clear
168
+ Ramaze::Cache.action_methods.clear
169
+ after_safe_load(file)
170
+ end
171
+
172
+ # Overwrite to add custom hook in addition to default Cache cleaning
173
+ def after_safe_load(file)
174
+ end
175
+
176
+ # Overwrite to add actions after a file is Kernel::load-ed unsuccessfully,
177
+ # by default we output an error-message with the exception.
178
+ def after_safe_load_failed(file, error)
179
+ Log.error(error)
180
+ end
181
+ end
182
+
183
+ include Hooks
184
+
185
+ end
186
+ end
@@ -24,7 +24,7 @@ module Ramaze
24
24
 
25
25
  # Shortcut if you don't need specific versions but tons of gems
26
26
  def gems(*args)
27
- gems.each{|g| gem(g) }
27
+ args.each{|g| gem(g) }
28
28
  end
29
29
 
30
30
  def global(hash = nil)
@@ -7,3 +7,16 @@ glob = File.join(dir, '**', '*.rb')
7
7
  Dir[glob].each do |snippet|
8
8
  require(snippet)
9
9
  end
10
+
11
+ Ramaze::CoreExtensions.constants.each do |const|
12
+ ext = Ramaze::CoreExtensions.const_get(const)
13
+ into = Module.const_get(const)
14
+
15
+ collisions = ext.instance_methods & into.instance_methods
16
+
17
+ if collisions.empty?
18
+ into.__send__(:include, ext)
19
+ else
20
+ warn "Won't include %p with %p, %p exists" % [into, ext, collisions]
21
+ end
22
+ end
@@ -1,37 +1,44 @@
1
1
  # Copyright (c) 2008 Michael Fellinger m.fellinger@gmail.com
2
2
  # All files in this distribution are subject to the terms of the Ruby license.
3
3
 
4
- class Array
4
+ module Ramaze
5
+ module CoreExtensions
5
6
 
6
- # a = [1, 2, 3]
7
- # a.put_within(4, :after => 2, :before => 3)
8
- # a # => [1, 2, 4, 3]
7
+ # Extensions for Array
9
8
 
10
- def put_within(object, constrain)
11
- pre, post = constrain.values_at(:after, :before)
9
+ module Array
12
10
 
13
- unless rindex(post) - index(pre) == 1
14
- raise ArgumentError, "Too many elements within constrain"
15
- end
11
+ # a = [1, 2, 3]
12
+ # a.put_within(4, :after => 2, :before => 3)
13
+ # a # => [1, 2, 4, 3]
16
14
 
17
- put_after(pre, object)
18
- end
15
+ def put_within(object, constrain)
16
+ pre, post = constrain.values_at(:after, :before)
19
17
 
20
- # a = [1, 2, 3]
21
- # a.put_after(2, 4)
22
- # a # => [1, 2, 4, 3]
18
+ return put_after(pre, object) if rindex(post) - index(pre) == 1
23
19
 
24
- def put_after(element, object)
25
- raise ArgumentError, "The given element doesn't exist" unless include?(element)
26
- self[index(element) + 1, 0] = object
27
- end
20
+ raise ArgumentError, "Too many elements within constrain"
21
+ end
22
+
23
+ # a = [1, 2, 3]
24
+ # a.put_after(2, 4)
25
+ # a # => [1, 2, 4, 3]
28
26
 
29
- # a = [1, 2, 3]
30
- # a.put_before(2, 4)
31
- # a # => [1, 4, 2, 3]
27
+ def put_after(element, object)
28
+ return self[index(element) + 1, 0] = object if include?(element)
32
29
 
33
- def put_before(element, object)
34
- raise ArgumentError, "The given element doesn't exist" unless include?(element)
35
- self[rindex(element), 0] = object
30
+ raise ArgumentError, "The given element doesn't exist"
31
+ end
32
+
33
+ # a = [1, 2, 3]
34
+ # a.put_before(2, 4)
35
+ # a # => [1, 4, 2, 3]
36
+
37
+ def put_before(element, object)
38
+ return self[rindex(element), 0] = object if include?(element)
39
+
40
+ raise ArgumentError, "The given element doesn't exist"
41
+ end
42
+ end
36
43
  end
37
44
  end
@@ -1,13 +1,25 @@
1
- class Binding
2
-
3
- # returns a hash of localvar/localvar-values from binding, useful for
4
- # template engines that do not accept bindings and force passing locals via
5
- # hash
6
- # usage: x = 42; p binding.locals #=> {'x'=> 42}
7
- def locals
8
- Kernel::eval '
9
- local_variables.inject({}){|h,v| h.update v => eval(v)}
10
- ', self
11
- end
1
+ module Ramaze
2
+ module CoreExtensions
3
+
4
+ # Extensions for Binding
5
+
6
+ module Binding
12
7
 
8
+ # Returns a hash of localvar/localvar-values from binding, useful for
9
+ # template engines that do not accept bindings and force passing locals
10
+ # via hash
11
+ #
12
+ # Usage:
13
+ # x = 42; p binding.locals #=> {'x'=> 42}
14
+
15
+ def locals
16
+ ::Kernel::eval '
17
+ local_variables.inject({}){|h,v|
18
+ k = v.to_s
19
+ h.merge!(k => eval(k))
20
+ }', self
21
+ end
22
+
23
+ end
24
+ end
13
25
  end
@@ -362,7 +362,7 @@ module Ramaze
362
362
  reorder
363
363
  self
364
364
  end
365
- alias :merge! update
365
+ alias merge! update
366
366
 
367
367
  def merge( hsh2 )
368
368
  self.dup.update(hsh2)
@@ -390,7 +390,7 @@ module Ramaze
390
390
  def length
391
391
  @order.length
392
392
  end
393
- alias :size :length
393
+ alias size length
394
394
 
395
395
  def empty?
396
396
  @hash.empty?
@@ -0,0 +1,63 @@
1
+ unless defined? Fiber
2
+ require 'thread'
3
+
4
+ class FiberError < StandardError; end
5
+
6
+ class Fiber
7
+ def initialize
8
+ raise ArgumentError, 'new Fiber requires a block' unless block_given?
9
+
10
+ @yield = Queue.new
11
+ @resume = Queue.new
12
+
13
+ @thread = Thread.new{ @yield.push [*yield(*wait)] }
14
+ @thread.abort_on_exception = true
15
+ @thread[:fiber] = self
16
+ end
17
+ attr_reader :yield, :thread
18
+
19
+ def resume *args
20
+ raise FiberError, 'dead fiber called' unless @thread.alive?
21
+ @resume.push(args)
22
+ result = @yield.pop
23
+ result.size > 1 ? result : result.first
24
+ end
25
+
26
+ def wait
27
+ @resume.pop
28
+ end
29
+
30
+ def self.yield *args
31
+ raise FiberError, "can't yield from root fiber" unless fiber = Thread.current[:fiber]
32
+ fiber.yield.push(args)
33
+ result = fiber.wait
34
+ result.size > 1 ? result : result.first
35
+ end
36
+
37
+ def inspect
38
+ "#<#{self.class}:0x#{self.object_id.to_s(16)}>"
39
+ end
40
+ end
41
+ end
42
+
43
+ if __FILE__ == $0
44
+ f = Fiber.new{ puts 'hi'; p Fiber.yield(1); puts 'bye'; :done }
45
+ p f.resume
46
+ p f.resume(2)
47
+ end
48
+
49
+ __END__
50
+
51
+ $ ruby fbr.rb
52
+ hi
53
+ 1
54
+ 2
55
+ bye
56
+ :done
57
+
58
+ $ ruby1.9 fbr.rb
59
+ hi
60
+ 1
61
+ 2
62
+ bye
63
+ :done