ramaze 0.0.7 → 0.0.8

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 (193) hide show
  1. data/Rakefile +52 -19
  2. data/bin/ramaze +19 -6
  3. data/doc/CHANGELOG +33 -0
  4. data/doc/COPYING +1 -1
  5. data/doc/FAQ +92 -0
  6. data/doc/GPL +340 -0
  7. data/doc/INSTALL +34 -0
  8. data/doc/ProjectInfo +53 -0
  9. data/doc/README +187 -110
  10. data/doc/readme_chunks/appendix.txt +13 -0
  11. data/doc/readme_chunks/examples.txt +38 -0
  12. data/doc/readme_chunks/features.txt +82 -0
  13. data/doc/readme_chunks/getting_help.txt +5 -0
  14. data/doc/readme_chunks/getting_started.txt +18 -0
  15. data/doc/readme_chunks/installing.txt +41 -0
  16. data/doc/readme_chunks/introduction.txt +18 -0
  17. data/doc/readme_chunks/principles.txt +41 -0
  18. data/doc/readme_chunks/thanks.txt +59 -0
  19. data/doc/tutorial/todolist.txt +546 -0
  20. data/examples/blog/main.rb +1 -1
  21. data/examples/blog/src/controller.rb +13 -11
  22. data/examples/blog/src/element.rb +11 -6
  23. data/examples/blog/src/model.rb +8 -23
  24. data/examples/blog/template/edit.xhtml +3 -1
  25. data/examples/blog/template/index.xhtml +4 -4
  26. data/examples/caching.rb +4 -4
  27. data/examples/element.rb +10 -7
  28. data/examples/hello.rb +3 -4
  29. data/examples/simple.rb +5 -3
  30. data/examples/templates/template/external.amrita +19 -0
  31. data/examples/templates/template/{external.rmze → external.zmr} +2 -2
  32. data/examples/templates/template_amrita2.rb +48 -0
  33. data/examples/templates/template_erubis.rb +5 -2
  34. data/examples/templates/{template_ramaze.rb → template_ezamar.rb} +13 -7
  35. data/examples/templates/template_haml.rb +4 -1
  36. data/examples/templates/template_liquid.rb +2 -1
  37. data/examples/templates/template_markaby.rb +2 -1
  38. data/examples/todolist/conf/benchmark.yaml +35 -0
  39. data/examples/todolist/conf/debug.yaml +34 -0
  40. data/examples/todolist/conf/live.yaml +33 -0
  41. data/examples/todolist/conf/silent.yaml +31 -0
  42. data/examples/todolist/conf/stage.yaml +33 -0
  43. data/examples/todolist/main.rb +18 -0
  44. data/examples/todolist/public/404.jpg +0 -0
  45. data/examples/todolist/public/css/coderay.css +105 -0
  46. data/examples/todolist/public/css/ramaze_error.css +42 -0
  47. data/{lib/proto → examples/todolist}/public/error.xhtml +0 -0
  48. data/examples/todolist/public/favicon.ico +0 -0
  49. data/examples/todolist/public/js/jquery.js +1923 -0
  50. data/examples/todolist/public/ramaze.png +0 -0
  51. data/examples/todolist/src/controller/main.rb +56 -0
  52. data/examples/todolist/src/element/page.rb +26 -0
  53. data/examples/todolist/src/model.rb +14 -0
  54. data/examples/todolist/template/index.xhtml +17 -0
  55. data/examples/todolist/template/new.xhtml +7 -0
  56. data/examples/todolist/todolist.db +9 -0
  57. data/examples/whywiki/main.rb +3 -8
  58. data/examples/whywiki/template/show.xhtml +4 -0
  59. data/lib/proto/public/error.zmr +77 -0
  60. data/lib/proto/src/controller/main.rb +2 -1
  61. data/lib/proto/src/element/page.rb +2 -1
  62. data/lib/proto/src/model.rb +3 -2
  63. data/lib/ramaze.rb +7 -9
  64. data/lib/ramaze/adapter.rb +51 -0
  65. data/lib/ramaze/adapter/cgi.rb +23 -0
  66. data/lib/ramaze/adapter/fcgi.rb +22 -0
  67. data/lib/ramaze/adapter/mongrel.rb +7 -86
  68. data/lib/ramaze/adapter/webrick.rb +14 -133
  69. data/lib/ramaze/cache/memcached.rb +6 -0
  70. data/lib/ramaze/cache/yaml_store.rb +3 -1
  71. data/lib/ramaze/controller.rb +292 -2
  72. data/lib/ramaze/dispatcher.rb +85 -213
  73. data/lib/ramaze/error.rb +10 -0
  74. data/lib/ramaze/global.rb +8 -0
  75. data/lib/ramaze/helper/aspect.rb +30 -7
  76. data/lib/ramaze/helper/auth.rb +16 -9
  77. data/lib/ramaze/helper/cache.rb +40 -35
  78. data/lib/ramaze/helper/feed.rb +1 -1
  79. data/lib/ramaze/helper/flash.rb +34 -0
  80. data/lib/ramaze/helper/link.rb +8 -2
  81. data/lib/ramaze/helper/openid.rb +63 -0
  82. data/lib/ramaze/helper/redirect.rb +12 -11
  83. data/lib/ramaze/helper/stack.rb +5 -7
  84. data/lib/ramaze/inform.rb +12 -1
  85. data/lib/ramaze/snippets/kernel/aquire.rb +1 -1
  86. data/lib/ramaze/snippets/kernel/{self_method.rb → method.rb} +3 -18
  87. data/lib/ramaze/snippets/kernel/{rescue_require.rb → pretty_inspect.rb} +7 -6
  88. data/lib/ramaze/snippets/method/name.rb +22 -0
  89. data/lib/ramaze/snippets/{kernel → ramaze}/autoreload.rb +0 -0
  90. data/lib/ramaze/snippets/ramaze/caller_info.rb +14 -0
  91. data/lib/ramaze/snippets/{kernel → ramaze}/caller_lines.rb +3 -10
  92. data/lib/ramaze/snippets/rdoc/usage_no_exit.rb +49 -23
  93. data/lib/ramaze/snippets/string/DIVIDE.rb +0 -1
  94. data/lib/ramaze/store/default.rb +58 -2
  95. data/lib/ramaze/store/yaml.rb +161 -0
  96. data/lib/ramaze/template.rb +27 -86
  97. data/lib/ramaze/template/amrita2.rb +14 -19
  98. data/lib/ramaze/template/erubis.rb +15 -38
  99. data/lib/ramaze/template/ezamar.rb +100 -0
  100. data/lib/ramaze/template/ezamar/element.rb +166 -0
  101. data/lib/ramaze/template/ezamar/engine.rb +124 -0
  102. data/lib/ramaze/template/ezamar/morpher.rb +155 -0
  103. data/lib/ramaze/template/haml.rb +16 -43
  104. data/lib/ramaze/template/liquid.rb +11 -51
  105. data/lib/ramaze/template/markaby.rb +44 -42
  106. data/lib/ramaze/tool/mime.rb +18 -0
  107. data/lib/ramaze/tool/mime_types.yaml +615 -0
  108. data/lib/ramaze/trinity/request.rb +20 -196
  109. data/lib/ramaze/trinity/response.rb +4 -33
  110. data/lib/ramaze/trinity/session.rb +150 -72
  111. data/lib/ramaze/version.rb +1 -1
  112. data/spec/adapter_spec.rb +20 -0
  113. data/spec/public/favicon.ico +0 -0
  114. data/spec/public/ramaze.png +0 -0
  115. data/spec/public/test_download.css +141 -0
  116. data/spec/{tc_request.rb → request_tc_helper.rb} +45 -21
  117. data/spec/spec_all.rb +77 -34
  118. data/spec/spec_helper.rb +8 -157
  119. data/spec/spec_helper_context.rb +72 -0
  120. data/spec/spec_helper_requester.rb +52 -0
  121. data/spec/spec_helper_simple_http.rb +433 -0
  122. data/spec/tc_adapter_mongrel.rb +3 -15
  123. data/spec/tc_adapter_webrick.rb +4 -14
  124. data/spec/tc_cache.rb +3 -5
  125. data/spec/tc_controller.rb +22 -12
  126. data/spec/tc_dependencies.rb +13 -0
  127. data/spec/tc_element.rb +8 -7
  128. data/spec/tc_error.rb +13 -7
  129. data/spec/tc_global.rb +16 -18
  130. data/spec/tc_helper_aspect.rb +2 -4
  131. data/spec/tc_helper_auth.rb +15 -14
  132. data/spec/tc_helper_cache.rb +5 -7
  133. data/spec/tc_helper_feed.rb +0 -2
  134. data/spec/tc_helper_flash.rb +103 -0
  135. data/spec/tc_helper_form.rb +4 -6
  136. data/spec/tc_helper_link.rb +1 -3
  137. data/spec/tc_helper_redirect.rb +23 -8
  138. data/spec/tc_helper_stack.rb +31 -15
  139. data/spec/tc_morpher.rb +1 -3
  140. data/spec/tc_params.rb +48 -7
  141. data/spec/tc_request_mongrel.rb +9 -0
  142. data/spec/tc_request_webrick.rb +5 -0
  143. data/spec/tc_session.rb +41 -25
  144. data/spec/tc_store.rb +55 -6
  145. data/spec/tc_store_yaml.rb +71 -0
  146. data/spec/tc_template_amrita2.rb +3 -3
  147. data/spec/tc_template_erubis.rb +2 -3
  148. data/spec/{tc_template_ramaze.rb → tc_template_ezamar.rb} +15 -5
  149. data/spec/tc_template_haml.rb +4 -3
  150. data/spec/tc_template_liquid.rb +3 -4
  151. data/spec/tc_template_markaby.rb +4 -6
  152. data/spec/tc_tidy.rb +1 -3
  153. data/spec/template/amrita2/{data.html → data.amrita} +0 -0
  154. data/spec/template/amrita2/{index.html → index.amrita} +0 -0
  155. data/spec/template/amrita2/{sum.html → sum.amrita} +0 -0
  156. data/spec/template/ezamar/another/long/action.zmr +1 -0
  157. data/spec/template/ezamar/combined.zmr +1 -0
  158. data/spec/template/{ramaze/file_only.rmze → ezamar/file_only.zmr} +0 -0
  159. data/spec/template/{ramaze/index.rmze → ezamar/index.zmr} +0 -0
  160. data/spec/template/{ramaze/nested.rmze → ezamar/nested.zmr} +0 -0
  161. data/spec/template/ezamar/some__long__action.zmr +1 -0
  162. data/spec/template/{ramaze/sum.rmze → ezamar/sum.zmr} +0 -0
  163. metadata +181 -123
  164. data/doc/allison/LICENSE +0 -184
  165. data/doc/allison/README +0 -37
  166. data/doc/allison/allison.css +0 -300
  167. data/doc/allison/allison.gif +0 -0
  168. data/doc/allison/allison.js +0 -307
  169. data/doc/allison/allison.rb +0 -287
  170. data/doc/allison/cache/BODY +0 -588
  171. data/doc/allison/cache/CLASS_INDEX +0 -4
  172. data/doc/allison/cache/CLASS_PAGE +0 -1
  173. data/doc/allison/cache/FILE_INDEX +0 -4
  174. data/doc/allison/cache/FILE_PAGE +0 -1
  175. data/doc/allison/cache/FONTS +0 -1
  176. data/doc/allison/cache/FR_INDEX_BODY +0 -1
  177. data/doc/allison/cache/IMGPATH +0 -1
  178. data/doc/allison/cache/INDEX +0 -1
  179. data/doc/allison/cache/JAVASCRIPT +0 -307
  180. data/doc/allison/cache/METHOD_INDEX +0 -4
  181. data/doc/allison/cache/METHOD_LIST +0 -1
  182. data/doc/allison/cache/SRC_PAGE +0 -1
  183. data/doc/allison/cache/STYLE +0 -322
  184. data/doc/allison/cache/URL +0 -1
  185. data/doc/changes.txt +0 -2021
  186. data/doc/changes.xml +0 -2024
  187. data/lib/ramaze/snippets/kernel/silently.rb +0 -13
  188. data/lib/ramaze/snippets/thread/deadQUESTIONMARK.rb +0 -11
  189. data/lib/ramaze/template/haml/actionview_stub.rb +0 -20
  190. data/lib/ramaze/template/ramaze.rb +0 -177
  191. data/lib/ramaze/template/ramaze/element.rb +0 -166
  192. data/lib/ramaze/template/ramaze/morpher.rb +0 -156
  193. data/spec/tc_test.rb +0 -17
