facets 2.7.0 → 2.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. data/HISTORY.rdoc +135 -294
  2. data/MANIFEST +40 -91
  3. data/NOTES +1 -1
  4. data/README.rdoc +10 -8
  5. data/Rakefile +11 -34
  6. data/demo/{hook.rd → hook.rdoc} +2 -0
  7. data/demo/{scenario_require.rd → scenario_require.rdoc} +3 -0
  8. data/lib/core/facets-live.rb +7 -5
  9. data/lib/core/facets.rb +379 -359
  10. data/lib/core/facets/array/conjoin.rb +2 -2
  11. data/lib/core/facets/array/pad.rb +1 -1
  12. data/lib/core/facets/array/recursively.rb +2 -2
  13. data/lib/core/facets/array/splice.rb +1 -1
  14. data/lib/core/facets/binding/caller.rb +2 -4
  15. data/lib/core/facets/comparable/comparable.rb +2 -2
  16. data/lib/core/facets/dir/ascend.rb +3 -0
  17. data/lib/core/facets/dir/recurse.rb +4 -0
  18. data/lib/core/facets/duplicable.rb +6 -8
  19. data/lib/core/facets/enumerable/count.rb +22 -13
  20. data/lib/core/facets/enumerable/map_detect.rb +28 -0
  21. data/lib/core/facets/enumerable/mash.rb +13 -5
  22. data/lib/core/facets/enumerable/per.rb +3 -1
  23. data/lib/core/facets/hash/count.rb +14 -0
  24. data/lib/core/facets/hash/data.rb +14 -0
  25. data/lib/core/facets/kernel/__method__.rb +1 -1
  26. data/lib/core/facets/kernel/d.rb +9 -8
  27. data/lib/core/facets/kernel/eigenclass.rb +20 -0
  28. data/lib/core/facets/kernel/extend.rb +10 -0
  29. data/lib/core/facets/kernel/instance_class.rb +1 -0
  30. data/lib/core/facets/kernel/instance_variables.rb +6 -6
  31. data/lib/core/facets/kernel/meta_alias.rb +18 -0
  32. data/lib/core/facets/kernel/meta_class.rb +17 -0
  33. data/lib/core/facets/kernel/meta_def.rb +18 -0
  34. data/lib/core/facets/kernel/meta_eval.rb +18 -0
  35. data/lib/core/facets/kernel/object_hexid.rb +21 -6
  36. data/lib/core/facets/kernel/object_state.rb +4 -2
  37. data/lib/core/facets/kernel/populate.rb +3 -1
  38. data/lib/core/facets/kernel/with.rb +1 -1
  39. data/lib/core/facets/metaid.rb +6 -93
  40. data/lib/core/facets/module/class_def.rb +2 -0
  41. data/lib/core/facets/module/extend.rb +10 -11
  42. data/lib/core/facets/module/is.rb +5 -5
  43. data/lib/core/facets/module/module_def.rb +31 -0
  44. data/lib/core/facets/string/camelcase.rb +14 -12
  45. data/lib/core/facets/string/cleanlines.rb +35 -0
  46. data/lib/core/facets/string/edit_distance.rb +62 -0
  47. data/lib/core/facets/string/indent.rb +86 -4
  48. data/lib/core/facets/string/index_all.rb +24 -0
  49. data/lib/core/facets/string/lines.rb +3 -6
  50. data/lib/core/facets/string/margin.rb +2 -1
  51. data/lib/core/facets/string/newlines.rb +35 -0
  52. data/lib/core/facets/string/op_div.rb +14 -0
  53. data/lib/core/facets/string/range.rb +2 -22
  54. data/lib/core/facets/string/range_all.rb +1 -0
  55. data/lib/core/facets/string/range_of_line.rb +1 -0
  56. data/lib/core/facets/string/similarity.rb +92 -0
  57. data/lib/core/facets/string/start_with.rb +6 -6
  58. data/lib/core/facets/string/titlecase.rb +1 -1
  59. data/lib/more/facets/basicobject.rb +16 -15
  60. data/lib/more/facets/blankslate.rb +8 -0
  61. data/lib/more/facets/class_extend.rb +126 -1
  62. data/lib/more/facets/continuation.rb +53 -54
  63. data/lib/more/facets/dictionary.rb +9 -63
  64. data/lib/more/facets/erb.rb +63 -0
  65. data/lib/more/facets/filelist.rb +5 -5
  66. data/lib/more/facets/hashbuilder.rb +101 -0
  67. data/lib/more/facets/inheritor.rb +36 -45
  68. data/lib/more/facets/ini.rb +267 -0
  69. data/lib/more/facets/instance_eval.rb +4 -4
  70. data/lib/more/facets/ioredirect.rb +7 -60
  71. data/lib/more/facets/linkedlist.rb +195 -0
  72. data/lib/more/facets/matcher.rb +140 -0
  73. data/lib/more/facets/memoizer.rb +64 -0
  74. data/lib/more/facets/methodspace.rb +9 -4
  75. data/lib/more/facets/module/class_extend.rb +2 -121
  76. data/lib/more/facets/ostruct.rb +9 -9
  77. data/lib/more/facets/pathlist.rb +1 -9
  78. data/lib/more/facets/pathname.rb +11 -4
  79. data/lib/more/facets/plugin_manager.rb +50 -0
  80. data/lib/more/facets/random.rb +25 -3
  81. data/lib/more/facets/roman.rb +174 -0
  82. data/lib/more/facets/semaphore.rb +92 -0
  83. data/lib/more/facets/shellwords.rb +21 -48
  84. data/lib/more/facets/succ.rb +1 -1
  85. data/meta/{modified → released} +0 -0
  86. data/meta/repository +1 -0
  87. data/meta/suite +1 -0
  88. data/meta/version +1 -1
  89. data/script/conflicts +63 -0
  90. data/script/methods +49 -0
  91. data/test/core/binding/test_caller.rb +11 -4
  92. data/test/core/enumerable/test_count.rb +19 -10
  93. data/test/core/enumerable/test_map_detect.rb +75 -0
  94. data/test/core/enumerable/test_take.rb +1 -1
  95. data/test/core/kernel/test_object_hexid.rb +2 -1
  96. data/test/core/proc/test_to_method.rb +1 -1
  97. data/test/core/string/test_cleanlines.rb +11 -0
  98. data/test/core/string/test_indent.rb +66 -4
  99. data/test/core/string/test_lines.rb +2 -1
  100. data/test/core/string/test_newlines.rb +13 -0
  101. data/test/core/time/test_change.rb +1 -1
  102. data/test/core/time/test_stamp.rb +4 -7
  103. data/test/core/unboundmethod/test_name.rb +1 -1
  104. data/test/more/test_basicobject.rb +1 -20
  105. data/test/more/test_class_extend.rb +7 -0
  106. data/test/more/test_continuation.rb +8 -6
  107. data/test/more/test_inheritor.rb +12 -6
  108. data/test/more/test_random.rb +19 -10
  109. data/test/more/test_shellwords.rb +33 -0
  110. metadata +60 -31
  111. data/TODO +0 -5
  112. data/doc/README.core +0 -102
  113. data/doc/README.more +0 -61
  114. data/doc/manual/about.rb +0 -47
  115. data/doc/manual/annotations.rdoc +0 -60
  116. data/doc/manual/associations.rdoc +0 -55
  117. data/doc/manual/blockups.rdoc +0 -101
  118. data/doc/manual/capsule.rdoc +0 -34
  119. data/doc/manual/command.rdoc +0 -177
  120. data/doc/manual/core.rdoc +0 -37
  121. data/doc/manual/faq.rdoc +0 -32
  122. data/doc/manual/typecast.html +0 -112
  123. data/lib/more/facets/capsule.rb +0 -258
  124. data/lib/more/facets/coroutine.rb +0 -159
  125. data/lib/more/facets/enumerablepass.rb +0 -3
  126. data/lib/more/facets/fileable.rb +0 -162
  127. data/lib/more/facets/progressbar.rb +0 -253
  128. data/lib/more/facets/recorder.rb +0 -108
  129. data/meta/releases +0 -14
  130. data/test/more/test_coroutine.rb +0 -46
