ramaze 2008.06 → 2008.11

Sign up to get free protection for your applications and to get access to all the features.
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