@@ -14,7 +14,7 @@ module Kernel
14
14
  require file if %w(rb so).any?{|f| File.file?("#{file}.#{f}")}
15
15
  $:.each do |path|
16
16
  Dir[File.join(path, file, '*.rb')].each do |file|
17
- require file
17
+ require file unless file == File.expand_path(__FILE__)
18
18
  end
19
19
  end
20
20
  end
@@ -1,6 +1,9 @@
1
1
  # Copyright (c) 2006 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
+ # This chunk of code redefines the #method method of Kernel to act more
5
+ # dynamic.
6
+
4
7
  module Kernel
5
8
  alias_method :method_get, :method unless defined? method_get
6
9
 
@@ -21,21 +24,3 @@ module Kernel
21
24
  method_get caller.to_s.scan(/`(.*?)'/)[n].first rescue nil
22
25
  end
23
26
  end
24
-
25
- class Method
26
-
27
- # name of the Method (example shows combination with the new Kernel#method)
28
- #
29
- # class Foo
30
- # def bar
31
- # method.name
32
- # end
33
- # end
34
- #
35
- # Foo.new.bar #=> 'bar'
36
-
37
- def name
38
- #<Method: A.d>
39
- inspect.gsub(/#<Method: .*?[\.#](.*?)>/, '\1')
40
- end
41
- end
@@ -1,12 +1,13 @@
1
1
  # Copyright (c) 2006 Michael Fellinger m.fellinger@gmail.com
2
2
  # All files in this distribution are subject to the terms of the Ruby license.
3
- module Kernel
4
3
 
5
- # try to require a file, output message if it failes.
4
+ require 'pp'
6
5
 
7
- def rescue_require(sym, message = nil)
8
- require sym
9
- rescue LoadError, RuntimeError
10
- puts message if message
6
+ module Kernel
7
+ unless defined?(pretty_inspect)
8
+ # returns a pretty printed object as a string.
9
+ def pretty_inspect
10
+ PP.pp(self, '')
11
+ end
11
12
  end
12
13
  end
@@ -0,0 +1,22 @@
1
+ # Copyright (c) 2006 Michael Fellinger m.fellinger@gmail.com
2
+ # All files in this distribution are subject to the terms of the Ruby license.
3
+
4
+ # Modification for upcoming functionality in 1.9
5
+
6
+ class Method
7
+
8
+ # name of the Method (example shows combination with the new Kernel#method)
9
+ #
10
+ # class Foo
11
+ # def bar
12
+ # method.name
13
+ # end
14
+ # end
15
+ #
16
+ # Foo.new.bar #=> 'bar'
17
+
18
+ def name
19
+ # parses things like <Method: A.d>
20
+ inspect.gsub(/#<Method: .*?[\.#](.*?)>/, '\1')
21
+ end
22
+ end
@@ -0,0 +1,14 @@
1
+ # Copyright (c) 2006 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
+ # Gives you back the file, line and method of the caller number i
7
+ # Example:
8
+ # Ramaze.caller_info(1)
9
+ # # => ['/usr/lib/ruby/1.8/irb/workspace.rb', '52', 'irb_binding']
10
+
11
+ def self.caller_info(i = 1)
12
+ file, line, meth = caller[i].scan(/(.*?):(\d+):in `(.*?)'/).first
13
+ end
14
+ end
@@ -1,14 +1,7 @@
1
1
  # Copyright (c) 2006 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
- module Kernel
5
- # Gives you back the file, line and method of the caller number i
6
- # Example:
7
- # __caller_info__(1) # -> ['/usr/lib/ruby/1.8/irb/workspace.rb', '52', 'irb_binding']
8
-
9
- def __caller_info__(i = 1)
10
- file, line, meth = caller[i].scan(/(.*?):(\d+):in `(.*?)'/).first
11
- end
4
+ module Ramaze
12
5
 
13
6
  # Gives you some context around a specific line in a file.
14
7
  # the size argument works in both directions + the actual line,
@@ -33,7 +26,7 @@ module Kernel
33
26
  # [ 124, " @suspend_next = false", false ]
34
27
  # ]
35
28
 
36
- def __caller_lines__ file, line, size = 4
29
+ def self.caller_lines(file, line, size = 4)
37
30
  return [[0, file, true]] if file == '(eval)'
38
31
  lines = File.readlines(file)
39
32
  current = line.to_i - 1
@@ -44,7 +37,7 @@ module Kernel
44
37
  last = current + size
45
38
  last = last > lines.size ? lines.size : last
46
39
 
47
- log = lines[first..last]
40
+ log = lines[first..last] || []
48
41
 
49
42
  area = []
50
43
 
@@ -1,39 +1,65 @@
1
1
  # Copyright (c) 2006 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
+ require 'rdoc/ri/ri_paths'
5
+ require 'rdoc/usage'
6
+
4
7
  # This is a little hack to enable RDoc to see through gems.
5
8
  #
6
9
  # Very evil, but until we get a better RDoc this will have to do.
7
10
 
8
- require 'rdoc/ri/ri_paths'
9
- require 'rdoc/usage'
11
+ module RDoc
12
+ class << self
10
13
 
11
- def RDoc.usage_no_exit(*args)
12
- p caller
13
- main_program_file = caller[1].sub(/:\d+$/, '')
14
- p main_program_file
15
- comment = File.open(main_program_file) do |file|
16
- find_comment(file)
17
- end
14
+ # a patch for RDocs::usage calling our Rdoc::ramazes_usage_no_exit
18
15
 
19
- comment = comment.gsub(/^\s*#/, '')
16
+ def ramazes_usage(*args)
17
+ exit_code = 0
20
18
 
21
- markup = SM::SimpleMarkup.new
22
- flow_convertor = SM::ToFlow.new
19
+ if args.size > 0
20
+ status = args[0]
21
+ if status.respond_to?(:to_int)
22
+ exit_code = status.to_int
23
+ args.shift
24
+ end
25
+ end
23
26
 
24
- flow = markup.convert(comment, flow_convertor)
27
+ # display the usage and exit with the given code
28
+ ramazes_usage_no_exit(*args)
29
+ exit(exit_code)
30
+ end
25
31
 
26
- format = "plain"
32
+ # Only a modfication of RDoc::usage_no_exit for the lookup of main_program,
33
+ # this would be buggy if used by the binary of the gem since $0 is
34
+ # different.
35
+ #
36
+ # Using caller to lookup the actual bin.
27
37
 
28
- unless args.empty?
29
- flow = extract_sections(flow, args)
30
- end
38
+ def ramazes_usage_no_exit(*args)
39
+ main_program_file = caller[1].sub(/:\d+$/, '')
40
+ comment = File.open(main_program_file) do |file|
41
+ find_comment(file)
42
+ end
31
43
 
32
- options = RI::Options.instance
33
- if args = ENV["RI"]
34
- options.parse(args.split)
44
+ comment = comment.gsub(/^\s*#/, '')
45
+
46
+ markup = SM::SimpleMarkup.new
47
+ flow_convertor = SM::ToFlow.new
48
+
49
+ flow = markup.convert(comment, flow_convertor)
50
+
51
+ format = "plain"
52
+
53
+ unless args.empty?
54
+ flow = extract_sections(flow, args)
55
+ end
56
+
57
+ options = RI::Options.instance
58
+ if args = ENV["RI"]
59
+ options.parse(args.split)
60
+ end
61
+ formatter = options.formatter.new(options, "")
62
+ formatter.display_flow(flow)
63
+ end
35
64
  end
36
- formatter = options.formatter.new(options, "")
37
- formatter.display_flow(flow)
38
65
  end
39
-
@@ -13,4 +13,3 @@ class String
13
13
  File.join(self, obj.to_s)
14
14
  end
15
15
  end
16
-
@@ -9,6 +9,8 @@ module Ramaze
9
9
  # A simple wrapper around YAML::Store
10
10
 
11
11
  class Default
12
+ include Enumerable
13
+
12
14
  attr_accessor :db
13
15
 
14
16
  # create a new store with a filename
@@ -18,6 +20,14 @@ module Ramaze
18
20
  @db = YAML::Store.new(filename)
19
21
  end
20
22
 
23
+ # yield a block in a transaction, identical to #db.transaction{}
24
+
25
+ def transaction
26
+ @db.transaction do
27
+ yield
28
+ end
29
+ end
30
+
21
31
  # pass on all methods inside a transaction
22
32
 
23
33
  def method_missing(meth, *args, &block)
@@ -29,7 +39,7 @@ module Ramaze
29
39
  # the actual content of the store in YAML format
30
40
 
31
41
  def to_yaml
32
- Db.dump(:x)
42
+ dump(:x)
33
43
  end
34
44
 
35
45
  # loads the #to_yaml
@@ -41,7 +51,53 @@ module Ramaze
41
51
  # available keys of the store
42
52
 
43
53
  def keys
44
- original.keys
54
+ (original || {}).keys
55
+ end
56
+
57
+ # is the Store empty? (no keys)
58
+
59
+ def empty?
60
+ keys.empty?
61
+ end
62
+
63
+ # nondestructive merge on #original
64
+
65
+ def merge hash = {}
66
+ original.merge(hash)
67
+ end
68
+
69
+ # destructive #merge
70
+
71
+ def merge! hash = {}
72
+ hash.each do |key, value|
73
+ transaction do
74
+ @db[key] = value
75
+ end
76
+ end
77
+
78
+ original
79
+ end
80
+
81
+ # delete all entries
82
+
83
+ def clear
84
+ keys.each do |key|
85
+ delete key
86
+ end
87
+ end
88
+
89
+ # number of #keys
90
+
91
+ def size
92
+ keys.size
93
+ end
94
+
95
+ # Iterate over #original and pass the key and value to a block.
96
+
97
+ def each
98
+ original.each do |key, value|
99
+ yield key, value
100
+ end
45
101
  end
46
102
  end
47
103
  end
@@ -0,0 +1,161 @@
1
+ # Copyright (c) 2006 Michael Fellinger m.fellinger@gmail.com
2
+ # All files in this distribution are subject to the terms of the Ruby license.
3
+
4
+ require 'yaml'
5
+ require 'pstore'
6
+ require 'fileutils'
7
+ require 'set'
8
+
9
+ module Ramaze::Store
10
+ module YAML
11
+ def self.new(*args)
12
+ Manager.new(*args)
13
+ end
14
+
15
+ class Store < PStore
16
+ def initialize( *o )
17
+ @opt = ::YAML::DEFAULTS.dup
18
+ if String === o.first
19
+ super(o.shift)
20
+ end
21
+ if o.last.is_a? Hash
22
+ @opt.update(o.pop)
23
+ end
24
+ end
25
+
26
+ def dump(table = nil)
27
+ @table.to_yaml(@opt)
28
+ end
29
+
30
+ def load(content)
31
+ ::YAML::load(content)
32
+ end
33
+
34
+ def load_file(file)
35
+ ::YAML::load(file)
36
+ end
37
+ end
38
+
39
+ class YAMLStoreWrapper
40
+
41
+ # pass on all methods inside a transaction
42
+
43
+ def method_missing(meth, *args, &block)
44
+ @entities.transaction do
45
+ @entities.send(meth, *args, &block)
46
+ end
47
+ end
48
+
49
+ # yield a block in a transaction, identical to #db.transaction{}
50
+
51
+ def transaction
52
+ @entities.transaction do
53
+ yield(@entities)
54
+ end
55
+ end
56
+
57
+ def to_yaml
58
+ (@entities.instance_variable_get('@table') || {}).to_yaml
59
+ end
60
+
61
+ # loads the #to_yaml
62
+
63
+ def original
64
+ ::YAML.load_file(@store_filename) rescue {}
65
+ end
66
+
67
+ # available keys of the store
68
+
69
+ def keys
70
+ (original || {}).keys
71
+ end
72
+
73
+ # is the Store empty? (no keys)
74
+
75
+ def empty?
76
+ keys.empty?
77
+ end
78
+
79
+ def all
80
+ original
81
+ end
82
+
83
+ def [](eid)
84
+ transaction do |e|
85
+ e[eid.to_s.to_sym]
86
+ end
87
+ end
88
+
89
+ def []=(eid, entity)
90
+ transaction do |e|
91
+ e[eid.to_s.to_sym] = entity
92
+ end
93
+ end
94
+
95
+ def each
96
+ original.each do |key, value|
97
+ yield key, value
98
+ end
99
+ end
100
+
101
+ def delete eid
102
+ transaction do |e|
103
+ e[eid.to_s.to_sym] = nil
104
+ end
105
+ end
106
+ end
107
+
108
+ class Manager < YAMLStoreWrapper
109
+ attr_accessor :store, :store_filename, :store_name, :entities
110
+
111
+ def initialize name, options = {}
112
+ @store_name = name
113
+ @store_filename = "#{@store_name}.yaml"
114
+
115
+ FileUtils.rm_f(@store_filename) if options[:destroy]
116
+
117
+ @entities = Store.new(@store_filename)
118
+ end
119
+
120
+ def new
121
+ entity = Entity.new
122
+ entity.instance_variable_set('@manager', self)
123
+ entity
124
+ end
125
+
126
+ def next_eid
127
+ (keys.max || '`').next
128
+ end
129
+
130
+ def store entity
131
+ if entity.eid
132
+ self[entity.eid] = entity
133
+ else
134
+ eid = next_eid
135
+ entity.eid = eid
136
+ self[entity.eid] = entity
137
+ end
138
+ end
139
+ end
140
+
141
+ class Entity < OpenStruct
142
+ attr_accessor :manager
143
+ trait :no_properties => Set.new(%w[ manager ])
144
+
145
+ def save
146
+ our_name = self.manager.store_name
147
+ @table.each do |key, value|
148
+ if value.respond_to?(:save) and value.send(our_name) != self
149
+ value.send("#{our_name}=", self)
150
+ value.save
151
+ end
152
+ end
153
+ @manager.store self
154
+ end
155
+
156
+ def to_yaml_properties
157
+ instance_variables - self.class.ancestral_trait[:no_properties].map{|np| "@#{np}"}
158
+ end
159
+ end
160
+ end
161
+ end