@@ -0,0 +1,267 @@
1
+ # ini.rb - read and write ini files
2
+ #
3
+ # Copyright (C) 2007 Jeena Paradies
4
+ # License: GPL
5
+ # Author: Jeena Paradies (info@jeenaparadies.net)
6
+ #
7
+ # This file provides a read-wite handling for ini files.
8
+ # The data of a ini file is represented by a object which
9
+ # is populated with strings.
10
+
11
+ # Class with methods to read from and write into ini files.
12
+ #
13
+ # A ini file is a text file in a specific format,
14
+ # it may include several fields which are sparated by
15
+ # field headlines which are enclosured by "[]".
16
+ # Each field may include several key-value pairs.
17
+ #
18
+ # Each key-value pair is represented by one line and
19
+ # the value is sparated from the key by a "=".
20
+ #
21
+ # == Examples
22
+ #
23
+ # === Example ini file
24
+ #
25
+ # # this is the first comment which will be saved in the comment attribute
26
+ # mail=info@example.com
27
+ # domain=example.com # this is a comment which will not be saved
28
+ # [database]
29
+ # db=example
30
+ # user=john
31
+ # passwd=very-secure
32
+ # host=localhost
33
+ # # this is another comment
34
+ # [filepaths]
35
+ # tmp=/tmp/example
36
+ # lib=/home/john/projects/example/lib
37
+ # htdocs=/home/john/projects/example/htdocs
38
+ # [ texts ]
39
+ # wellcome=Wellcome on my new website!
40
+ # Website description = This is only a example. # and another comment
41
+ #
42
+ # === Example object
43
+ #
44
+ # A Ini#comment stores:
45
+ # "this is the first comment which will be saved in the comment attribute"
46
+ #
47
+ # A Ini object stores:
48
+ #
49
+ # {
50
+ # "mail" => "info@example.com",
51
+ # "domain" => "example.com",
52
+ # "database" => {
53
+ # "db" => "example",
54
+ # "user" => "john",
55
+ # "passwd" => "very-secure",
56
+ # "host" => "localhost"
57
+ # },
58
+ # "filepaths" => {
59
+ # "tmp" => "/tmp/example",
60
+ # "lib" => "/home/john/projects/example/lib",
61
+ # "htdocs" => "/home/john/projects/example/htdocs"
62
+ # }
63
+ # "texts" => {
64
+ # "wellcome" => "Wellcome on my new website!",
65
+ # "Website description" => "This is only a example."
66
+ # }
67
+ # }
68
+ #
69
+ # As you can see this module gets rid of all comments, linebreaks
70
+ # and unnecessary spaces at the beginning and the end of each
71
+ # field headline, key or value.
72
+ #
73
+ # === Using the object
74
+ #
75
+ # Using the object is stright forward:
76
+ #
77
+ # ini = Ini.new("path/settings.ini")
78
+ # ini["mail"] = "info@example.com"
79
+ # ini["filepaths"] = { "tmp" => "/tmp/example" }
80
+ # ini.comment = "This is\na comment"
81
+ # puts ini["filepaths"]["tmp"]
82
+ # # => /tmp/example
83
+ # ini.write()
84
+ #
85
+
86
+ class Ini
87
+
88
+
89
+ #
90
+ # :inihash is a hash which holds all ini data
91
+ # :comment is a string which holds the comments on the top of the file
92
+ #
93
+ attr_accessor :inihash, :comment
94
+
95
+ #
96
+ # Creating a new Ini object
97
+ #
98
+ # +path+ is a path to the ini file
99
+ # +load+ if nil restores the data if possible
100
+ # if true restores the data, if not possible raises an error
101
+ # if false does not resotre the data
102
+ #
103
+ def initialize(path, load=nil)
104
+ @path = path
105
+ @inihash = {}
106
+
107
+ if load or ( load.nil? and FileTest.readable_real? @path )
108
+ restore()
109
+ end
110
+ end
111
+
112
+ #
113
+ # Retrive the ini data for the key +key+
114
+ #
115
+ def [](key)
116
+ @inihash[key]
117
+ end
118
+
119
+ #
120
+ # Set the ini data for the key +key+
121
+ #
122
+ def []=(key, value)
123
+ raise TypeError, "String expected" unless key.is_a? String
124
+ raise TypeError, "String or Hash expected" unless value.is_a? String or value.is_a? Hash
125
+
126
+ @inihash[key] = value
127
+ end
128
+
129
+ #
130
+ # Restores the data from file into the object
131
+ #
132
+ def restore()
133
+ @inihash = Ini.read_from_file(@path)
134
+ @comment = Ini.read_comment_from_file(@path)
135
+ end
136
+
137
+ #
138
+ # Store data from the object in the file
139
+ #
140
+ def update()
141
+ Ini.write_to_file(@path, @inihash, @comment)
142
+ end
143
+
144
+ #
145
+ def to_h
146
+ @inihash.dup
147
+ end
148
+
149
+ #
150
+ # Reading data from file
151
+ #
152
+ # +path+ is a path to the ini file
153
+ #
154
+ # returns a hash which represents the data from the file
155
+ #
156
+ def Ini.read_from_file(path)
157
+
158
+ inihash = {}
159
+ headline = nil
160
+
161
+ IO.foreach(path) do |line|
162
+
163
+ line = line.strip.split(/#/)[0]
164
+
165
+ # read it only if the line doesn't begin with a "=" and is long enough
166
+ unless line.length < 2 and line[0,1] == "="
167
+
168
+ # it's a headline if the line begins with a "[" and ends with a "]"
169
+ if line[0,1] == "[" and line[line.length - 1, line.length] == "]"
170
+
171
+ # get rid of the [] and unnecessary spaces
172
+ headline = line[1, line.length - 2 ].strip
173
+ inihash[headline] = {}
174
+ else
175
+
176
+ key, value = line.split(/=/, 2)
177
+
178
+ key = key.strip unless key.nil?
179
+ value = value.strip unless value.nil?
180
+
181
+ unless headline.nil?
182
+ inihash[headline][key] = value
183
+ else
184
+ inihash[key] = value unless key.nil?
185
+ end
186
+ end
187
+ end
188
+ end
189
+
190
+ inihash
191
+ end
192
+
193
+ #
194
+ # Reading comments from file
195
+ #
196
+ # +path+ is a path to the ini file
197
+ #
198
+ # Returns a string with comments from the beginning of the
199
+ # ini file.
200
+ #
201
+ def Ini.read_comment_from_file(path)
202
+ comment = ""
203
+
204
+ IO.foreach(path) do |line|
205
+ line.strip!
206
+ break unless line[0,1] == "#" or line == ""
207
+
208
+ comment << "#{line[1, line.length ].strip}\n"
209
+ end
210
+
211
+ comment
212
+ end
213
+
214
+ #
215
+ # Writing a ini hash into a file
216
+ #
217
+ # +path+ is a path to the ini file
218
+ # +inihash+ is a hash representing the ini File. Default is a empty hash.
219
+ # +comment+ is a string with comments which appear on the
220
+ # top of the file. Each line will get a "#" before.
221
+ # Default is no comment.
222
+ #
223
+ def Ini.write_to_file(path, inihash={}, comment=nil)
224
+ raise TypeError, "String expected" unless comment.is_a? String or comment.nil?
225
+
226
+ raise TypeError, "Hash expected" unless inihash.is_a? Hash
227
+ File.open(path, "w") { |file|
228
+
229
+ unless comment.nil?
230
+ comment.each do |line|
231
+ file << "# #{line}"
232
+ end
233
+ end
234
+
235
+ file << Ini.to_s(inihash)
236
+ }
237
+ end
238
+
239
+ #
240
+ # Turn a hash (up to 2 levels deepness) into a ini string
241
+ #
242
+ # +inihash+ is a hash representing the ini File. Default is a empty hash.
243
+ #
244
+ # Returns a string in the ini file format.
245
+ #
246
+ def Ini.to_s(inihash={})
247
+ str = ""
248
+
249
+ inihash.each do |key, value|
250
+
251
+ if value.is_a? Hash
252
+ str << "[#{key.to_s}]\n"
253
+
254
+ value.each do |under_key, under_value|
255
+ str << "#{under_key.to_s}=#{under_value.to_s unless under_value.nil?}\n"
256
+ end
257
+
258
+ else
259
+ str << "#{key.to_s}=#{value.to_s unless value2.nil?}\n"
260
+ end
261
+ end
262
+
263
+ str
264
+ end
265
+
266
+ end
267
+
@@ -31,16 +31,16 @@ class Object
31
31
  #
32
32
  # TODO: Will only support calls with blocks as of Ruby 1.9+.
33
33
  #
34
- def instance_eval(&block)
35
- return super if block
34
+ def instance_eval(*args, &block)
35
+ return super if block or !args.empty?
36
36
  @_instance_eval ||= Functor.new do |op, *a|
37
37
  instance_eval{ send(op, *a) }
38
38
  end
39
39
  end
40
40
 
41
41
  # TODO for Ruby 1.9
42
- #def instance_eval(&block)
43
- # return super if block
42
+ #def instance_eval(*args, &block)
43
+ # return super if block or !args.empty?
44
44
  # @_instance_functor ||= Functor.new do |op, *a, &b|
45
45
  # fcall(op, *a, &b)
46
46
  # end
@@ -1,22 +1,8 @@
1
+ warn "IORedirect is being deprecated. It is not a robust solution. If you use this library, please consider contributing to Facets by rewritting the library so we can keep it in Facets."
2
+
1
3
  # = IORedirect
2
4
  #
3
- # A class to redirect $stdout, or other IO object, to a StringIO object,
4
- # or any other object with a write() method.
5
- #
6
- # s = StringIO.new
7
- # r = Redirector.redirect($stdout, s) do
8
- # $stdout.puts "this is a test"
9
- # end
10
- #
11
- # == History
12
- #
13
- # * IORedirect was ported from Paul Brannan's Ruby Treasures.
14
- #
15
- # == Authors
16
- #
17
- # * Paul Brannan <paul@atdesk.com>
18
- #
19
- # = Copying
5
+ # IORedirect was ported from Paul Brannan's Ruby Treasures.
20
6
  #
21
7
  # Copyright (C) 2002 Paul Brannan <paul@atdesk.com>
22
8
  #
@@ -29,6 +15,7 @@
29
15
  # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
30
16
  # FOR A PARTICULAR PURPOSE.
31
17
 
18
+ require 'thread'
32
19
 
33
20
  # = IORedirect
34
21
  #
@@ -36,7 +23,7 @@
36
23
  # or any other object with a write() method.
37
24
  #
38
25
  # s = StringIO.new
39
- # r = Redirector.redirect($stdout, s) do
26
+ # r = IORedirect.redirect($stdout, s) do
40
27
  # $stdout.puts "this is a test"
41
28
  # end
42
29
  #
@@ -55,7 +42,7 @@ class IORedirect
55
42
  def start
56
43
  raise "Redirection already in progress" if @t
57
44
  tmp = @from.dup
58
- r, w = IO.pipe
45
+ r, w = *IO.pipe
59
46
  @from.reopen(w)
60
47
  @t = Thread.new do
61
48
  begin
@@ -78,53 +65,13 @@ class IORedirect
78
65
 
79
66
  # An exception-safe class method for redirection
80
67
  def self.redirect(from, to)
81
- s = self.new(from, to)
68
+ s = new(from, to)
82
69
  begin
83
70
  yield
84
71
  ensure
85
72
  s.stop
86
73
  end
87
74
  end
88
- end
89
-
90
-
91
- # --- test ---
92
-
93
- if __FILE__ == $0 then
94
-
95
- class SimpleStringIO
96
- attr_reader :str
97
- def initialize; @str = ''; end
98
- def write(str); @str << str; end
99
- end
100
-
101
- Thread.abort_on_exception = true
102
- s = SimpleStringIO.new
103
- r = Redirector.redirect($stdout, s) do
104
- $stdout.puts "this is a test"
105
- $stdout.puts "of the StringIO redirection system"
106
- end
107
- puts "Done redirecting."
108
- puts "Result:\n#{s.str}"
109
75
 
110
76
  end
111
77
 
112
-
113
-
114
- # _____ _
115
- # |_ _|__ ___| |_
116
- # | |/ _ \/ __| __|
117
- # | | __/\__ \ |_
118
- # |_|\___||___/\__|
119
- #
120
-
121
- # TODO
122
-
123
- =begin #testing
124
-
125
- require 'test/unit'
126
-
127
- =end
128
-
129
-
130
-
@@ -0,0 +1,195 @@
1
+ # LinkedList
2
+ #
3
+ # Copyright (C) 2006 Kirk Haines <khaines@enigo.com>.
4
+ #
5
+ # General Public License (GPL)
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining
8
+ # a copy of this software and associated documentation files (the
9
+ # "Software"), to deal in the Software without restriction, including
10
+ # without limitation the rights to use, copy, modify, merge, publish,
11
+ # distribute, sublicense, and/or sell copies of the Software, and to
12
+ # permit persons to whom the Software is furnished to do so, subject to
13
+ # the following conditions:
14
+ #
15
+ # The above copyright notice and this permission notice shall be
16
+ # included in all copies or substantial portions of the Software.
17
+ #
18
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
+
26
+ require 'enumerator'
27
+
28
+ # LinkedList implements a simple doubly linked list with efficient
29
+ # hash-like element access.
30
+ #
31
+ # This is a simple linked list implementation with efficient random
32
+ # access of data elements. It was inspired by George Moscovitis'
33
+ # LRUCache implementation found in Facets 1.7.30, but unlike the
34
+ # linked list in that cache, this one does not require the use of a
35
+ # mixin on any class to be stored. The linked list provides the
36
+ # push, pop, shift, unshift, first, last, delete and length methods
37
+ # which work just like their namesakes in the Array class, but it
38
+ # also supports setting and retrieving values by key, just like a
39
+ # hash.
40
+ #
41
+ # LinkedList was ported from the original in Kirk Hanes IOWA web framework.
42
+ #
43
+ class LinkedList
44
+
45
+ include Enumerable
46
+
47
+ # Represents a single node of the linked list.
48
+
49
+ class Node
50
+ attr_accessor :key, :value, :prev_node, :next_node
51
+
52
+ def initialize(key=nil,value=nil,prev_node=nil,next_node=nil)
53
+ @key = key
54
+ @value = value
55
+ @prev_node = prev_node
56
+ @next_node = next_node
57
+ end
58
+ end
59
+
60
+ def initialize
61
+ @head = Node.new
62
+ @tail = Node.new
63
+ @lookup = Hash.new
64
+ node_join(@head,@tail)
65
+ end
66
+
67
+ def [](v)
68
+ @lookup[v].value
69
+ end
70
+
71
+ def []=(k,v)
72
+ if @lookup.has_key?(k)
73
+ @lookup[k].value = v
74
+ else
75
+ n = Node.new(k,v,@head,@head.next_node)
76
+ node_join(n,@head.next_node)
77
+ node_join(@head,n)
78
+ @lookup[k] = n
79
+ end
80
+ v
81
+ end
82
+
83
+ def empty?
84
+ @lookup.empty?
85
+ end
86
+
87
+ def delete(k)
88
+ n = @lookup.delete(k)
89
+ v = n ? node_purge(n) : nil
90
+ v
91
+ end
92
+
93
+ def first
94
+ @head.next_node.value
95
+ end
96
+
97
+ def last
98
+ @tail.prev_node.value
99
+ end
100
+
101
+ def shift
102
+ k = @head.next_node.key
103
+ n = @lookup.delete(k)
104
+ node_delete(n) if n
105
+ end
106
+
107
+ def unshift(v)
108
+ if @lookup.has_key?(v)
109
+ n = @lookup[v]
110
+ node_delete(n)
111
+ node_join(n,@head.next_node)
112
+ node_join(@head,n)
113
+ else
114
+ n = Node.new(v,v,@head,@head.next_node)
115
+ node_join(n,@head.next_node)
116
+ node_join(@head,n)
117
+ @lookup[v] = n
118
+ end
119
+ v
120
+ end
121
+
122
+ def pop
123
+ k = @tail.prev_node.key
124
+ n = @lookup.delete(k)
125
+ node_delete(n) if n
126
+ end
127
+
128
+ def push(v)
129
+ if @lookup.has_key?(v)
130
+ n = @lookup[v]
131
+ node_delete(n)
132
+ node_join(@tail.prev_node,n)
133
+ node_join(n,@tail)
134
+ else
135
+ n = Node.new(v,v,@tail.prev_node,@tail)
136
+ node_join(@tail.prev_node,n)
137
+ node_join(n,@tail)
138
+ @lookup[v] = n
139
+ end
140
+ v
141
+ end
142
+
143
+ def queue
144
+ r = []
145
+ n = @head
146
+ while (n = n.next_node) and n != @tail
147
+ r << n.key
148
+ end
149
+ r
150
+ end
151
+
152
+ def to_a
153
+ r = []
154
+ n = @head
155
+ while (n = n.next_node) and n != @tail
156
+ r << n.value
157
+ end
158
+ r
159
+ end
160
+
161
+ def length
162
+ @lookup.length
163
+ end
164
+
165
+ def each
166
+ n = @head
167
+ while (n = n.next_node) and n != @tail
168
+ yield(n.key,n.value)
169
+ end
170
+ end
171
+
172
+ private
173
+
174
+ def node_delete(n)
175
+ node_join(n.prev_node,n.next_node)
176
+ v = n.value
177
+ end
178
+
179
+ def node_purge(n)
180
+ node_join(n.prev_node,n.next_node)
181
+ v = n.value
182
+ n.value = nil
183
+ n.key = nil
184
+ n.next_node = nil
185
+ n.prev_node = nil
186
+ v
187
+ end
188
+
189
+ def node_join(a,b)
190
+ a.next_node = b
191
+ b.prev_node = a
192
+ end
193
+
194
+ end
195
+