hashery-2.1.2/0000755000004100000410000000000012712231705013207 5ustar www-datawww-datahashery-2.1.2/HISTORY.md0000644000004100000410000001322512712231704014674 0ustar www-datawww-data# RELEASE HISTORY ## 2.1.1 / 2013-08-21 This minor release clarifies the licensing. The entire library is now distributed under the BSD-2-Clause license, also known as the FreeBSD license. In addition this release provides a bug fix for flattening arrays that contain an OpenCascade object. Changes: * Clarify licensing. * Fix #flatten on Arrays that contain an OpenCascade. ## 2.1.0 / 2012-11-24 (Golden Retriever) The major change of the 2.1 release is to switch over to `Hash#fetch` as the fundamental CRUD read method in-place of the previous `#read` core extension (an alias of `#[]`). This is a pretty fundamental change which required modification of a number of classes. So please do extra-diligence and file an issue if you experience any problems. In addition, the Hash#read core extension has been renamed to Hash#retrieve to avoid any possible confusion with IO objects. This release also fixes a couple of issues with 1.8 compatibility and makes a few other small enhancements. Changes: * Rename Hash#read to Hash#retrieve. * Deprecate `Dictionary.alpha` in favor of `Dictionary.alphabetic`. * Add support for block argument in Dictionary#order_by_key and #order_by_value. * Fix OpenHash issues with Ruby 1.8.x compatibility. * OpenHash methods are opened up via `protected` instead of `private`. * Change OpenCascade to auto-create the subclass when inherited. ## 2.0.1 / 2012-07-06 This minor release fixes an issue with OpenCascade (#13). The key_proc procedure wasn't being passed along to sub-cascades. Changes: * OpenCascade passes along key_proc to children. ## 2.0.0 / 2012-05-11 (Crud Space) This is a big release for Hashery which both culls some of it's less fitting classes and modules while greatly improving the rest. The first and most immediate change is use of a proper namespace. All classes and modules are now appropriately kept in the `Hashery` namespace. To get the old behavior you can `include Hashery` as the toplevel. For the other changes and improvements dive into the API documentation. Changes: * Use proper Hashery namespace. * Add CRUDHash, which also serves a good base class. * Improved OpenHash to be nearly 100% open. * Deprecate BasicStruct, as it would be better to improve OpenStruct. * Deprecate BasicCascade, though it never really came to be. * Deprecate BasicObject emulator, as it is no longer needed. * Deprecate Memoizer, not sure how that got in here anyway. * Deprecate Ostructable, which can be paired up with better OpenStruct. * Removed open_object.rb, which has long been deprecated. ## 1.5.1 / 2012-05-09 This release adds transformative #each method to OpenCascade, to ensure #each returns an OpenCascade. Also, BasicCascade has been added that is like OpenCascade by fully open by use of BasicObject as a base class. Changes: * Fix OpenCascade#each (porecreat). * Introduce BasicCascade class. * Renamed `Ini` class to `IniHash` class. ## 1.5.0 / 2011-11-10 (Devil's Core) In this release, CoreExt module has been added to encapsulate methods that extend Ruby's core Hash class (there are only a few). Presently these are only loaded when using `require 'hashery'`. If you are cherry-picking from Hashery but still want the core extensions, you need to use `require 'hasery/core_ext'` first. In addition, BasicStruct class now has a #key method. And finally this release switches licensing to BSD 2-Clause. Changes: * Use CoreExt mixin for core Hash extensions. * Add BasicStruct#key method (b/c #index is deprecated in Ruby 1.9). * Deprecate SparseArray class. * Switch license to BSD-2-Clause license. ## 1.4.0 / 2011-01-19 (Back To Basics) This release includes a copy of Ruby Facets' BasicObject class, which fixes the loading bug of the previous version. This release also renames OpenObject to BasicStruct, which is a much better description of what the class actually provides. Changes: * Rename OpenObject to BasicStruct. * Fix basicobject.rb loading issue. ## 1.3.0 / 2010-10-01 (Private Property) This release fixes a minor bug in CastingHash and adds a new PropertyHash class. Changes: * 1 New Library * Added PropertyHash * 1 Bug Fix * Fixed CastingHash#new where #to_proc is called against NilClass ## 1.2.0 / 2010-06-04 (Fuzzy Wuzzy) This release makes two significant changes to the Hashery. First, we have a new shiny library called FuzzyHash by Joshua Hull. It's a cool idea that allows hash keys to be regular expressions. Secondly, OpenCascade is now a subclass of OpenHash rather than OpenObject (to go along with the changes of the last release), and it now support cascading within Arrays. Changes: * 1 New Library * FuzzyHash by Joshua Hull * 1 Major Enhancement * OpenCascade subclasses OpenHash and handles Array cascading. ## 1.1.0 / 2010-04-28 (Ugly Ducklings) A follow-up release of Hashery that adds two new libraries: Association and SparseArray. Both of these may seem like odd entries, but they each belong in a unique way. An Association is akin to a single entry Hash --it represents a pairing. While a SpareArray, though compatible with the Array class, is completely under-pinned by a Hash in order to make it efficient when no entries are given for a set of indexes, hence "sparse". Changes: * 2 New Libraries * Added association.rb * Added sparsearray.rb ## 1.0.0 / 2010-04-21 (Hatching Hashery) This is the first release of the Facets Hashery. Most of included classes come directly from Ruby Facets, so they have been around a while and are in good working condition. Some improvements are planned for the next release. In particular the OrderHash and Dictionary, which presently have essentially the same coding, will diverge to target slightly different use cases. Changes: * Happy Birthday! hashery-2.1.2/.index0000644000004100000410000000342212712231704014317 0ustar www-datawww-data--- revision: 2013 type: ruby sources: - Index.yml - Gemfile authors: - name: Trans email: transfire@gmail.com - name: Kirk Haines - name: Robert Klemme - name: Jan Molic - name: George Moschovitis - name: Jeena Paradies - name: Erik Veenstra organizations: - name: RubyWorks (http://rubyworks.github.com/) requirements: - groups: - development - test version: ">= 0" name: qed - groups: - development - test version: ">= 0" name: lemon - groups: - development - test version: ">= 0" name: rubytest-cli conflicts: [] alternatives: [] resources: - type: home uri: http://rubyworks.github.com/hashery label: Homepage - type: code uri: http://github.com/rubyworks/hashery label: Source Code - type: mail uri: http://groups.google.com/group/rubyworks-mailinglist label: Mailing List - type: docs uri: http://rubydoc.info/github/rubyworks/hashery/master/frames label: Documentation - type: wiki uri: http://wiki.github.com/rubyworks/hashery label: User Guide - type: gems uri: http://rubygems.org/gems/hashery repositories: - name: upstream scm: git uri: git://github.com/rubyworks/hashery.git categories: [] copyrights: - holder: Rubyworks year: '2010' license: BSD-2-Clause customs: [] paths: lib: - lib - alt name: hashery title: Hashery version: 2.1.2 summary: Facets-bread collection of Hash-like classes. description: The Hashery is a tight collection of Hash-like classes. Included among its many offerings are the auto-sorting Dictionary class, the efficient LRUHash, the flexible OpenHash and the convenient KeyHash. Nearly every class is a subclass of the CRUDHash which defines a CRUD model on top of Ruby's standard Hash making it a snap to subclass and augment to fit any specific use case. created: '2010-04-21' date: '2016-05-01' hashery-2.1.2/Index.yml0000644000004100000410000000227612712231704015007 0ustar www-datawww-data--- name: hashery version: 2.1.2 title: Hashery summary: Facets-bread collection of Hash-like classes. description: The Hashery is a tight collection of Hash-like classes. Included among its many offerings are the auto-sorting Dictionary class, the efficient LRUHash, the flexible OpenHash and the convenient KeyHash. Nearly every class is a subclass of the CRUDHash which defines a CRUD model on top of Ruby's standard Hash making it a snap to subclass and augment to fit any specific use case. authors: - Trans - Kirk Haines - Robert Klemme - Jan Molic - George Moschovitis - Jeena Paradies - Erik Veenstra resources: home: http://rubyworks.github.com/hashery code: http://github.com/rubyworks/hashery mail: http://groups.google.com/group/rubyworks-mailinglist docs: http://rubydoc.info/github/rubyworks/hashery/master/frames wiki: http://wiki.github.com/rubyworks/hashery gems: http://rubygems.org/gems/hashery repositories: upstream: "git://github.com/rubyworks/hashery.git" organizations: - RubyWorks (http://rubyworks.github.com/) copyrights: - 2010 Rubyworks (BSD-2-Clause) load_path: - lib - alt created: '2010-04-21' hashery-2.1.2/demo/0000755000004100000410000000000012712231704014132 5ustar www-datawww-datahashery-2.1.2/demo/applique/0000755000004100000410000000000012712231704015752 5ustar www-datawww-datahashery-2.1.2/demo/applique/ae.rb0000644000004100000410000000004112712231704016657 0ustar www-datawww-datarequire 'ae' require 'ae/should' hashery-2.1.2/demo/applique/hashery.rb0000644000004100000410000000004312712231704017737 0ustar www-datawww-datarequire 'hashery' include Hashery hashery-2.1.2/demo/05_key_hash.rdoc0000644000004100000410000000057012712231704017104 0ustar www-datawww-data= KeyHash The KeyHash is essentially the same as regular Hash but instead of a `default_proc` the initializer takes the `key_proc` for normalizing keys. kh = KeyHash.new{ |k| k.to_s.upcase } kh[:a] = 1 kh.to_h #=> ({'A'=>1}) By default, when no `key_proc` is given, it converts all keys to strings. kh = KeyHash.new kh[:a] = 1 kh.to_h #=> ({'a'=>1}) hashery-2.1.2/demo/10_association.rdoc0000644000004100000410000000225412712231704017622 0ustar www-datawww-data= Association An Association is a class for creating simple pairings. require 'hashery/association' An Association can bew created through the usual means of instantiation. Association.new(:a, :b) Or the shortcut method #>> can be used in most cases. :x >> :z An association provides two methods to access its content, #index and #value. a = 'foo' >> 'bar' a.index.assert == 'foo' a.value.assert == 'bar' Associations can be used to create ordered-hashes via normal arrays. keys = [] vals = [] ohash = [ 'A' >> '3', 'B' >> '2', 'C' >> '1' ] ohash.each{ |k,v| keys << k ; vals << v } keys.assert == ['A','B','C'] vals.assert == ['3','2','1'] Becuase Associations are objects in themselves more complex collections can also be created. complex = [ 'parent' >> 'child', 'childless', 'another_parent' >> [ 'subchildless', 'subparent' >> 'subchild' ] ] An experimental feature of Association keeps a cache of all defined associations. o = Object.new o >> :a o >> :b o >> :c o.associations.assert == [:a, :b, :c] However this feature will probably be deprecated. hashery-2.1.2/demo/01_open_hash.rdoc0000644000004100000410000000317012712231704017250 0ustar www-datawww-data= OpenHash An OpenHash is a Hash that provides +open+ access to its entries via method calls. Writers (methods ending in =-marks) assign entries. Methods without special puncuation will retrieve entries. o = OpenHash.new o.a = 1 o.b = 2 o.a.assert == 1 o.b.assert == 2 Writers always use a Symbol for keys in the underlying Hash. o.to_h.assert == { :a=>1, :b=>2 } All the usual Hash methods are still available in an OpenHash. c = o.map{ |k,v| [k,v] } c.assert.include?([:a,1]) c.assert.include?([:b,2]) And they are protected from being overridden by writers. o.map = 3 o.map.refute == 3 Even so, the underlying Hash object does contain the entry even when it cannot be accessed via a reader method. o.to_h.assert == { :a=>1, :b=>2, :map=>3 } We can see if a method is open or not via the `#open?` method. o.open?(:a).assert == true o.open?(:map).assert == false For some usecases it may be necessary to give up access to one or more Hash methods in favor of access to the hash entries. This can be done using the `#open!` method. o.open!(:map, :merge) o.map.assert == 3 o.merge = 4 o.merge.assert == 4 Becuase of nature of a writer, a certain set of Hash methods are always protected, in particluar all methods buffered by underscore (e.g. `__id__`). So these cannot be opened. expect ArgumentError do o.open!(:__id__) end Even though writers alwasy use Symbols as keys, because an OpenHash is a true Hash object, any object can be used as a key internally. o = OpenHash.new o[nil] = "Nothing" o.to_h.assert == { nil=>"Nothing" } It simply cannot be accessible via a reader method. hashery-2.1.2/demo/07_fuzzy_hash.rdoc0000644000004100000410000000563212712231704017511 0ustar www-datawww-data= FuzzyHash Should accept strings and retrieve based on them. l = FuzzyHash.new l['asd'] = 'qwe' l['asd'].should == 'qwe' Should accept strings, but the second time you set the same string, it should overwrite. l = FuzzyHash.new l['asd'] = 'asd' l['asd'] = 'qwe' l['asd'].should == 'qwe' Should accept regexs too. l = FuzzyHash.new l[/asd.*/] = 'qwe' l['asdqweasd'].should == 'qwe' Should accept regexs too, but the second time you set the same regex, it should overwrite. l = FuzzyHash.new l[/asd/] = 'asd' l[/asd/] = 'qwe' l['asdqweasd'].should == 'qwe' Should accept regexs too with the match. l = FuzzyHash.new l[/asd.*/] = 'qwe' l.match_with_result('asdqweasd').should == ['qwe', 'asdqweasd'] Should accept regexs that match the whole strong too with the match. l = FuzzyHash.new l[/asd/] = 'qwe' l.match_with_result('asd').should == ['qwe', 'asd'] Should prefer string to regex matches. l = FuzzyHash.new l['asd'] = 'qwe2' l[/asd.*/] = 'qwe' l['asd'].should == 'qwe2' Should allow nil keys. l = FuzzyHash.new l[nil] = 'qwe2' l['asd'] = 'qwe' l['asd'].should == 'qwe' l[nil].should == 'qwe2' Should allow boolean keys. l = FuzzyHash.new l[false] = 'false' l[true] = 'true' l[/.*/] = 'everything else' l[true].should == 'true' l[false].should == 'false' l['false'].should == 'everything else' Should pick between the correct regex. hash = FuzzyHash.new hash[/^\d+$/] = 'number' hash[/.*/] = 'something' hash['123asd'].should == 'something' Should be able to delete by value for hash. l = FuzzyHash.new l[nil] = 'qwe2' l['asd'] = 'qwe' l['asd'].should == 'qwe' l[nil].should == 'qwe2' l.delete_value('qwe2') l[nil].should == nil Should be able to delete by value for regex. l = FuzzyHash.new l[/qwe.*/] = 'qwe2' l['asd'] = 'qwe' l['asd'].should == 'qwe' l['qweasd'].should == 'qwe2' l.delete_value('qwe2') l['qweasd'].should == nil Should iterate through the keys. l = FuzzyHash.new l[/qwe.*/] = 'qwe2' l['asd'] = 'qwe' l['zxc'] = 'qwe' l.keys.size.should == 3 Should iterate through the values. l = FuzzyHash.new l[/qwe.*/] = 'qwe2' l['asd'] = 'qwe' l['zxc'] = 'qwelkj' (['qwe2','qwe','qwelkj'] & l.values).size.should == 3 Should clear. l = FuzzyHash.new l[/qwe.*/] = 'qwe2' l['asd'] = 'qwe' l['zxc'] = 'qwelkj' l.clear l.empty?.should == true Should handle equality. l_1 = FuzzyHash.new l_1[/qwe.*/] = 'qwe2' l_1['asd'] = 'qwelkj' l_1['zxc'] = 'qwe' l_2 = FuzzyHash.new l_2['zxc'] = 'qwe' l_2['asd'] = 'qwelkj' l_2[/qwe.*/] = 'qwe2' l_1.should == l_2 Should return the value when adding the value. h = FuzzyHash.new (h[/asd/] = '123').should == '123' (h['qwe'] = '123').should == '123' That's It. hashery-2.1.2/demo/00_introduction.rdoc0000644000004100000410000000023712712231704020025 0ustar www-datawww-data= Hashery For the following demos the `hashery` script has been preloaded and the Hashery namespace has been included into the demo context for convenience. hashery-2.1.2/demo/08_propery_hash.rdoc0000644000004100000410000000131312712231704020013 0ustar www-datawww-data= PropertyHash The Property hash can be used an object in itself. h = PropertyHash.new(:a=>1, :b=>2) h[:a] #=> 1 h[:a] = 3 h[:a] #=> 3 Becuase the properties are fixed, if we try to set a key that is not present, then we will get an error. expect ArgumentError do h[:x] = 5 end The PropertyHash can also be used as a superclass. class MyPropertyHash < PropertyHash property :a, :default => 1 property :b, :default => 2 end h = MyPropertyHash.new h[:a] #=> 1 h[:a] = 3 h[:a] #=> 3 Again, if we try to set key that was not fixed, then we will get an error. expect ArgumentError do h[:x] = 5 end hashery-2.1.2/demo/06_open_cascade.rdoc0000644000004100000410000000276412712231704017725 0ustar www-datawww-data= OpenCascade The reason this class is labeled "cascade", is that every internal Hash is transformed into an OpenCascade dynamically upon access. This makes it easy to create _cascading_ references. h = { :x => { :y => { :z => 1 } } } c = OpenCascade[h] assert c.x.y.z == 1 As soon as you access a node it automatically becomes an OpenCascade. c = OpenCascade.new assert(OpenCascade === c.r) assert(OpenCascade === c.a.b) But if you set a node, then that will be it's value. c.a.b = 4 assert c.a.b == 4 To query a node without causing the auto-creation of an OpenCasade object, use the ?-mark. assert c.a.z? == nil OpenCascade also transforms Hashes within Arrays. h = { :x=>[ {:a=>1}, {:a=>2} ], :y=>1 } c = OpenCascade[h] assert c.x.first.a == 1 assert c.x.last.a == 2 Like OpenObject, OpenCascade allows you to insert entries as array pairs. c = OpenCascade.new c << [:x,8] c << [:y,9] assert c.x == 8 assert c.y == 9 Finally, you can call methods ending in a !-mark to access the underlying hash (Note that these differ in behavior from the built-in !-methods). bk = c.map!{ |k,v| k.to_s.upcase } bk.sort.assert == ['X', 'Y'] So you can see that for the most an OpenCascade is just like OpenHash, but it allows us to conveniently build open sub-layers easily. Enumerable still works with OpenCascades too. h = {} c = OpenCascade[:a=>1,:b=>{:c=>3}] c.each do |k,v| h[k] = v end OpenCascade.assert === h[:b] hashery-2.1.2/demo/03_casting_hash.rdoc0000644000004100000410000000040412712231704017736 0ustar www-datawww-data= CastingHash A CastingHash is a Hash that allows _casting_ procedures to defined that the keys and values pass through upon assignment. c = CastingHash.new c.cast_proc = lambda { |k,v| [k.to_s, v.to_s.upcase] } c[:a] = 'a' c.assert == {'a'=>'A'} hashery-2.1.2/demo/02_query_hash.rdoc0000644000004100000410000000062212712231704017454 0ustar www-datawww-data= QueryHash A QueryHash is a Hash that provides open access much like an OpenHash, but it limits readers to bang and query methods (i.e. method ending in `!` or `?`). q = QueryHash.new q.a = 1 q.b = 2 q.a?.assert == 1 q.b?.assert == 2 By default keys are converted to strings. q.assert == { "a"=>1, "b"=>2 } A QueryHash is compatible with Ruby's standard Hash in every other respect. hashery-2.1.2/demo/04_static_hash.rdoc0000644000004100000410000000060112712231704017575 0ustar www-datawww-data= StaticHash A StaticHash is simply a Hash that can only be assigned once per key. Once assigned a subsequent attempt to assign a value to the same key will raise an ArgumentError. h = StaticHash.new h["x"] = 1 expect ArgumentError do h["x"] = 2 end The same error will be raised when using #update or #merge!. expect ArgumentError do h.update( "x"=>3 ) end hashery-2.1.2/LICENSE.txt0000644000004100000410000000233512712231704015034 0ustar www-datawww-dataBSD-2-Clause License Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. hashery-2.1.2/lib/0000755000004100000410000000000012712231704013754 5ustar www-datawww-datahashery-2.1.2/lib/hashery.yml0000644000004100000410000000342212712231704016143 0ustar www-datawww-data--- revision: 2013 type: ruby sources: - Index.yml - Gemfile authors: - name: Trans email: transfire@gmail.com - name: Kirk Haines - name: Robert Klemme - name: Jan Molic - name: George Moschovitis - name: Jeena Paradies - name: Erik Veenstra organizations: - name: RubyWorks (http://rubyworks.github.com/) requirements: - groups: - development - test version: ">= 0" name: qed - groups: - development - test version: ">= 0" name: lemon - groups: - development - test version: ">= 0" name: rubytest-cli conflicts: [] alternatives: [] resources: - type: home uri: http://rubyworks.github.com/hashery label: Homepage - type: code uri: http://github.com/rubyworks/hashery label: Source Code - type: mail uri: http://groups.google.com/group/rubyworks-mailinglist label: Mailing List - type: docs uri: http://rubydoc.info/github/rubyworks/hashery/master/frames label: Documentation - type: wiki uri: http://wiki.github.com/rubyworks/hashery label: User Guide - type: gems uri: http://rubygems.org/gems/hashery repositories: - name: upstream scm: git uri: git://github.com/rubyworks/hashery.git categories: [] copyrights: - holder: Rubyworks year: '2010' license: BSD-2-Clause customs: [] paths: lib: - lib - alt name: hashery title: Hashery version: 2.1.2 summary: Facets-bread collection of Hash-like classes. description: The Hashery is a tight collection of Hash-like classes. Included among its many offerings are the auto-sorting Dictionary class, the efficient LRUHash, the flexible OpenHash and the convenient KeyHash. Nearly every class is a subclass of the CRUDHash which defines a CRUD model on top of Ruby's standard Hash making it a snap to subclass and augment to fit any specific use case. created: '2010-04-21' date: '2016-05-01' hashery-2.1.2/lib/hashery.rb0000644000004100000410000000103712712231704015745 0ustar www-datawww-datamodule Hashery VERSION = "2.1.0" end require 'hashery/core_ext' #require 'hashery/basic_struct' require 'hashery/casting_hash' require 'hashery/crud_hash' require 'hashery/dictionary' require 'hashery/fuzzy_hash' require 'hashery/ini_hash' require 'hashery/linked_list' require 'hashery/lru_hash' require 'hashery/key_hash' require 'hashery/open_cascade' require 'hashery/open_hash' #require 'hashery/ordered_hash' #require 'hashery/ostructable' require 'hashery/property_hash' require 'hashery/query_hash' require 'hashery/static_hash' hashery-2.1.2/lib/hashery/0000755000004100000410000000000012712231704015417 5ustar www-datawww-datahashery-2.1.2/lib/hashery/core_ext.rb0000644000004100000410000000510412712231704017554 0ustar www-datawww-dataclass Hash # # Create a hash given an `initial_hash`. # # initial_hash - Hash or hash-like object to use as priming data. # block - Procedure used by initialize (e.g. default_proc). # # Returns a `Hash`. # def self.create(initial_hash={}, &block) o = new &block o.update(initial_hash) o end # # Like #fetch but returns the results of calling `default_proc`, if defined, # otherwise `default`. # # key - Hash key to lookup. # # Returns value of Hash entry or `nil`. # def retrieve(key) fetch(key, default_proc ? default_proc[self, key] : default) end # # Convert to Hash. # def to_hash dup # -or- `h = {}; each{ |k,v| h[k] = v }; h` ? end \ unless method_defined?(:to_hash) # # For a Hash, `#to_h` is the same as `#to_hash`. # alias :to_h :to_hash \ unless method_defined?(:to_h) # # Synonym for Hash#rekey, but modifies the receiver in place (and returns it). # # key_map - Hash of old key to new key. # block - Procedure to convert keys, which can take just the key # or both key and value as arguments. # # Examples # # foo = { :name=>'Gavin', :wife=>:Lisa } # foo.rekey!{ |k| k.to_s } #=> { "name"=>"Gavin", "wife"=>:Lisa } # foo.inspect #=> { "name"=>"Gavin", "wife"=>:Lisa } # # Returns `Hash`. # def rekey(key_map=nil, &block) if !(key_map or block) block = lambda{|k| k.to_sym} end key_map ||= {} hash = {} (keys - key_map.keys).each do |key| hash[key] = self[key] end key_map.each do |from, to| hash[to] = self[from] if key?(from) end hash2 = {} if block case block.arity when 0 raise ArgumentError, "arity of 0 for #{block.inspect}" when 2 hash.each do |k,v| nk = block.call(k,v) hash2[nk] = v end else hash.each do |k,v| nk = block[k] hash2[nk] = v end end else hash2 = hash end hash2 end # # Synonym for Hash#rekey, but modifies the receiver in place (and returns it). # # key_map - Hash of old key to new key. # block - Procedure to convert keys, which can take just the key # or both key and value as arguments. # # Examples # # foo = { :name=>'Gavin', :wife=>:Lisa } # foo.rekey!{ |k| k.to_s } #=> { "name"=>"Gavin", "wife"=>:Lisa } # foo #=> { "name"=>"Gavin", "wife"=>:Lisa } # # Returns `Hash`. # def rekey!(key_map=nil, &block) replace(rekey(key_map, &block)) end end hashery-2.1.2/lib/hashery/linked_list.rb0000644000004100000410000001074012712231704020247 0ustar www-datawww-datarequire 'enumerator' module Hashery # LinkedList implements a simple doubly linked list with efficient # hash-like element access. # # This is a simple linked-list implementation with efficient random # access of data elements. It was inspired by George Moscovitis' # LRUCache implementation found in Facets 1.7.30, but unlike the # linked-list in that cache, this one does not require the use of a # mixin on any class to be stored. The linked-list provides the # push, pop, shift, unshift, first, last, delete and length methods # which work just like their namesakes in the Array class, but it # also supports setting and retrieving values by key, just like a # hash. # # LinkedList was ported from the original in Kirk Hanes IOWA web framework. # # == Acknowledgements # # LinkedList is based on the LinkedList library by Kirk Haines. # # Copyright (C) 2006 Kirk Haines . # class LinkedList include Enumerable # Represents a single node of the linked list. # class Node attr_accessor :key, :value, :prev_node, :next_node def initialize(key=nil,value=nil,prev_node=nil,next_node=nil) @key = key @value = value @prev_node = prev_node @next_node = next_node end end # # Initialize new LinkedList instance. # def initialize @head = Node.new @tail = Node.new @lookup = Hash.new node_join(@head,@tail) end # # Lookup entry by key. # def [](key) @lookup[key].value end # # Add node to linked list. # def []=(k,v) if @lookup.has_key?(k) @lookup[k].value = v else n = Node.new(k,v,@head,@head.next_node) node_join(n,@head.next_node) node_join(@head,n) @lookup[k] = n end v end # # Is linked list empty? # def empty? @lookup.empty? end # # Remove node idenified by key. # def delete(key) n = @lookup.delete(key) v = n ? node_purge(n) : nil v end # # Get value of first node. # def first @head.next_node.value end # # Get value of last node. # def last @tail.prev_node.value end # # # def shift k = @head.next_node.key n = @lookup.delete(k) node_delete(n) if n end # # # def unshift(v) if @lookup.has_key?(v) n = @lookup[v] node_delete(n) node_join(n,@head.next_node) node_join(@head,n) else n = Node.new(v,v,@head,@head.next_node) node_join(n,@head.next_node) node_join(@head,n) @lookup[v] = n end v end # # # def pop k = @tail.prev_node.key n = @lookup.delete(k) node_delete(n) if n end # # # def push(v) if @lookup.has_key?(v) n = @lookup[v] node_delete(n) node_join(@tail.prev_node,n) node_join(n,@tail) else n = Node.new(v,v,@tail.prev_node,@tail) node_join(@tail.prev_node,n) node_join(n,@tail) @lookup[v] = n end v end alias :<< :push # # Produces an Array of key values. # # Returns [Array]. # def queue r = [] n = @head while (n = n.next_node) and n != @tail r << n.key end r end # # Converts to an Array of node values. # # Returns [Array]. # def to_a r = [] n = @head while (n = n.next_node) and n != @tail r << n.value end r end # # Number of nodes. # def length @lookup.length end alias size length # # Iterate over nodes, starting with the head node # and ending with the tail node. # def each n = @head while (n = n.next_node) and n != @tail yield(n.key,n.value) end end private # # Delete a node. # # n - A node. # def node_delete(n) node_join(n.prev_node,n.next_node) v = n.value end # # Purge a node. # # n - A node. # def node_purge(n) node_join(n.prev_node,n.next_node) v = n.value n.value = nil n.key = nil n.next_node = nil n.prev_node = nil v end # Join two nodes. # # a - A node. # b - A node. # def node_join(a,b) a.next_node = b b.prev_node = a end end end hashery-2.1.2/lib/hashery/ini_hash.rb0000644000004100000410000002012212712231704017523 0ustar www-datawww-datamodule Hashery # Hash class with methods to read from and write into ini files. # # A ini file is a text file in a specific format, # it may include several fields which are sparated by # field headlines which are enclosured by "[]". # Each field may include several key-value pairs. # # Each key-value pair is represented by one line and # the value is sparated from the key by a "=". # # == Examples # # === Example ini file # # # this is the first comment which will be saved in the comment attribute # mail=info@example.com # domain=example.com # this is a comment which will not be saved # [database] # db=example # user=john # passwd=very-secure # host=localhost # # this is another comment # [filepaths] # tmp=/tmp/example # lib=/home/john/projects/example/lib # htdocs=/home/john/projects/example/htdocs # [ texts ] # wellcome=Wellcome on my new website! # Website description = This is only a example. # and another comment # # === Example object # # Ini#comment stores: # # "this is the first comment which will be saved in the comment attribute" # # Ini's internal hash stores: # # { # "mail" => "info@example.com", # "domain" => "example.com", # "database" => { # "db" => "example", # "user" => "john", # "passwd" => "very-secure", # "host" => "localhost" # }, # "filepaths" => { # "tmp" => "/tmp/example", # "lib" => "/home/john/projects/example/lib", # "htdocs" => "/home/john/projects/example/htdocs" # } # "texts" => { # "wellcome" => "Wellcome on my new website!", # "Website description" => "This is only a example." # } # } # # As you can see this module gets rid of all comments, linebreaks # and unnecessary spaces at the beginning and the end of each # field headline, key or value. # # === Using the object # # Using the object is stright forward: # # ini = IniHash.new("path/settings.ini") # ini["mail"] = "info@example.com" # ini["filepaths"] = { "tmp" => "/tmp/example" } # ini.comment = "This is\na comment" # puts ini["filepaths"]["tmp"] # # => /tmp/example # ini.write() # # == Acknowlegements # # IniHash is based on ini.rb. # # Copyright (C) 2007 Jeena Paradies class IniHash # TODO: Use class method for loading from file, not initializer. # # NOTE: In future versions, `#new` will not take a path, and `#load` # will have to be used. # def self.load(path, load=true) new(path, load) end # # The hash which holds all INI data. # attr_accessor :inihash # # The string which holds the comments on the top of the file # attr_accessor :comment # # Creating a new IniHash object. # # path - is a path to the ini file # load - if nil restores the data if possible # if true restores the data, if not possible raises an error # if false does not resotre the data # def initialize(path, load=nil) @path = path if String === path @inihash = (Hash === path ? path.dup : {}) if load or ( load.nil? and FileTest.readable_real? @path ) restore() end end # # Retrive the ini data for the key +key+ # def [](key) @inihash[key] end # # Set the ini data for the key +key+ # # key - Index key. # value - The value to index. # # Returns +value+. # def []=(key, value) #raise TypeError, "String expected" unless key.is_a? String key = key.to_str #raise TypeError, "String or Hash expected" unless value.is_a? String or value.is_a? Hash value = value.to_str unless Hash === value @inihash[key] = value end # # Restores the data from file into the object # def restore @inihash = IniHash.read_from_file(@path) @comment = IniHash.read_comment_from_file(@path) end # # Store data from the object in the file. # def save IniHash.write_to_file(@path, @inihash, @comment) end # # Deprecated: Save INI data to file path. Use #save instead. # def update warn 'IniHash#update is deprecated for this use, use IniHash#save instead.' save end # # Convert to hash by duplicating the underlying hash table. # def to_h @inihash.dup end alias :inspect :to_s # # Turn a hash (up to 2 levels deepness) into a ini string # # inihash - Hash representing the ini File. Default is a empty hash. # # Returns a string in the ini file format. # def to_s str = "" inihash.each do |key, value| if value.is_a? Hash str << "[#{key.to_s}]\n" value.each do |under_key, under_value| str << "#{under_key.to_s}=#{under_value.to_s unless under_value.nil?}\n" end else str << "#{key.to_s}=#{value.to_s unless value.nil?}\n" end end str end # # Delegate missing mthods to underlying Hash. # # TODO: Sublcass Hash instead of delegating. # def method_missing(s,*a,&b) @inihash.send(s, *a, &b) if @inihash.respond_to?(s) end # # Reading data from file # # path - a path to the ini file # # Returns a `Hash` which represents the data from the file. # def self.read_from_file(path) raise "file not found - #{path}" unless File.file?(path) inihash = {} headline = nil IO.foreach(path) do |line| line = line.strip.split(/#/)[0].to_s # read it only if the line doesn't begin with a "=" and is long enough unless line.length < 2 and line[0,1] == "=" # it's a headline if the line begins with a "[" and ends with a "]" if line[0,1] == "[" and line[line.length - 1, line.length] == "]" # get rid of the [] and unnecessary spaces headline = line[1, line.length - 2 ].strip inihash[headline] = {} else key, value = line.split(/=/, 2) key = key.strip unless key.nil? value = value.strip unless value.nil? unless headline.nil? inihash[headline][key] = value else inihash[key] = value unless key.nil? end end end end inihash end # # Reading comments from file # # path - a path to the INI file # # Returns a `String` with the comments from the beginning of the INI file. # def self.read_comment_from_file(path) comment = "" IO.foreach(path) do |line| line.strip! break unless line[0,1] == "#" or line == "" comment_line = line[1, line.length].to_s comment << "#{comment_line.strip}\n" end comment end # # Writing a ini hash into a file # # path - Path to the INI file. # inihash - Hash representing the ini File. Default is a empty hash. # comment - String with comments which appear on the # top of the file. Each line will get a "#" before. # Default is no comment. # def self.write_to_file(path, inihash={}, comment=nil) raise TypeError, "String expected" unless comment.is_a? String or comment.nil? raise TypeError, "Hash expected" unless inihash.is_a? Hash File.open(path, "w") { |file| unless comment.nil? comment.each do |line| file << "# #{line}" end end file << IniHash.text(inihash) } end # # Turn a hash (up to 2 levels deepness) into a ini string # # inihash - Hash representing the ini File. Default is a empty hash. # # Returns a String in the ini file format. # # TODO: Rename `IniHash.text` method to something else ? # def self.text(inihash={}) new(inihash).to_s end class << self # @deprecated alias_method :to_s, :text end end end hashery-2.1.2/lib/hashery/query_hash.rb0000644000004100000410000000430612712231704020117 0ustar www-datawww-datamodule Hashery require 'hashery/key_hash' # QueryHash is essentially a Hash class, but with some OpenStruct-like features. # # q = QueryHash.new # # Entries can be added to the Hash via a setter method. # # q.a = 1 # # Then looked up via a query method. # # q.a? #=> 1 # # The can also be looked up via a bang method. # # q.a! #=> 1 # # The difference between query methods and bang methods is that the bang method # will auto-instantiate the entry if not present, where as a query method will not. # # A QueryHash might not be quite as elegant as an OpenHash in that reader # methods must end in `?` or `!`, but it remains fully compatible with Hash # regardless of it's settings. # class QueryHash < CRUDHash # # By default the `key_proc` is set to convert all keys to strings via `#to_s`. # # default - Default object, or # default_proc - Default procedure. # def initialize(*default, &default_proc) @key_proc = Proc.new{ |k| k.to_s } super(*default, &default_proc) end # # Route get and set calls. # # s - [Symbol] Name of method. # a - [Array] Method arguments. # b - [Proc] Block argument. # # Examples # # o = QueryHash.new # o.a = 1 # o.a? #=> 1 # o.b? #=> nil # def method_missing(s,*a, &b) type = s.to_s[-1,1] name = s.to_s.sub(/[!?=]$/, '') key = name #key = cast_key(name) case type when '=' store(key, a.first) when '!' default = (default_proc ? default_proc.call(self, key) : default) key?(key) ? fetch(key) : store(key, default) when '?' key?(key) ? fetch(key) : nil else # return self[key] if key?(key) super(s,*a,&b) end end # # Custom #respond_to to account for #method_missing. # # name - The method name to check. # # Returns `true` or `false`. # def respond_to?(name) return true if name.to_s.end_with?('=') return true if name.to_s.end_with?('?') return true if name.to_s.end_with?('!') #key?(name.to_sym) || super(name) super(name) end end end hashery-2.1.2/lib/hashery/path_hash.rb0000644000004100000410000001550312712231704017707 0ustar www-datawww-datamodule Hashery # A PathHash is a hash whose values can be accessed in the normal manner, # or with keys that are slash (`/`) separated strings. To get the whole hash # as a single flattened level, call `#flat`. All keys are converted to strings. # All end-of-the-chain values are kept in whatever value they are. # # s = PathHash['a' => 'b', 'c' => {'d' => :e}] # s['a'] #=> 'b' # s['c'] #=> {slashed: 'd'=>:e} # s['c']['d'] #=> :e # s['c/d'] #=> :e # # PathHash is derived from the SlashedHash class in the HashMagic project # by Daniel Parker . # # Copyright (c) 2006 BehindLogic (http://hash_magic.rubyforge.org) # # Authors: Daniel Parker # # TODO: This class is very much a work in progess and will be substantially rewritten # for future versions. # class PathHash < Hash # # Initialize PathHash. # # hsh - Priming Hash. # def initialize(hsh={}) raise ArgumentError, "must be a hash or array of slashed values" unless hsh.is_a?(Hash) || hsh.is_a?(Array) @constructor = hsh.is_a?(Hash) ? hsh.class : Hash @flat = flatten_to_hash(hsh) end # Standard Hash methods, plus the overwritten ones #include StandardHashMethodsInRuby # Behaves like the usual Hash#[] method, but you can access nested hash # values by composing a single key of the traversing keys joined by '/': # # hash['c']['d'] # is the same as: # hash['c/d'] # def [](key) rg = Regexp.new("^#{key}/?") start_obj = if @constructor == OrderedHash @constructor.new((@flat.instance_variable_get(:@keys_in_order) || []).collect {|e| e.gsub(rg,'')}) else @constructor.new end v = @flat.has_key?(key) ? @flat[key] : self.class.new(@flat.reject {|k,v| !(k == key || k =~ rg)}.inject(start_obj) {|h,(k,v)| h[k.gsub(rg,'')] = v; h}) v.is_a?(self.class) && v.empty? ? nil : v end # # Same as above, except sets value rather than retrieving it. # def []=(key,value) @flat.reject! {|k,v| k == key || k =~ Regexp.new("^#{key}/")} if value.is_a?(Hash) flatten_to_hash(value).each do |hk,hv| @flat[key.to_s+'/'+hk.to_s] = hv end else @flat[key.to_s] = value end end def clear # :nodoc: @flat.clear end # # # def fetch(key,default=:ehisehoah0928309q98y30,&block) # :nodoc: value = @flat.has_key?(key) ? @flat[key] : self.class.new(@flat.reject {|k,v| !(k == key || k =~ Regexp.new("^#{key}/"))}.inject({}) {|h,(k,v)| h[k.split('/',2)[1]] = v; h}) if value.is_a?(self.class) && value.empty? if default == :ehisehoah0928309q98y30 if block_given? block.call(key) else raise IndexError end value else default end else value end end # # Delete entry from Hash. Slashed keys can be used here, too. # # key - The key to delete. # block - Produces the return value if key not found. # # Returns delete value. # def delete(key,&block) value = @flat.has_key?(key) ? @flat[key] : self.class.new(@flat.reject {|k,v| !(k == key || k =~ Regexp.new("^#{key}/"))}.inject({}) {|h,(k,v)| h[k.split('/',2)[1]] = v; h}) return block.call(key) if value.is_a?(self.class) && value.empty? && block_given? @flat.keys.reject {|k| !(k == key || k =~ Regexp.new("^#{key}/"))}.each {|k| @flat.delete(k)} return value end # def empty? @flat.empty? end # This gives you the slashed key of the value, no matter where the value is in the tree. def index(value) @flat.index(value) end # def inspect @flat.inspect.insert(1,'slashed: ') end # This gives you only the top-level keys, no slashes. To get the list of slashed keys, do hash.flat.keys def keys @flat.inject([]) {|a,(k,v)| a << [k.split('/',2)].flatten[0]; a}.uniq end # This is rewritten to mean something slightly different than usual: Use this to restructure the hash, for cases when you # end up with an array holding several hashes. def rehash # :nodoc: @flat.rehash end # Gives a list of all keys in all levels in the multi-level hash, joined by slashes. # # {'a'=>{'b'=>'c', 'c'=>'d'}, 'b'=>'c'}.slashed.flat.keys # #=> ['a/b', 'a/c', 'b'] # def flat @flat end # Expands the whole hash to Hash objects ... not useful very often, it seems. def expand inject({}) {|h,(k,v)| h[k] = v.is_a?(SlashedHash) ? v.expand : v; h} end def to_string_array flatten_to_array(flat,[]) end def slashed # :nodoc: self end # Same as ordered! but returns a new SlashedHash object instead of modifying the same. def ordered(*keys_in_order) dup.ordered!(*keys_in_order) end # Sets the SlashedArray as ordered. The *keys_in_order must be a flat array # of slashed keys that specify the order for each level: # # s = {'a'=>{'b'=>'c', 'c'=>'d'}, 'b'=>'c'}.slashed # s.ordered!('b', 'a/c', 'a/b') # s.expand # => {'b'=>'c', 'a'=>{'c'=>'d', 'b'=>'c'}} # # Note that the expanded hashes will *still* be ordered! # def ordered!(*keys_in_order) return self if @constructor == OrderedHash @constructor = OrderedHash @flat = @flat.ordered(*keys_in_order) self end # def ==(other) case other when SlashedHash @slashed == other.instance_variable_get(:@slashed) when Hash self == SlashedHash.new(other) else raise TypeError, "Cannot compare #{other.class.name} with SlashedHash" end end private def flatten_to_hash(hsh) flat = @constructor.new if hsh.is_a?(Array) hsh.each do |e| flat.merge!(flatten_to_hash(e)) end elsif hsh.is_a?(Hash) hsh.each do |k,v| if v.is_a?(Hash) flatten_to_hash(v).each do |hk,hv| flat[k.to_s+'/'+hk.to_s] = hv end else flat[k.to_s] = v end end else ks = hsh.split('/',-1) v = ks.pop ks = ks.join('/') if !flat[ks].nil? if flat[ks].is_a?(Array) flat[ks] << v else flat[ks] = [flat[ks], v] end else flat[ks] = v end end flat end def flatten_to_array(value,a) if value.is_a?(Array) value.each {|e| flatten_to_array(e,a)} elsif value.is_a?(Hash) value.inject([]) {|aa,(k,v)| flatten_to_array(v,[]).each {|vv| aa << k+'/'+vv.to_s}; aa}.each {|e| a << e} else a << value.to_s end a end end end hashery-2.1.2/lib/hashery/property_hash.rb0000644000004100000410000000704112712231704020635 0ustar www-datawww-datarequire 'hashery/crud_hash' module Hashery # A PropertyHash is the same as a regular Hash except it strictly limits the # allowed keys. # # There are two ways to use it. # # 1) As an object in itself. # # h = PropertyHash.new(:a=>1, :b=>2) # h[:a] #=> 1 # h[:a] = 3 # h[:a] #=> 3 # # But if we try to set key that was not fixed, then we will get an error. # # h[:x] = 5 #=> ArgumentError # # 2) As a superclass. # # class MyPropertyHash < PropertyHash # property :a, :default => 1 # property :b, :default => 2 # end # # h = MyPropertyHash.new # h[:a] #=> 1 # h[:a] = 3 # h[:a] #=> 3 # # Again, if we try to set key that was not fixed, then we will get an error. # # h[:x] = 5 #=> ArgumentError # class PropertyHash < CRUDHash # # Get a list of properties with default values. # # Returns [Hash] of properties and their default values. # def self.properties @properties ||= ( parent = ancestors[1] if parent.respond_to?(:properties) parent.properties else {} end ) end # # Define a property. # # key - Name of property. # opts - Property options. # :default - Default value of property. # # Returns default value. # def self.property(key, opts={}) properties[key] = opts[:default] end # # Initialize new instance of PropertyHash. # # properties - [Hash] Priming properties with default values, or # if it doesn't respond to #each_pair, a default object. # default_proc - [Proc] Procedure for default value of properties # for properties without specific defaults. # def initialize(properties={}, &default_proc) if properties.respond_to?(:each_pair) super(&default_proc) fixed = self.class.properties.merge(properties) fixed.each_pair do |key, value| store!(key, value) end else super(*[properties].compact, &default_proc) end end # Alias original #store method and make private. alias :store! :store private :store! # # Create a new property, on-the-fly. # # key - Name of property. # opts - Property options. # :default - Default value of property. # # Returns default value. # def property(key, opts={}) if opts[:default] store!(key, opts[:default]) else store!(key, retrieve(key)) end end # # Store key value pair, ensuring the key is a valid property first. # # key - The `Object` to act as indexing key. # value - The `Object` to associate with key. # # Raises ArgumentError if key is not a valid property. # # Returns +value+. # def store(key, value) assert_key!(key) super(key, value) end # #def update(h) # h.keys.each{ |k| assert_key!(k) } # super(h) #end # #def merge!(h) # h.keys.each{ |k| assert_key!(k) } # super(h) #end # # Like #store but takes a two-element Array of `[key, value]`. # # Returns value. # #def <<(a) # k,v = *a # store(k,v) #end private # # Asserta that a key is a defined property. # # Raises ArgumentError if key is not a property. # def assert_key!(key) unless key?(key) raise ArgumentError, "property is not defined -- #{key.inspect}" end end end end hashery-2.1.2/lib/hashery/stash.rb0000644000004100000410000000031312712231704017063 0ustar www-datawww-datarequire 'hashery/key_hash' module Hashery # Stash is the original name for the KeyHash. Stash = KeyHash end class Hash # Convert Hash to Stash. def to_stash Hashery::Stash[self] end end hashery-2.1.2/lib/hashery/association.rb0000644000004100000410000001112412712231704020257 0ustar www-datawww-datamodule Hashery # TODO: Should associations be singleton? # # TODO: Is it really wise to keep a table of all associations? # Association is a general binary association that allows one # object to be associated with another. It has a variety of uses, # such as linked-lists, simple ordered maps and mixed collections, # among them. # # NOTE: This class is still fairly experimental. And it is not # loaded along with the other Hashery libraries when using # `require 'hashery'`. It must be required independently. # # Associations can be used to draw simple relationships. # # :Apple >> :Fruit # :Apple >> :Red # # :Apple.associations #=> [ :Fruit, :Red ] # # It can also be used for simple lists of ordered pairs. # # c = [ :a >> 1, :b >> 2 ] # c.each { |k,v| puts "#{k} associated with #{v} } # # produces # # a associated with 1 # b associated with 2 # # The method :>> is used to construct the association. # It is a rarely used method so it is generally available. # But you can't use it for any of the following classes # becuase they use #>> for other things. # # Bignum # Fixnum # Date # IPAddr # Process::Status # class Association include Comparable class << self # # Store association references. # # Returns `Hash` of all associaitons. # def reference @reference ||= Hash.new{ |h,k,v| h[k]=[] } end # # Shortcut for #new. # # index - The "index key" of the association. # value - The "value" of the association. # # Returns `Association`. # def [](index, value) new(index, value) end #def new(index, value) # lookup[[index, value]] ||= new(index, value) #end #def lookup # @lookup ||= {} #end end # # The "index key" of the association. # attr_accessor :index # # The "value" of the association. # attr_accessor :value # # Initialize new Association. # # index - The "index key" of the association. # value - The "value" of the association. # def initialize(index, value=nil) @index = index @value = value unless index.associations.include?(value) index.associations << value end end # # Compare the values of two associations. # # TODO: Comparions with non-associations? # # assoc - The other `Association`. # # Returns [Integer] `1`, `0`, or `-1`. # def <=>(assoc) return -1 if self.value < assoc.value return 1 if self.value > assoc.value return 0 if self.value == assoc.value end # # Invert association, making the index the value and vice-versa. # # Returns [Array] with two-elements reversed. # def invert! temp = @index @index = @value @value = temp end # # Produce a string representation. # # Returns [String]. # def to_s return "#{index} >> #{value}" end # # Produce a literal code string for creating an association. # # Returns [String]. # def inspect "#{index.inspect} >> #{value.inspect}" end # # Convert to two-element associative array. # # Returns [Array] Two-element Array of index and value pair. # def to_ary [index, value] end # # Object extensions. # module Kernel # # Define an association for +self+. # # to - The value of the association. # # Returns [Association]. # def >>(to) Association.new(self, to) end # # List of associations for this object. # # Returns an `Array` of `Associations`. # def associations Association.reference[self] end end end end class Object #:nodoc: include Hashery::Association::Kernel end #-- # Setup the >> method in classes that use it already. # # This is a bad idea b/c it can cause backward compability issues. # # class Bignum # alias_method( :rshift, :>>) if method_defined?(:>>) # remove_method :>> # end # # class Fixnum # alias_method( :rshift, :>>) if method_defined?(:>>) # remove_method :>> # end # # class Date # alias_method( :months_later, :>>) if method_defined?(:>>) # remove_method :>> # end # # class IPAddr # alias_method( :rshift, :>>) if method_defined?(:>>) # remove_method :>> # end # # class Process::Status # alias_method( :rshift, :>>) if method_defined?(:>>) # remove_method :>> # end #++ # Copyright (c) 2005 Rubyworks, Thomas Sawyer hashery-2.1.2/lib/hashery/dictionary.rb0000644000004100000410000003072212712231704020115 0ustar www-datawww-datamodule Hashery # The Dictionary class is a Hash that preserves order. # So it has some array-like extensions also. By defualt # a Dictionary object preserves insertion order, but any # order can be specified including alphabetical key order. # # Using a Dictionary is almost the same as using a Hash. # # # You can do simply # hsh = Dictionary.new # hsh['z'] = 1 # hsh['a'] = 2 # hsh['c'] = 3 # p hsh.keys #=> ['z','a','c'] # # # or using Dictionary[] method # hsh = Dictionary['z', 1, 'a', 2, 'c', 3] # p hsh.keys #=> ['z','a','c'] # # # but this don't preserve order # hsh = Dictionary['z'=>1, 'a'=>2, 'c'=>3] # p hsh.keys #=> ['a','c','z'] # # # Dictionary has useful extensions: push, pop and unshift # p hsh.push('to_end', 15) #=> true, key added # p hsh.push('to_end', 30) #=> false, already - nothing happen # p hsh.unshift('to_begin', 50) #=> true, key added # p hsh.unshift('to_begin', 60) #=> false, already - nothing happen # p hsh.keys #=> ["to_begin", "a", "c", "z", "to_end"] # p hsh.pop #=> ["to_end", 15], if nothing remains, return nil # p hsh.keys #=> ["to_begin", "a", "c", "z"] # p hsh.shift #=> ["to_begin", 30], if nothing remains, return nil # # == Notes # # * You can use #order_by to set internal sort order. # * #<< takes a two element [k,v] array and inserts. # * Use ::auto which creates Dictionay sub-entries as needed. # * And ::alpha which creates a new Dictionary sorted by key. # # == Acknowledgments # # Dictionary is a port of OrderHash 2.0 Copyright (c) 2005 Jan Molic. # # People who have contributed to this class since then include: # # * Andrew Johnson (merge, to_a, inspect, shift and Hash[]) # * Jeff Sharpe (reverse and reverse!) # * Thomas Leitner (has_key? and key?) # # OrderedHash is public domain. # class Dictionary include Enumerable class << self # # Create a new Dictionary storing argument pairs as an initial mapping. # # TODO: Is this needed? Doesn't the super class do this? # # Returns Dictionary instance. # def [](*args) hsh = new if Hash === args[0] hsh.replace(args[0]) elsif (args.size % 2) != 0 raise ArgumentError, "odd number of elements for Hash" else while !args.empty? hsh[args.shift] = args.shift end end hsh end # # Like #new but the block sets the order instead of the default. # # Dictionary.new_by{ |k,v| k } # def new_by(*args, &blk) new(*args).order_by(&blk) end # # Alternate to #new which creates a dictionary sorted by the key as a string. # # d = Dictionary.alphabetic # d["z"] = 1 # d["y"] = 2 # d["x"] = 3 # d #=> {"x"=>3,"y"=>2,"z"=>2} # # This is equivalent to: # # Dictionary.new.order_by { |key,value| key.to_s } # def alphabetic(*args, &block) new(*args, &block).order_by { |key,value| key.to_s } end # DEPRECATED: Use #alphabetic instead. alias :alpha :alphabetic # # Alternate to #new which auto-creates sub-dictionaries as needed. # # Examples # # d = Dictionary.auto # d["a"]["b"]["c"] = "abc" #=> { "a"=>{"b"=>{"c"=>"abc"}}} # def auto(*args) #AutoDictionary.new(*args) leet = lambda { |hsh, key| hsh[key] = new(&leet) } new(*args, &leet) end end # # New Dictiionary. # def initialize(*args, &blk) @order = [] @order_by = nil if blk dict = self # This ensures automatic key entry effect the oblk = lambda{ |hsh, key| blk[dict,key] } # dictionary rather then just the interal hash. @hash = Hash.new(*args, &oblk) else @hash = Hash.new(*args) end end # # Order of keys. # # Returns [Array]. # def order reorder if @order_by @order end # # Keep dictionary sorted by a specific sort order. # # block - Ordering procedure. # # Returns +self+. # def order_by( &block ) @order_by = block order self end # # Keep dictionary sorted by key. # # d = Dictionary.new.order_by_key # d["z"] = 1 # d["y"] = 2 # d["x"] = 3 # d #=> {"x"=>3,"y"=>2,"z"=>2} # # This is equivalent to: # # Dictionary.new.order_by { |key,value| key } # # The initializer Dictionary#alpha also provides this. # # Returns +self+. # def order_by_key if block_given? @order_by = Proc.new{ |k,v| yield(k) } else @order_by = Proc.new{ |k,v| k } end order self end # # Keep dictionary sorted by value. # # d = Dictionary.new.order_by_value # d["z"] = 1 # d["y"] = 2 # d["x"] = 3 # d #=> {"x"=>3,"y"=>2,"z"=>2} # # This is equivalent to: # # Dictionary.new.order_by { |key,value| value } # def order_by_value if block_given? @order_by = Proc.new{ |k,v| yield(v) } else @order_by = Proc.new{ |k,v| v } end order self end # # Re-apply the sorting procedure. # def reorder if @order_by assoc = @order.collect{ |k| [k,@hash[k]] }.sort_by(&@order_by) @order = assoc.collect{ |k,v| k } end @order end #def ==( hsh2 ) # return false if @order != hsh2.order # super hsh2 #end # # Is the dictionary instance equivalent to another? # def ==(hsh2) if hsh2.is_a?( Dictionary ) @order == hsh2.order && @hash == hsh2.instance_variable_get("@hash") else false end end # # Lookup entry with key. # def [] key @hash[ key ] end # # Featch entry given +key+. # def fetch(key, *a, &b) @hash.fetch(key, *a, &b) end # # Store operator. # # h[key] = value # # Or with additional index. # # h[key,index] = value # def []=(k, i=nil, v=nil) if v insert(i,k,v) else store(k,i) end end # # Insert entry into dictionary at specific index position. # # index - [Integer] Position of order placement. # key - [Object] Key to associate with value. # value - [Object] Value to associate with key. # # Returns `value` stored. # def insert(index, key, value) @order.insert(index, key) @hash.store(key, value) end # # Add entry into dictionary. # # Returns `value`. # def store(key, value) @order.push(key) unless @hash.has_key?(key) @hash.store(key, value) end # # Clear dictionary of all entries. # def clear @order = [] @hash.clear end # # Delete the entry with given +key+. # def delete(key) @order.delete(key) @hash.delete(key) end # # Iterate over each key. # def each_key order.each { |k| yield( k ) } self end # # Iterate over each value. # def each_value order.each { |k| yield( @hash[k] ) } self end # # Iterate over each key-value pair. # def each order.each { |k| yield( k,@hash[k] ) } self end alias each_pair each # # Delete entry if it fits conditional block. # def delete_if order.clone.each { |k| delete k if yield(k,@hash[k]) } self end # # List of all dictionary values. # # Returns [Array]. # def values ary = [] order.each { |k| ary.push @hash[k] } ary end # # List of all dictionary keys. # # Returns [Array]. # def keys order end # # Invert the dictionary. # # Returns [Dictionary] New dictionary that is inverse of the original. # def invert hsh2 = self.class.new order.each { |k| hsh2[@hash[k]] = k } hsh2 end # # Reject entries based on give condition block and return # new dictionary. # # Returns [Dictionary]. # def reject(&block) self.dup.delete_if(&block) end # # Reject entries based on give condition block. # # Returns [Hash] of rejected entries. # # FIXME: This looks like it is implemented wrong!!! # def reject!( &block ) hsh2 = reject(&block) self == hsh2 ? nil : hsh2 end # # Replace dictionary entries with new table. # def replace(hsh2) case hsh2 when Dictionary @order = hsh2.order @hash = hsh2.to_h when Hash @hash = hsh2 @order = @hash.keys else @hash = hsh2.to_h @order = @hash.keys end reorder end # # Remove entry from the to top of dictionary. # def shift key = order.first key ? [key,delete(key)] : super end # # Push entry on to the top of dictionary. # def unshift( k,v ) unless @hash.include?( k ) @order.unshift( k ) @hash.store( k,v ) true else false end end # # Same as #push. # def <<(kv) push(*kv) end # # Push entry on to bottom of the dictionary. # def push(k,v) unless @hash.include?( k ) @order.push( k ) @hash.store( k,v ) true else false end end # # Pop entry off the bottom of dictionary. # def pop key = order.last key ? [key,delete(key)] : nil end # # Inspection string for Dictionary. # # Returns [String]. # def inspect ary = [] each {|k,v| ary << k.inspect + "=>" + v.inspect} '{' + ary.join(", ") + '}' end # # Duplicate dictionary. # # Returns [Dictionary]. # def dup a = [] each{ |k,v| a << k; a << v } self.class[*a] end # # Update dictionary with other hash. # # Returns self. # def update( hsh2 ) hsh2.each { |k,v| self[k] = v } reorder self end alias :merge! update # # Merge other hash creating new dictionary. # # Returns [Dictionary]. # def merge(hsh2) self.dup.update(hsh2) end # # Select items from dictiornary. # # Returns [Array] of two-element arrays. # def select ary = [] each { |k,v| ary << [k,v] if yield k,v } ary end # # Reverse the order of the dictionary. # # Returns self. # def reverse! @order.reverse! self end # # Reverse the order of duplicte dictionary. # # Returns [Dictionary]. # def reverse dup.reverse! end # # Get/set initial entry value. # def first(x=nil) return @hash[order.first] unless x order.first(x).collect { |k| @hash[k] } end # # Get/set last entry value. # def last(x=nil) return @hash[order.last] unless x order.last(x).collect { |k| @hash[k] } end # # Number of items in the dictionary. # def length @order.length end alias :size :length # # Is the dictionary empty? # # Returns `true` or `false`. # def empty? @hash.empty? end # # Does the dictionary have a given +key+. # # Returns `true` or `false`. # def has_key?(key) @hash.has_key?(key) end # # Does the dictionary have a given +key+. # # Returns `true` or `false`. # def key?(key) @hash.key?(key) end # # Convert to array. # # Returns [Array] of two-element arrays. # def to_a ary = [] each { |k,v| ary << [k,v] } ary end # # Convert to array then to string. # # Returns [String]. # def to_s self.to_a.to_s end # # Get a duplicate of the underlying hash table. # # Returns [Hash]. # def to_hash @hash.dup end # # Get a duplicate of the underlying hash table. # # Returns [Hash]. # def to_h @hash.dup end protected # # Underlying hash table. # def hash_table @hash end end end hashery-2.1.2/lib/hashery/ordered_hash.rb0000644000004100000410000000627512712231704020405 0ustar www-datawww-datamodule Hashery # OrderedHash is a simple ordered hash implmentation, for users of # Ruby 1.8.7 or less. # # NOTE: As of Ruby 1.9+ this class is not needed, since # Ruby 1.9's standard Hash tracks inseration order. # # This implementation derives from the same class in # ActiveSupport library. # class OrderedHash < ::Hash def to_yaml_type "!tag:yaml.org,2002:omap" end def to_yaml(opts = {}) YAML.quick_emit(self, opts) do |out| out.seq(taguri, to_yaml_style) do |seq| each do |k, v| seq.add(k => v) end end end end # Hash is ordered in Ruby 1.9! if RUBY_VERSION < '1.9' def initialize(*args, &block) super @keys = [] end def self.[](*args) ordered_hash = new if (args.length == 1 && args.first.is_a?(Array)) args.first.each do |key_value_pair| next unless (key_value_pair.is_a?(Array)) ordered_hash[key_value_pair[0]] = key_value_pair[1] end return ordered_hash end unless (args.size % 2 == 0) raise ArgumentError.new("odd number of arguments for Hash") end args.each_with_index do |val, ind| next if (ind % 2 != 0) ordered_hash[val] = args[ind + 1] end ordered_hash end def initialize_copy(other) super(other) @keys = other.keys end def []=(key, value) @keys << key unless key?(key) super(key, value) end def delete(key) if has_key? key index = @keys.index(key) @keys.delete_at(index) end super(key) end def delete_if super sync_keys! self end def reject! super sync_keys! self end def reject(&block) dup.reject!(&block) end def keys @keys.dup end def values @keys.collect{ |key| self[key] } end def to_hash self end def to_a @keys.map{ |key| [ key, self[key] ] } end def each_key @keys.each{ |key| yield(key) } end def each_value @keys.each{ |key| yield(self[key]) } end def each @keys.each{ |key| yield(key, self[key]) } end alias_method :each_pair, :each def clear super @keys.clear self end def shift k = @keys.first v = delete(k) [k, v] end def merge!(other_hash) other_hash.each{ |k,v| self[k] = v } self end def merge(other_hash) dup.merge!(other_hash) end # When replacing with another hash, the initial order of our # keys must come from the other hash, ordered or not. def replace(other) super @keys = other.keys self end def inspect "#" end private def sync_keys! @keys.delete_if{ |k| !key?(k) } end end end end require 'yaml' YAML.add_builtin_type("omap") do |type, val| OrderedHash[val.map(&:to_a).map(&:first)] end hashery-2.1.2/lib/hashery/fuzzy_hash.rb0000644000004100000410000000770412712231704020146 0ustar www-datawww-datarequire 'set' module Hashery # FuzzyHash is a weird hash with special semantics for regex keys. # # This is useful when you want to have a lookup table that can either contain strings or regexes. # For instance, you might want a catch all for certain regexes that perform a certain logic. # # >> hash = FuzzyHash.new # >> hash[/^\d+$/] = 'number' # >> hash[/.*/] = 'something' # >> hash['chunky'] = 'bacon' # >> hash['foo'] = 'vader' # # >> hash['foo'] # << 'vader' # >> hash['food'] # << 'something' # >> hash['123'] # << 'number' # # This class is based on Joshua Hull's original FuzzyHash class. # class FuzzyHash # # # def initialize(init_hash = nil) @fuzzies = [] @hash_reverse = {} @fuzzies_reverse = {} @fuzzy_hash = {} @hash = {} init_hash.each{ |key,value| self[key] = value } if init_hash end # # # def clear hash.clear fuzzies.clear hash_reverse.clear fuzzies_reverse.clear end # # # def size hash.size + fuzzies.size end alias_method :count, :size # # # def ==(o) o.is_a?(FuzzyHash) o.send(:hash) == hash && o.send(:fuzzies) == fuzzies end # # # def empty? hash.empty? && fuzzies.empty? end # # # def keys hash.keys + fuzzy_hash.keys end # # # def values hash.values + fuzzies.collect{|r| r.last} end # # # def each hash.each{|k,v| yield k,v } fuzzies.each{|v| yield v.first, v.last } end # # # def delete_value(value) hash.delete(hash_reverse[value]) || ((rr = fuzzies_reverse[value]) && fuzzies.delete_at(rr[0])) end # # # def []=(key, value) if Regexp === key fuzzies.delete_if{|f| f.first.inspect.hash == key.inspect.hash} fuzzies_reverse.delete_if{|k, v| v[1].inspect.hash == key.inspect.hash} hash_reverse.delete_if{|k,v| v.inspect.hash == key.inspect.hash} fuzzy_hash[key] = value fuzzies << [key, value] reset_fuzz_test! fuzzies_reverse[value] = [fuzzies.size - 1, key, value] else hash[key] = value hash_reverse.delete_if{|k,v| v.hash == key.hash} hash_reverse[value] = key end value end # # # def replace(src, dest) if hash_reverse.key?(src) key = hash_reverse[src] hash[key] = dest hash_reverse.delete(src) hash_reverse[dest] = key elsif fuzzies_reverse.key?(src) key = fuzzies_reverse[src] fuzzies[rkey[0]] = [rkey[1], dest] fuzzies_reverse.delete(src) fuzzies_reverse[dest] = [rkey[0], rkey[1], dest] end end # # # def [](key) (hash.key?(key) && hash[key]) || ((lookup = fuzzy_lookup(key)) && lookup && lookup.first) || fuzzy_hash[key] end # # # def match_with_result(key) if hash.key?(key) [hash[key], key] else fuzzy_lookup(key) end end private attr_reader :fuzzies, :hash_reverse, :fuzzies_reverse, :hash, :fuzzy_hash attr_writer :fuzz_test # # # def reset_fuzz_test! self.fuzz_test = nil end # # # def fuzz_test unless @fuzz_test @fuzz_test = Object.new @fuzz_test.instance_variable_set(:'@fuzzies', fuzzies) method = " def match(str) case str\n " fuzzies.each_with_index do |reg, index| method << "when #{reg.first.inspect}; [@fuzzies[#{index}][1], Regexp.last_match(0)];" end method << "end\nend\n" @fuzz_test.instance_eval method end @fuzz_test end # # # def fuzzy_lookup(key) if !fuzzies.empty? && (value = fuzz_test.match(key)) value end end end end # Copyright (c) 2009 Joshua Hull hashery-2.1.2/lib/hashery/open_hash.rb0000644000004100000410000000700012712231704017705 0ustar www-datawww-datarequire 'hashery/crud_hash' module Hashery # OpenHash is a Hash, but also supports open properties much like # OpenStruct. # # Only names that are name methods of Hash can be used as open slots. # To open a slot for a name that would otherwise be a method, the # method needs to be made private. The `#open!` method can be used # to handle this. # # Examples # # o = OpenHash.new # o.open!(:send) # o.send = 4 # class OpenHash < CRUDHash alias :object_class :class #FILTER = /(^__|^\W|^instance_|^object_|^to_)/ #methods = Hash.instance_methods(true).select{ |m| m !~ FILTER } #methods = methods - [:each, :inspect, :send] # :class, :as] #private *methods # # Initialize new OpenHash instance. # # TODO: Maybe `safe` should be the first argument? # def initialize(default=nil, safe=false, &block) @safe = safe super(*[default].compact, &block) end # # If safe is set to true, then public methods cannot be overriden # by hash keys. # attr_accessor :safe # # Alias to original store method. # #alias :store! :store # # Index `value` to `key`. Unless safe mode, will also open up the # key if it is not already open. # # key - Index key to associate with value. # value - Value to be associate with key. # # Returns +value+. # def store(key, value) #open!(key) super(key, value) end # # Open up a slot that that would normally be a Hash method. # # The only methods that can't be opened are ones starting with `__`. # # methods - [Array] method names # # Returns Array of slot names that were opened. # def open!(*methods) # Only select string and symbols, any other type of key is allowed, # it just won't be accessible via dynamic methods. methods = methods.select{ |x| String === x || Symbol === x } if methods.any?{ |m| m.to_s.start_with?('__') } raise ArgumentError, "cannot open shadow methods" end # only public methods need be made protected methods = methods.map{ |x| x.to_sym } methods = methods & public_methods(true).map{ |x| x.to_sym } if @safe raise ArgumentError, "cannot set public method" unless methods.empty? else (class << self; self; end).class_eval{ protected *methods } end methods end # @deprecated alias :omit! :open! # # Is a slot open? # # method - [String,Symbol] method name # # Returns `true` or `false`. # def open?(method) methods = public_methods(true).map{ |m| m.to_sym } ! methods.include?(method.to_sym) end # # Make specific Hash methods available for use that have previously opened. # # methods - [Array] method names # # Returns +methods+. # def close!(*methods) (class << self; self; end).class_eval{ public *methods } methods end # # # def method_missing(s,*a, &b) type = s.to_s[-1,1] name = s.to_s.sub(/[!?=]$/, '') key = name.to_sym case type when '=' store(key, a.first) when '?' key?(key) when '!' # call an underlying private method # TODO: limit this to omitted methods (from included) ? __send__(name, *a, &b) else #if key?(key) retrieve(key) #else # super(s,*a,&b) #end end end end end hashery-2.1.2/lib/hashery/lru_hash.rb0000644000004100000410000001315012712231704017551 0ustar www-datawww-datarequire 'enumerator' module Hashery # Hash with LRU expiry policy. There are at most max_size elements in a # LRUHash. When adding more elements old elements are removed according # to LRU policy. # # Based on Robert Klemme's LRUHash class. # # LRUHash, Copyright (c) 2010 Robert Klemme. # class LRUHash include Enumerable attr_reader :max_size attr_accessor :default attr_accessor :default_proc attr_accessor :release_proc # # Initialize new LRUHash instance. # # max_size - # default_value - # block - # def initialize(max_size, default_value=nil, &block) @max_size = normalize_max(max_size) @default = default_value @default_proc = block @h = {} @head = Node.new @tail = front(Node.new) end # # Iterate over each pair. # def each_pair if block_given? each_node do |n| yield [n.key, n.value] end else enum_for :each_pair end end # # Same as each pair. # alias each each_pair # # Iterate over each key. # def each_key if block_given? each_node do |n| yield n.key end else enum_for :each_key end end # # Iterate over each value. # def each_value if block_given? each_node do |n| yield n.value end else enum_for :each_value end end # # Size of the hash. # def size @h.size end # # # def empty? @head.succ.equal? @tail end # # # def fetch(key, &b) n = @h[key] if n front(n).value else (b || FETCH)[key] end end # # # def [](key) fetch(key) do |k| @default_proc ? @default_proc[self, k] : default end end # # # def keys @h.keys end # # # def values @h.map {|k,n| n.value} end # # # def has_key?(key) @h.has_key? key end alias key? has_key? alias member? has_key? alias include? has_key? # # # def has_value?(value) each_pair do |k, v| return true if value.eql? v end false end alias value? has_value? def values_at(*key_list) key_list.map {|k| self[k]} end # # # def assoc(key) n = @h[key] if n front(n) [n.key, n.value] end end # # # def rassoc(value) each_node do |n| if value.eql? n.value front(n) return [n.key, n.value] end end nil end # # # def key(value) pair = rassoc(value) and pair.first end # # # def store(key, value) # same optimization as in Hash key = key.dup.freeze if String === key && !key.frozen? n = @h[key] unless n if size == max_size # reuse node to optimize memory usage n = delete_oldest n.key = key n.value = value else n = Node.new key, value end @h[key] = n end front(n).value = value end alias []= store # # # def delete(key) n = @h[key] and remove_node(n).value end # # # def delete_if each_node do |n| remove_node n if yield n.key, n.value end end # # # def max_size=(limit) limit = normalize_max(limit) while size > limit delete_oldest end @max_size = limit end # # # def clear until empty? delete_oldest end self end # # # def to_s s = nil each_pair {|k, v| (s ? (s << ', ') : s = '{') << k.to_s << '=>' << v.to_s} s ? (s << '}') : '{}' end alias inspect to_s private # # Iterate nodes. # def each_node n = @head.succ until n.equal? @tail succ = n.succ yield n n = succ end self end # # Move node to front. # # node - [Node] # def front(node) node.insert_after(@head) end # # Remove the node and invoke release_proc # if set # # node - [Node] # def remove_node(node) n = @h.delete(node.key) n.unlink release_proc and release_proc[n.key, n.value] n end # # Remove the oldest node returning the node # def delete_oldest n = @tail.pred raise "Cannot delete from empty hash" if @head.equal? n remove_node n end # # Normalize the argument in order to be usable as max_size # criterion is that n.to_i must be an Integer and it must # be larger than zero. # # n - [#to_i] max size # def normalize_max(n) n = n.to_i raise ArgumentError, 'Invalid max_size: %p' % n unless Integer === n && n > 0 n end # FETCH = Proc.new {|k| raise KeyError, 'key not found'} # A single node in the doubly linked LRU list of nodes. Node = Struct.new :key, :value, :pred, :succ do def unlink pred.succ = succ if pred succ.pred = pred if succ self.succ = self.pred = nil self end def insert_after(node) raise 'Cannot insert after self' if equal? node return self if node.succ.equal? self unlink self.succ = node.succ self.pred = node node.succ.pred = self if node.succ node.succ = self self end end end end hashery-2.1.2/lib/hashery/crud_hash.rb0000644000004100000410000002121412712231704017704 0ustar www-datawww-datarequire 'hashery/core_ext' module Hashery # The CRUDHash is essentailly the same as the Hash class, but it reduces the # the set of necessary methods to the fundametal CRUD requirements. All other # methods route through these CRUD methods. This is a better general design, # although it is, of course, a little bit slower. The utility of this class # becomes appearent when subclassing or delegating, as only a handful of methods # need to be changed for all other methods to work accordingly. # # In addition to the CRUD features, CRUDHash supports a `#key_proc`, akin to # `#default_proc`, that can be used to normalize keys. # # The CRUD methods are: # # * key? # * fetch # * store # * delete # # In addition to these main methods, there are these supporting "CRUD" methods: # # * default # * default_proc # * default_proc= # * key_proc # * key_proc= # class CRUDHash < ::Hash # # Dummy object for null arguments. # NA = Object.new # # This method is overridden to ensure that new entries pass through # the `#store` method. # # hash - [#each] Single Hash, associative array or just a list of pairs. # def self.[](*hash) h = new if hash.size == 1 hash.first.each do |k,v| h.store(k, v) end else hash.each do |(k,v)| h.store(k, v) end end h end # # Alternate to #new which auto-creates sub-dictionaries as needed. # By default the `default_proc` procuced a empty Hash and is # self-referential so every such Hash also has the same `default_proc`. # # args - Pass-thru arguments to `#new`. # block - Alternate internal procedure for default proc. # # Examples # # d = CRUDHash.auto # d["a"]["b"]["c"] = "abc" #=> { "a"=>{"b"=>{"c"=>"abc"}}} # # Returns `Hash`. # def self.auto(*args, &block) if block leet = lambda { |hsh, key| hsh[key] = block.call(hsh, key) } else leet = lambda { |hsh, key| hsh[key] = new(&leet) } end new(*args, &leet) end # # Set `key_proc`. # # Examples # # ch = CRUDHash.new # ch.key_proc = Proc.new{ |key| key.to_sym } # # Returns `Proc`. # def key_proc=(proc) raise ArgumentError unless Proc === proc or NilClass === proc @key_proc = proc end # # Get/set `key_proc`. # # Examples # # ch = CRUDHash.new # ch.key_proc # # Returns `Proc`. # def key_proc(&block) @key_proc = block if block @key_proc end # # Allow `#default_proc` to take a block. # # block - The `Proc` object to set the `default_proc`. # # Returns `Proc`, the `default_proc`. # def default_proc(&block) self.default_proc = block if block super() end # # CRUD method for checking if key exists. # # key - Hash key to lookup. # # Returns `true/false`. # def key?(key) super cast_key(key) end # # CRUD method for read. This method gets the value for a given key. # An error is raised if the key is not present, but an optional argument # can be provided to be returned instead. # # key - Hash key to lookup. # default - Value to return if key is not present. # # Raises KeyError when key is not found and default has not been given. # # Returns the `Object` that is the Hash entry's value. # def fetch(key, *default) super(cast_key(key), *default) end # # CRUD method for create and update. # # key - The `Object` to act as indexing key. # value - The `Object` to associate with key. # # Returns +value+. # def store(key, value) super(cast_key(key), value) end # # CRUD method for delete. # # key - Hash key to remove. # # Returns value of deleted Hash entry. # def delete(key) super cast_key(key) end # END OF CRUD METHODS # # Like #fetch but returns the results of calling `default_proc`, if defined, # otherwise `default`. # # key - Hash key to lookup. # # Returns value of Hash entry or `nil`. # def retrieve(key) if key?(key) fetch(key) else default_proc ? default_proc.call(self, key) : default end end # # Method for reading value. Returns `nil` if key is not present. # # Note that this method used to be the CRUD method instead of #retrieve. Complaints about # #read being indicative of an IO object (though in my opinion that is a bad asumption) have # led to this method's deprecation. # # key - Hash key to lookup. # # Returns value of Hash entry. # def read(key) warn "The #read method as been deprecated. Use #retrieve instead." retrieve(key) end # # Update Hash with +assoc+. # # assoc - Two-element `Array` or a `Hash`. # # Returns +assoc+. # def <<(assoc) case assoc when Hash update(assoc) when Array assoc.each_slice(2) do |(k,v)| store(k,v) end else raise ArgumentError # or TypeError ? end end # # Operator for `#retrieve`. # # key - Index key to lookup. # # Returns `Object` value of key. # def [](key) retrieve(key) end # # Operator for `#store`. # # key - The `Object` to act as indexing key. # value - The `Object` to associate with key. # # Returns +value+. # def []=(key,value) store(key,value) end # # Update the Hash with another hash. # # other - Other hash or hash-like object to add to the hash. # # Returns +self+. # def update(other) other.each do |k,v| store(k, v) end self end # # Alias for `#update`. # alias merge! update # # Merge the Hash with another hash, returning a new Hash. # # other - Other hash or hash-like object to add to the hash. # # Returns `Hash`. # def merge(other) #super(other.rekey{ |key| cast_key(key) }) copy = dup other.each{ |k,v| copy.store(k, v) } copy end # # Iterate over each hash pair. # def each #:yield: if block_given? keys.each do |k| yield(k, retrieve(k)) end else to_enum(:each) end end # # Alias for #each. # alias each_pair each # # Alias for `#key?`. # alias has_key? key? # # Alias for `#key?`. # alias member? key? # # Alias for `#key?`. # alias include? key? # why isn't it an alias for `#has_value?` ? # # Replace current entries with those from another Hash, # or Hash-like object. Each entry is run through the # casting procedure as it is added. # # other - Hash-like object. # # Returns +self+. # def replace(other) super cast(other) end # # Get the values at. # # keys - List of keys to lookup. # # Returns `Array` of values. # def values_at(*keys) super *keys.map{ |key| cast_key(key) } end # Convert CRUDHash to regular Hash. # # TODO: Since a CRUDHash is a subclass of Hash should #to_hash just `#dup` # insted of converting to traditional Hash? # def to_hash h = {}; each{ |k,v| h[k] = v }; h end #unless method_defined?(:to_hash) # # Convert CRUDHash to regular Hash. # # TODO: Since a CRUDHash is a subclass of Hash should #to_h just `#dup` # insted of converting to traditional Hash? # # Returns `Hash`. # alias :to_h :to_hash private # # Cast a given `hash` in accordance to the `#key_proc`. # # hash - Any object the responds to `#each` like a Hash. # # Returns `Hash`. # def cast(hash) h = {} hash.each do |k,v| h[cast_key(k)] = v end h end # # Callback for normalizing hash keys. # # key - Index key. # # Returns key after passing through the `key_proc`. # def cast_key(key) @key_proc ? @key_proc.call(key) : key end # TODO: Consider value callback procs for future version of CRUDHash. # # # # # Callback for writing value. # # # def cast_write(value) # @write_proc ? @write_proc.call(value) : value # end # # # # # Callback for reading value. # # # def cast_read(value) # @read_proc ? @read_proc.call(value) : value # end end end hashery-2.1.2/lib/hashery/open_cascade.rb0000644000004100000410000000771512712231704020362 0ustar www-datawww-datarequire 'hashery/open_hash' module Hashery # OpenCascade is subclass of OpenHash. It differs in a few # significant ways. The reason this class is called "cascade" is that # every internal Hash is transformed into an OpenCascade dynamically # upon access. This makes it easy to create "cascading" references. # # h = { :x => { :y => { :z => 1 } } } # c = OpenCascade[h] # c.x.y.z #=> 1 # # As soon as you access a node it automatically becomes an OpenCascade. # # c = OpenCascade.new #=> # # c.r #=> # # c.a.b #=> # # # But if you set a node, then that will be that value. # # c.a.b = 4 #=> 4 # # To query a node without causing the auto-creation of an OpenCasade # instance, use the `?`-mark. # # c.a.z? #=> nil # # OpenCascade also transforms Hashes within Arrays. # # h = { :x=>[ {:a=>1}, {:a=>2} ], :y=>1 } # c = OpenCascade[h] # c.x.first.a.assert == 1 # c.x.last.a.assert == 2 # # Finally, you can set call a private method via bang methods using the `!`-mark. # # c = OpenCascade.new #=> # # c.each = 4 # c.each! do |k,v| # ... # end # # c.x!(4).y!(3) #=> #4, :y=>3}> # # Subclassing OpenCascade with cause the new subclass to become the class that # is auto-created. If this is not the behavior desired, consider using delegation # instead of subclassing. # class OpenCascade < OpenHash # #def self.[](hash) # oc = new # hash.each{ |(k,v)| oc.store(k,v) } # oc #end # # Initialize new OpenCascade instance. # # default - The usual default object. # def initialize(*default) @read = {} leet = lambda { |h,k| h[k] = self.class.new(&leet) } super(*default, &leet) end # # Alias for original read method. # alias :retrieve! :retrieve # # Read value given a +key+. # # key - Index key to lookup. # # Returns value. # def retrieve(key) ckey = cast_key(key) if @read[ckey] super(key) else @read[ckey] = store(key, cast_value(super(key))) end end # # # def method_missing(sym, *args, &blk) type = sym.to_s[-1,1] name = sym.to_s.gsub(/[=!?]$/, '').to_sym case type when '=' store(name, args.first) when '?' key?(name) ? retrieve!(name) : nil # key?(name) when '!' __send__(name, *args, &blk) else #if key?(name) retrieve(name) #else # #default = OpenCascade.new #self.class.new # #default = default_proc ? default_proc.call(self, name) : default # store(name, read(name)) #end end end def respond_to?(sym, include_private = false) sym != :to_ary && super end #def each # super do |key, entry| # yield([key, transform_entry(entry)]) # end #end private # # Cast value, such that Hashes are converted to OpenCascades. # And Hashes in Arrays are converted to OpenCascades as well. # def cast_value(entry) case entry when Hash e = OpenCascade.new e.key_proc = key_proc if key_proc e.merge!(entry) e when Array entry.map{ |e| cast_value(e) } else entry end end end end #-- # Last, when an entry is not found, 'null' is returned rather then 'nil'. # This allows for run-on entries withuot error. Eg. # # o = OpenCascade.new # o.a.b.c #=> null # # Unfortuately this requires an explict test for null? in 'if' conditions. # # if o.a.b.c.null? # true if null # if o.a.b.c.nil? # true if nil or null # if o.a.b.c.not? # true if nil or null or false # # So be sure to take that into account. #++ hashery-2.1.2/lib/hashery/casting_hash.rb0000644000004100000410000000642212712231704020403 0ustar www-datawww-datarequire 'hashery/crud_hash' module Hashery # CastingHash is just like CRUDHash, except that both keys and values # can be passed through casting procedures. # class CastingHash < CRUDHash # # Like `#new` but can take a priming Hash or Array-pairs. # # hash - Hash-like object. # # Examples # # CastingHash[:a,1,:b,2] # # Returns `CastingHash`. # def self.[](hash) s = new hash.each{ |k,v| s[k] = v } s end # # Unlike traditional Hash a CastingHash's block argument # coerces key/value pairs when #store is called. # # default - Default value. # cast_proc - Casting procedure. # def initialize(default=nil, &cast_proc) @cast_proc = cast_proc super(default, &nil) end # # The cast procedure. # # proc - Casting procedure. # # Returns `Proc` used for casting. # def cast_proc(&proc) @cast_proc = proc if proc @cast_proc end # # Set `cast_proc`. This procedure must take two arguments (`key, value`) # and return the same. # # proc - Casting procedure. # # Returns +proc+. # def cast_proc=(proc) raise ArgumentError unless Proc === proc or NilClass === proc @cast_proc = proc end # # CRUD method for create and update. Unlike the parent class # the key, value pair are passed threw the cast_proc before # being set in the underlying hash table. # # key - Key of entry. # value - Value of entry. # # Returns the +value+. # def store(key, value) super(*cast_pair(key, value)) end # # Replace current entries with those from another Hash, # or Hash-like object. Each entry is run through the # casting procedure as it is added. # # other - Hash-like object. # # Returns +self+. # def replace(other) super cast(other) end # # Convert the CastingHash to a regular Hash. # # Returns an ordinary `Hash`. # def to_hash h = {}; each{ |k,v| h[k] = v }; h end # # Returns an ordinary `Hash`. # alias_method :to_h, :to_hash # # Recast all entries via the cast procedure. # # TODO: Isn't this the same as `#rehash`? # # Returns +self+. # def recast! replace self end private # # If `cast_proc` is defined then use it to process key-value pair, # otherwise return them as is. # # key - Key of entry. # value - Value of entry. # # Returns `Array` of key-value pair. # def cast_pair(key, value) if cast_proc return cast_proc.call(key, value) else return key, value end end # # Cast a given +hash+ according to the `#key_proc` and `#value_proc`. # # hash - A `Hash` or anything the responds to `#each` like a hash. # # Returns a recasted `Hash`. # def cast(hash) h = {} hash.each do |k,v| k, v = cast_pair(k, v) h[k] = v end h end end end # TODO: Should we add #to_casting_hash to Hash classs? #class Hash # # # Convert a Hash to a CastingHash. # def to_casting_hash(value_cast=nil, &key_cast) # CastingHash.new(self, value_cast, &key_cast) # end # #end hashery-2.1.2/lib/hashery/static_hash.rb0000644000004100000410000000236212712231704020241 0ustar www-datawww-datamodule Hashery # StaticHash ia a Hash object which raises an error if any # previously-defined key attempts to be set again. # # foo = StaticHash.new # foo['name'] = 'Tom' #=> 'Tom' # foo['age'] = 30 #=> 30 # foo['name'] = 'Bob' # # produces # # ArgumentError: Duplicate key for StaticHash -- 'name' # # StaticHash has it's orgins in Gavin Kistner's WriteOnceHash # class found in his +basiclibrary.rb+ script. # # TODO: Maybe StaticHash isn't bets name for this class? # class StaticHash < CRUDHash # # Set a value for a key. Raises an error if that key already # exists with a different value. # # key - Index key to associate with value. # value - Value to associate with key. # # Retruns value. # def store(key, value) if key?(key) && fetch(key) != value raise ArgumentError, "Duplicate key for StaticHash -- #{key.inspect}" end super(key, value) end # #def update(hash) # dups = (keys | hash.keys) # if dups.empty? # super(hash) # else # raise ArgumentError, "Duplicate key for StaticHash -- #{dups.inspect}" # end #end # #alias_method :merge!, :update end end hashery-2.1.2/lib/hashery/key_hash.rb0000644000004100000410000000273512712231704017546 0ustar www-datawww-datarequire 'hashery/crud_hash' module Hashery # The KeyHash class is a Hash class which accepts a block for # normalizing keys. # # The KeyHash class is essentially the same as a normal Hash. # But notice the significant distinction of indifferent key # access. # # s = KeyHash.new # s[:x] = 1 # s[:x] #=> 1 # s['x'] #=> 1 # # We can see that internally the key has indeed been converted # to a String. # # s.to_h #=> {'x'=>1 } # # By default all keys are converted to strings. This has two advantages # over a regular Hash is many usecases. First it means hash entries have # indifferent access. 1, "1" and :1 are all # equivalent --any object that defines #to_s can be used as a key. # Secondly, since strings are garbage collected so will default KeyHash # objects. # # But keys can be normalized by any function. Theses functions can be quite # unique. # # h = KeyHash.new(0){ |k| k.to_i } # h[1.34] += 1 # h[1.20] += 1 # h[1.00] += 1 # h #=> { 1 => 3 } # class KeyHash < CRUDHash # # Unlike a regular Hash, a KeyHash's block sets the `key_proc` rather # than the `default_proc`. # def initialize(*default, &block) super(*default) @key_proc = block || Proc.new{ |k| k.to_s } end end end #class Hash # # # # Convert a Hash to a KeyHash object. # # # def to_keyhash # Hashery::KeyHash[self] # end #end hashery-2.1.2/test/0000755000004100000410000000000012712231704014165 5ustar www-datawww-datahashery-2.1.2/test/case_dictionary.rb0000644000004100000410000001520212712231704017652 0ustar www-datawww-datarequire 'helper' testcase Dictionary do include AE::Legacy::Assertions class_method :[] do test do d = Dictionary['z', 1, 'a', 2, 'c', 3] assert_equal( ['z','a','c'], d.keys ) end end class_method :new do test "with default" do d = Dictionary.new{ |hash,key| hash[key] = 0 } d[:a] = 0 d[:b] += 1 assert_equal [0, 1], d.values assert_equal [:a,:b], d.keys end end method :[] do test do d = Dictionary['a', 1] d['a'].assert == 1 end end method :[]= do test do d = Dictionary.new d['z'] = 1 d['a'] = 2 d['c'] = 3 assert_equal( ['z','a','c'], d.keys ) end end method :[]= do test do d = Dictionary[] d[:a] = 1 d[:c] = 3 assert_equal( [1,3], d.values ) d[:b,1] = 2 assert_equal( [1,2,3], d.values ) assert_equal( [:a,:b,:c], d.keys ) end end method :push do test do d = Dictionary['a', 1, 'c', 2, 'z', 3] assert( d.push('end', 15) ) assert_equal( 15, d['end'] ) assert( ! d.push('end', 30) ) assert( d.unshift('begin', 50) ) assert_equal( 50, d['begin'] ) assert( ! d.unshift('begin', 60) ) assert_equal( ["begin", "a", "c", "z", "end"], d.keys ) assert_equal( ["end", 15], d.pop ) assert_equal( ["begin", "a", "c", "z"], d.keys ) assert_equal( ["begin", 50], d.shift ) end end method :insert do test "front" do d = Dictionary['a', 1, 'b', 2, 'c', 3] r = Dictionary['d', 4, 'a', 1, 'b', 2, 'c', 3] assert_equal( 4, d.insert(0,'d',4) ) assert_equal( r, d ) end test "back" do d = Dictionary['a', 1, 'b', 2, 'c', 3] r = Dictionary['a', 1, 'b', 2, 'c', 3, 'd', 4] assert_equal( 4, d.insert(-1,'d',4) ) assert_equal( r, d ) end end method :update do test "with other orderred hash" do d = Dictionary['a', 1, 'b', 2, 'c', 3] c = Dictionary['d', 4] r = Dictionary['a', 1, 'b', 2, 'c', 3, 'd', 4] assert_equal( r, d.update(c) ) assert_equal( r, d ) end test "with other hash" do d = Dictionary['a', 1, 'b', 2, 'c', 3] c = { 'd' => 4 } r = Dictionary['a', 1, 'b', 2, 'c', 3, 'd', 4] assert_equal( r, d.update(c) ) assert_equal( r, d ) end end method :merge do test "with other orderred hash" do d = Dictionary['a', 1, 'b', 2, 'c', 3] c = Dictionary['d', 4] r = Dictionary['a', 1, 'b', 2, 'c', 3, 'd', 4] assert_equal( r, d.merge(c) ) end test "with other hash" do d = Dictionary['a', 1, 'b', 2, 'c', 3] c = { 'd' => 4 } r = Dictionary['a', 1, 'b', 2, 'c', 3, 'd', 4] assert_equal( r, d.merge(c) ) end end method :order_by do test do d = Dictionary['a', 3, 'b', 2, 'c', 1] d.order_by{ |k,v| v } assert_equal( [1,2,3], d.values ) assert_equal( ['c','b','a'], d.keys ) end end method :reverse! do test do d = Dictionary['z', 1, 'a', 2, 'c', 3] d.reverse! assert_equal( ['c','a','z'], d.keys ) end end method :collect do test "enumerable method" do d = Dictionary[] d[:a] = "a" d[:c] = "b" r = d.collect{|k,v| v.capitalize} r.assert == ["A","B"] end end method :dup do test "with array values" do d = Dictionary.new d.dup d[:a]=['t',5] assert_equal(d, d.dup) end end method :first do test do d = Dictionary[] d[:a] = "a" d[:b] = "b" d[:c] = "c" d.first.assert == "a" d.first(0).assert == [] assert_equal ["a"] , d.first(1) assert_equal ["a", "b"] , d.first(2) end end method :last do test do d = Dictionary[] d[:a] = "a" d[:b] = "b" d[:c] = "c" d.last.assert == "c" d.last(0).assert == [] d.last(1).assert == ["c"] d.last(2).assert == ["b", "c"] end end method :select do test do d = Dictionary[:a=>1, :b=>2, :c=>3] r = d.select{ |k,v| v % 2 == 1 } r.assert == [[:a, 1], [:c, 3]] end end method :to_h do test do d = Dictionary[:a=>1, :b=>2] h = d.to_h h.assert == {:a=>1, :b=>2} end end method :replace do test do d1 = Dictionary[:a=>1, :b=>2] d2 = Dictionary[:c=>3, :d=>4] d1.replace(d2) d1.to_h.assert == {:c=>3, :d=>4} end end method :reverse do test do d = Dictionary[:a=>1, :b=>2, :c=>3] r = d.reverse r.first.assert == 3 end end method :invert do test do d = Dictionary[:a=>1, :b=>2, :c=>3] r = d.invert Dictionary.assert === r r.to_h.assert == {1=>:a, 2=>:b, 3=>:c} end end method :each_key do d = Dictionary[:a=>1, :b=>2, :c=>3] d.order_by_key a = [] d.each_key{ |k| a << k } a.assert == [:a, :b, :c] end method :each_value do d = Dictionary[:a=>1, :b=>2, :c=>3] d.order_by_value a = [] d.each_value{ |v| a << v } a.assert == [1, 2, 3] end method :clear do d = Dictionary[:a=>1, :b=>2, :c=>3] d.clear d.to_a.assert == [] end method :fetch do d = Dictionary[:a=>1, :b=>2, :c=>3] d.fetch(:a).assert == 1 end method :key? do test do d = Dictionary[:a=>1, :b=>2, :c=>3] d.assert.key?(:a) d.refute.key?(:d) end end method :has_key? do test do d = Dictionary[:a=>1, :b=>2, :c=>3] d.assert.has_key?(:a) d.refute.has_key?(:d) end end method :length do test do d = Dictionary[:a=>1, :b=>2, :c=>3] d.length.assert == 3 end end method :to_a do test do d = Dictionary[:a=>1, :b=>2, :c=>3] d.to_a.assert == [[:a,1], [:b,2], [:c,3]] end end method :to_hash do test do d = Dictionary[:a=>1, :b=>2, :c=>3] d.to_hash.assert == {:a=>1, :b=>2, :c=>3} end end method :empty? do test "is emtpy" do d = Dictionary[] d.assert.empty? end test 'is not emtpy' do d = Dictionary[:a=>1, :b=>2, :c=>3] d.refute.empty? end end method :order_by_key do test do d = Dictionary[:b=>1, :c=>2, :a=>4] d.order_by_key d.order.assert == [:a, :b, :c] end end method :order_by_value do test do d = Dictionary[:b=>1, :c=>2, :a=>4] d.order_by_value d.order.assert == [:b, :c, :a] end end class_method :alpha do test do d = Dictionary.alpha d.update(:b=>1, :c=>2, :a=>4) d.order.assert == [:a, :b, :c] end end class_method :auto do test do d = Dictionary.auto s = d[:foo] s.class.assert == Dictionary end end end hashery-2.1.2/test/case_ini_hash.rb0000644000004100000410000000162212712231704017270 0ustar www-datawww-datarequire 'helper' test_case IniHash do class_method :new do test do h = IniHash.new('foo.ini', false) end end method :[]= do test do h = IniHash.new('foo.ini', false) h['a'] = '1' h['a'].assert = '1' end end method :[] do test do h = IniHash.new('foo.ini', false) h['a'] = '1' h['a'].assert = '1' end end method :to_h do test do h = IniHash.new('foo.ini', false) h['a'] = '1' h.to_h.assert = {'a'=>'1'} end end method :to_s do test do h = IniHash.new('foo.ini', false) h['a'] = '1' h.to_s.assert == "a=1\n" end test do h = IniHash.new('foo.ini', false) h['a'] = '1' h['b'] = {'c'=>3} h.to_s.assert == "a=1\n[b]\nc=3\n" end end class_method :load do h = IniHash.load('test/fixture/example.ini') h['a'].assert == '1' end end hashery-2.1.2/test/helper.rb0000644000004100000410000000021412712231704015766 0ustar www-datawww-datarequire 'lemon' require 'ae' require 'ae/legacy' # bacause imitation BasicObject sucks require 'ae/pry' require 'hashery' include Hashery hashery-2.1.2/test/fixture/0000755000004100000410000000000012712231704015653 5ustar www-datawww-datahashery-2.1.2/test/fixture/example.ini0000644000004100000410000000005512712231704020007 0ustar www-datawww-data# top comment a = 1 [section] x = 2 y = 3 hashery-2.1.2/test/case_linked_list.rb0000644000004100000410000000514412712231704020012 0ustar www-datawww-datarequire 'helper' test_case LinkedList do class_method :new do ll = LinkedList.new LinkedList.assert === ll end method :to_a do test 'empty' do ll = LinkedList.new ll.to_a.assert == [] end test 'not empty' do ll = LinkedList.new ll.push :a ll.to_a.assert == [:a] end end method :empty? do test do ll = LinkedList.new ll.assert.empty? end end method :delete do test do ll = LinkedList.new ll.push :a ll.to_a.assert == [:a] ll.delete(:a) ll.to_a.assert == [] end test do ll = LinkedList.new ll.push :a ll.push :b ll.push :c ll.to_a.assert == [:a, :b, :c] ll.delete(:b) ll.to_a.assert == [:a, :c] end end method :each do test do a = [] ll = LinkedList.new ll.push :a ll.each do |e| a << e end a.assert == [:a] end end method :length do test do ll = LinkedList.new ll.push :a ll.length.assert == 1 end end method :push do test do ll = LinkedList.new ll.push :a ll.to_a.assert == [:a] end end method :unshift do test do ll = LinkedList.new ll.unshift :a ll.to_a.assert == [:a] end test do ll = LinkedList.new ll.push :a ll.unshift :b ll.to_a.assert == [:b, :a] end end method :pop do test do ll = LinkedList.new ll.push :a ll.push :b ll.to_a.assert == [:a, :b] ll.pop ll.to_a.assert == [:a] end end method :shift do test do ll = LinkedList.new ll.push :a ll.push :b ll.to_a.assert == [:a, :b] ll.shift ll.to_a.assert == [:b] end end method :first do test do ll = LinkedList.new ll.push :a ll.push :b ll.to_a.assert == [:a, :b] ll.first.assert == :a end end method :last do test do ll = LinkedList.new ll.push :a ll.push :b ll.to_a.assert == [:a, :b] ll.last.assert == :b end end method :queue do test do ll = LinkedList.new ll.push :a ll.push :b ll.queue.assert == [:a, :b] end end method :[]= do test do ll = LinkedList.new ll[:a] = :b ll.to_a.assert == [:b] ll[:a].assert == :b end end method :[] do test do ll = LinkedList.new ll.push :a ll[:a].assert == :a end test do ll = LinkedList.new ll.push :a ll.push :b ll[:a].assert == :a ll[:b].assert == :b end end end hashery-2.1.2/test/case_casting_hash.rb0000644000004100000410000000241112712231704020136 0ustar www-datawww-datarequire 'helper' test_case CastingHash do class_method :[] do test do h = CastingHash[:a=>1, :b=>2] end end class_method :new do test do h = CastingHash.new end test 'with default' do h = CastingHash.new(0) h['a'].assert == 0 end test 'with casting procedure' do h = CastingHash.new{ |k,v| [k.to_sym, v] } h['a'] = 1 h.assert == {:a=>1} end test 'with default and casting procedure' do h = CastingHash.new(0){ |k,v| [k.to_sym, v] } h['a'].assert == 0 h['b'] = 2 h.assert == {:b=>2} end end method :recast! do test do h = CastingHash[:a=>1, :b=>2] h.cast_proc{ |k,v| [k.to_s, v] } h.recast! h.assert == {'a'=>1, 'b'=>2} end end method :cast_proc= do test do h = CastingHash[:a=>1, :b=>2] h.cast_proc = Proc.new{ |k,v| [k.to_s, v] } h.recast! h.assert == {'a'=>1, 'b'=>2} end end method :to_hash do test do h = CastingHash[:a=>1, :b=>2] h.to_hash ::Hash.assert === h h.assert == {:a=>1, :b=>2} end end method :to_h do test do h = CastingHash[:a=>1, :b=>2] h.to_h ::Hash.assert === h h.assert == {:a=>1, :b=>2} end end end hashery-2.1.2/test/case_key_hash.rb0000644000004100000410000000616012712231704017303 0ustar www-datawww-datarequire 'helper' testcase KeyHash do class_method :[] do test 'creates new KeyHash' do s = KeyHash[] KeyHash.assert === s end test 'pre-assigns values' do s = KeyHash[:a=>1, :b=>2] s[:a].assert == 1 s[:b].assert == 2 end end method :[] do test 'instance level fetch' do s = KeyHash[:a=>1, :b=>2] s[:a].assert == 1 s[:b].assert == 2 end test 'by default keys are converted to strings' do s = KeyHash[:a=>1, :b=>2] s['a'].assert == 1 s['b'].assert == 2 end end method :[]= do test do s = KeyHash.new s[:a] = 1 s[:b] = 2 s[:a].assert == 1 s[:b].assert == 2 s['a'].assert == 1 s['b'].assert == 2 end end method :initialize do test do StandardError.refute.raised? do s = KeyHash.new end end end method :to_hash do test do s = KeyHash[:a=>1, :b=>2] s.to_hash.assert == {'a'=>1, 'b'=>2} end end method :to_h do test do s = KeyHash[:a=>1, :b=>2] s.to_h.assert == {'a'=>1, 'b'=>2} end end method :replace do test do s = KeyHash.new s.replace(:a=>1, :b=>2) s.to_h.assert == {'a'=>1, 'b'=>2} end end method :delete do test do s = KeyHash[:a=>1, :b=>2] s.delete(:a) s.to_h.assert == {'b'=>2} end end method :each do test do s = KeyHash[:a=>1, :b=>2] s.each do |k,v| String.assert === k end end end method :store do test do s = KeyHash.new s.store(:a, 1) s.to_h.assert == {'a'=>1} end end method :update do test do s1 = KeyHash[:a=>1,:b=>2] s2 = KeyHash[:c=>3,:d=>4] s1.update(s2) s1.to_h.assert == {'a'=>1,'b'=>2,'c'=>3,'d'=>4} end end method :rekey do test do s = KeyHash[:a=>1,:b=>2,:c=>3] x = s.rekey{ |k| k.upcase } x.to_h.assert == {'A'=>1,'B'=>2,'C'=>3} end end method :rekey! do test do s = KeyHash[:a=>1,:b=>2,:c=>3] s.rekey!{ |k| k.upcase } s.to_h.assert == {'A'=>1,'B'=>2,'C'=>3} end end method :key? do test do s = KeyHash[:a=>1] s.assert.key?(:a) s.assert.key?('a') end end method :has_key? do test do s = KeyHash[:a=>1] s.assert.has_key?(:a) s.assert.has_key?('a') end end method :<< do test do s = KeyHash.new s << [:a, 1] s << [:b, 2] s.to_h.assert == {'a'=>1, 'b'=>2} end end method :merge! do test do s1 = KeyHash[:a=>1,:b=>2] s2 = KeyHash[:c=>3,:d=>4] s1.merge!(s2) s1.to_h.assert == {'a'=>1,'b'=>2,'c'=>3,'d'=>4} end end method :values_at do test do s = KeyHash[:a=>1,:b=>2,:c=>3] s.values_at(:a, :b).assert == [1,2] s.values_at('a','b').assert == [1,2] end end method :fetch do test do s = KeyHash[:a=>1,:b=>2,:c=>3] s.fetch(:a).assert == 1 s.fetch('a').assert == 1 end end #method :cast_key do # test do # s = KeyHash.new # s.send(:cast_key, :a).assert == 'a' # end #end end hashery-2.1.2/test/case_association.rb0000644000004100000410000000340612712231704020024 0ustar www-datawww-datarequire 'helper' # must be required independently require 'hashery/association' testcase Association do class_method :new do test do Association.new(:A, :B) end end class_method :[] do test do a = Association[:a, 1] a.assert.index == :a a.assert.value == 1 end end method :index do test do a = Association.new(:a,1) a.index.assert == :a end end method :value do test do a = Association.new(:a,1) a.value.assert == 1 end end method :to_ary do test do k,v = [],[] ohash = [ 'A' >> '3', 'B' >> '2', 'C' >> '1' ] ohash.each { |e1,e2| k << e1 ; v << e2 } k.assert == ['A','B','C'] v.assert == ['3','2','1'] end end method :index do test do complex = [ 'Drop Menu' >> [ 'Button 1', 'Button 2', 'Button 3' ], 'Help' ] complex[0].index.assert == 'Drop Menu' end end method :<=> do test 'when differnt in value' do a = Association.new(:a,1) b = Association.new(:b,2) (a <=> b).assert == -1 (b <=> a).assert == 1 end test 'when equal value' do a = Association.new(:a,1) b = Association.new(:b,1) (a <=> b).assert == 0 end end method :invert! do test do a = Association.new(:a,1) a.invert! a.index.assert == 1 a.value.assert == :a end end method :inspect do test do a = Association.new(:a,1) a.inspect.assert == ":a >> 1" end end method :to_s do test do a = Association.new(:a,1) a.to_s.assert == "a >> 1" end end end testcase Object do method :associations do test do s = 'a' complex = [ s >> :b, s >> :c ] s.associations.assert == [:b, :c] end end end hashery-2.1.2/test/case_crud_hash.rb0000644000004100000410000000065212712231704017450 0ustar www-datawww-datarequire 'helper' test_case CRUDHash do class_method :create do test do h = CRUDHash.create(:a=>1,:b=>2) h.assert == {:a=>1,:b=>2} end end class_method :auto do test 'without a block' do h = CRUDHash.auto h[:a].assert == {} end test 'with a block' do h = CRUDHash.auto{ [] } h[:a].assert == [] end end end # # OT: Why not make `:a=>1` a Pair object? # hashery-2.1.2/test/case_property_hash.rb0000644000004100000410000000045212712231704020375 0ustar www-datawww-datarequire 'helper' test_case PropertyHash do class_method :new do test do PropertyHash.new end end method :update do test do h = PropertyHash.new h.property :a h.property :b h.update(:a=>1, :b=>2) h.assert == {:a=>1, :b=>2} end end end hashery-2.1.2/test/case_lru_hash.rb0000644000004100000410000000460412712231704017316 0ustar www-datawww-datarequire 'helper' test_case LRUHash do class_method :new do h = LRUHash.new(10) LRUHash.assert === h end method :max_size= do test do h = LRUHash.new(10) h.max_size = 100 end end method :store do test do h = LRUHash.new(10) h.store(:a, 1) h[:a].assert == 1 end end method :[] do test do h = LRUHash.new(10) h.store(:a, 1) h[:a].assert == 1 end test do h = LRUHash.new(10){ |h,k| h[k] = 0 } h[:a].assert == 0 end end method :empty? do test do h = LRUHash.new(10) h.assert.empty? end end method :key do test do h = LRUHash.new(10) h[:a] = 1 h.key(1).assert == :a end end method :keys do test do h = LRUHash.new(10) h[:a] = 1 h.keys.assert == [:a] end end method :values do test do h = LRUHash.new(10) h[:a] = 1 h.values.assert == [1] end end method :values_at do test do h = LRUHash.new(10) h[:a] = 1 h[:b] = 2 h.values_at(:a).assert == [1] end end method :has_key? do test do h = LRUHash.new(10) h[:a] = 1 h.assert.has_key?(:a) end end method :has_value? do test do h = LRUHash.new(10) h[:a] = 1 h.assert.has_value?(1) end end method :assoc do test do h = LRUHash.new(10) h[:a] = 1 h[:b] = 2 h.assoc(:a).assert == [:a,1] end end method :rassoc do test do h = LRUHash.new(10) h[:a] = 1 h[:b] = 2 h.rassoc(1).assert == [:a,1] end end method :each_key do test do h = LRUHash.new(10) h[:a] = 1 h[:b] = 2 h.each_key do |k| [:a,:b].assert.include?(k) end end end method :each_value do test do h = LRUHash.new(10) h[:a] = 1 h[:b] = 2 h.each_value do |v| [1,2].assert.include?(v) end end end method :clear do test do h = LRUHash.new(10) h[:a] = 1 h[:b] = 2 h.clear h.assert.empty? end end method :delete do test do h = LRUHash.new(10) h[:a] = 1 h.delete(:a) h.assert.empty? end end method :delete_if do test do h = LRUHash.new(10) h[:a] = 1 h.delete_if{ |k,v| k == :a } h.assert.empty? end end end hashery-2.1.2/test/case_open_cascade.rb0000644000004100000410000000444112712231704020114 0ustar www-datawww-datarequire 'helper' testcase OpenCascade do include AE::Legacy::Assertions class_method :new do OpenCascade[:a=>1] end class_method :[] do test "hash" do o = OpenCascade[:a=>1,:b=>2] assert_equal(1, o.a) assert_equal(2, o.b) end test "hash in hash" do o = OpenCascade[:a=>1,:b=>2,:c=>{:x=>9}] assert_equal(9, o.c.x) end test "hash in hash in hash" do h = {:a=>1,:x=>{:y=>{:z=>1}}} c = OpenCascade[h] assert_equal(1, c.x.y.z) end end method :[] do test "basic assignment" do o = OpenCascade.new o[:a] = 1 assert_equal(1, o[:a]) end end method :[]= do test "basic assignment with primed OpenCascade" do o = OpenCascade[:a=>1] o[:b] = 2 o.to_h.assert == {:a=>1,:b=>2} end end method :to_a do test do o = OpenCascade[:a=>1,:b=>2] a = o.to_a a.assert.include?([:a,1]) a.assert.include?([:b,2]) a.size.assert == 2 end end method :to_h do test do o = OpenCascade[:a=>1] assert_equal({:a=>1}, o.to_h) end end method :merge! do test do o = OpenCascade[:f0=>"f0"] r = OpenCascade[:f0=>"f0", :h0=>"h0"] h = { :h0=>"h0" } assert_equal(r, o.merge!(h)) assert_equal({:f0=>"f0", :h0=>"h0"}, h.merge(o)) end end method :update do test do o = OpenCascade[:f1=>"f1"] o.update(:h1=>"h1") o.assert == OpenCascade[:f1=>"f1", :h1=>"h1"] end end method :method_missing do test "writer and reader" do o = OpenCascade.new 10.times{ |i| o.__send__("n#{i}=", 1 ) } 10.times{ |i| assert_equal(1, o.__send__("n#{i}")) } end end method :<< do test do c = OpenCascade.new c << [:x,8] c << [:y,9] assert_equal(8, c.x) assert_equal(9, c.y) end end end testcase Hash do method :update do test "hash can be updated by OpenCascade" do o = OpenCascade[:f1=>"f1"] h = {:h1=>"h1"} h.update(o) h.assert == {:f1=>"f1", :h1=>"h1"} end end end testcase Array do method :flatten do test "array can be flattened if contains OpenCascade" do cascade = OpenCascade[:foo=>"bar"] array = [cascade] array.flatten # should not raise error end end end hashery-2.1.2/test/case_core_ext.rb0000644000004100000410000000323712712231704017322 0ustar www-datawww-datarequire 'helper' test_case Hash do method :rekey do test "default" do foo = { "a"=>1, "b"=>2 } foo.rekey.assert == { :a=>1, :b=>2 } foo.assert == { "a"=>1, "b"=>2 } end test "specific key" do bar = { :a=>1, :b=>2 } foo = bar.rekey(:a=>:c) foo[:c].assert == 1 foo[:b].assert == 2 foo[:a].assert == nil end test "with block" do bar = { :a=>1, :b=>2 } foo = bar.rekey{ |k| k.to_s } foo['a'].assert == 1 foo['b'].assert == 2 foo[:a].assert == nil foo[:b].assert == nil foo.assert == { 'a'=>1, 'b'=>2 } end test "symbol proc" do foo = { :a=>1, :b=>2 } foo.rekey(&:to_s).assert == { "a"=>1, "b"=>2 } foo.assert == { :a =>1, :b=>2 } end end method :rekey! do test "default" do foo = { "a"=>1, "b"=>2 } foo.rekey!.assert == { :a=>1, :b=>2 } foo.assert == { :a=>1, :b=>2 } end test "specific key" do foo = { :a=>1, :b=>2 } foo.rekey!(:a=>:c) foo[:c].assert == 1 foo[:b].assert == 2 foo[:a].assert == nil end test "with block" do foo = { :a=>1, :b=>2 } foo.rekey!{ |k| k.to_s } foo['a'].assert == 1 foo['b'].assert == 2 foo[:a].assert == nil foo[:b].assert == nil foo.assert == { 'a'=>1, 'b'=>2 } end test "symbol proc" do foo = { :a=>1, :b=>2 } foo.rekey!(&:to_s).assert == { "a"=>1, "b"=>2 } foo.assert == { "a"=>1, "b"=>2 } end test "no conflict between keys" do r = {1 => :a, 2 => :b}.rekey!{ |k| k + 1 } r.refute = {3 => :a} r.assert = {2 => :a, 3 => :b} end end end hashery-2.1.2/test/case_query_hash.rb0000644000004100000410000001041612712231704017657 0ustar www-datawww-datarequire 'helper' testcase QueryHash do class_method :new do test 'new QueryHash with default proc' do q = QueryHash.new{ |h,k| h[k] = 1 } q[:a].assert == 1 end end class_method :[] do test 'creates new QueryHash' do s = QueryHash[] QueryHash.assert === s end test 'pre-assigns values' do s = QueryHash[:a=>1, :b=>2] s[:a].assert == 1 s[:b].assert == 2 end end method :[] do test 'instance level fetch' do s = QueryHash[:a=>1, :b=>2] s[:a].assert == 1 s[:b].assert == 2 #s['a'].assert == 1 #s['b'].assert == 2 end end method :[]= do test do s = QueryHash.new s[:a] = 1 s[:b] = 2 s[:a].assert == 1 s[:b].assert == 2 #s['a'].assert == 1 #s['b'].assert == 2 end end method :respond_to? do test 'responds to all query methods' do q = QueryHash.new q.assert.respond_to?(:anything?) end test 'responds to all bang methods' do q = QueryHash.new q.assert.respond_to?(:anything!) end test 'responds to all setter methods' do q = QueryHash.new q.assert.respond_to?(:anything=) end test 'responds to usual methods' do q = QueryHash.new q.assert.respond_to?(:each) end end method :to_hash do test do s = QueryHash[:a=>1, :b=>2] s.to_hash.assert == {'a'=>1, 'b'=>2} end end method :to_h do test do s = QueryHash[:a=>1, :b=>2] s.to_h.assert == {'a'=>1, 'b'=>2} end end method :replace do test do s = QueryHash.new s.replace(:a=>1, :b=>2) s.to_h.assert == {'a'=>1, 'b'=>2} end end method :delete do test do s = QueryHash[:a=>1, :b=>2] s.delete(:a) s.to_h.assert == {'b'=>2} end end method :each do test do s = QueryHash[:a=>1, :b=>2] s.each do |k,v| String.assert === k end end end method :store do test do s = QueryHash.new s.store(:a, 1) s.to_h.assert == {'a'=>1} end end method :update do test do s1 = QueryHash[:a=>1,:b=>2] s2 = QueryHash[:c=>3,:d=>4] s1.update(s2) s1.to_h.assert == {'a'=>1,'b'=>2,'c'=>3,'d'=>4} end end method :rekey do test do s = QueryHash[:a=>1,:b=>2,:c=>3] x = s.rekey{ |k| k.upcase } x.to_h.assert == {'A'=>1,'B'=>2,'C'=>3} end end method :rekey! do test do s = QueryHash[:a=>1,:b=>2,:c=>3] s.rekey!{ |k| k.upcase } s.to_h.assert == {'A'=>1,'B'=>2,'C'=>3} end end method :key? do test do s = QueryHash[:a=>1] s.assert.key?(:a) s.assert.key?('a') end end method :has_key? do test do s = QueryHash[:a=>1] s.assert.has_key?(:a) s.assert.has_key?('a') end end method :<< do test do s = QueryHash.new s << [:a, 1] s << [:b, 2] s.to_h.assert == {'a'=>1, 'b'=>2} end end method :merge! do test do s1 = QueryHash[:a=>1,:b=>2] s2 = QueryHash[:c=>3,:d=>4] s1.merge!(s2) s1.to_h.assert == {'a'=>1,'b'=>2,'c'=>3,'d'=>4} end end method :values_at do test do s = QueryHash[:a=>1,:b=>2,:c=>3] s.values_at(:a, :b).assert == [1,2] s.values_at('a','b').assert == [1,2] end end method :fetch do test do s = QueryHash[:a=>1,:b=>2,:c=>3] s.fetch(:a).assert == 1 s.fetch('a').assert == 1 end end method :cast_key do test do s = QueryHash.new s.pry.cast_key(:a).assert == 'a' end end method :method_missing do test 'dynamic query methods can look-up values' do q = QueryHash[:a=>1,:b=>2,:c=>3] q.a?.assert == 1 q.b?.assert == 2 q.c?.assert == 3 end test 'dynamic bang methods can looks up values too' do q = QueryHash[:a=>1,:b=>2,:c=>3] q.a!.assert == 1 q.b!.assert == 2 q.c!.assert == 3 end test 'dynamic bang methods will auto-instantiate' do q = QueryHash.new q.default_proc{ |h,k| h[k] = 'default' } q.foo!.assert == 'default' end test 'dynamic query methods will NOT auto-instantiate' do q = QueryHash.new q.default_proc{ |h,k| h[k] = 'default' } q.foo?.assert == nil end end end hashery-2.1.2/test/case_open_hash.rb0000644000004100000410000000255512712231704017460 0ustar www-datawww-datarequire 'helper' testcase OpenHash do class_method :[] do test do o = OpenHash[:a=>1, :b=>2] o.a.assert == 1 o.b.assert == 2 end test do o = OpenHash[:a=>1, :b=>2] o.a.assert == 1 o.b.assert == 2 end end method :open? do test do o = OpenHash[:a=>1, :b=>2] o.assert.open?(:foo) o.refute.open?(:each) end end method :open! do test do o = OpenHash[:a=>1, :b=>2] o.open!(:each) o.assert.open?(:each) o.each = 10 o.each.assert == 10 end end method :close! do test do o = OpenHash[:a=>1, :b=>2] o.open!(:each) o.assert.open?(:each) o.each = 10 o.each.assert == 10 o.close!(:each) o.each.refute == 10 end end method :method_missing do test 'bang method' do o = OpenHash[] o.open!(:each) o.each = 10 o.each.assert == 10 a = [] o.each! do |k,v| a << [k,v] end a.assert == [[:each,10]] end test 'query method' do o = OpenHash[] o.a = 1 o.assert.a? o.refute.b? end end method :send do test do o = OpenHash[] o.open!(:each) o.each = 10 o.each.assert == 10 a = [] o.send(:each) do |k,v| a << [k,v] end a.assert == [[:each,10]] end end end hashery-2.1.2/alt/0000755000004100000410000000000012712231704013766 5ustar www-datawww-datahashery-2.1.2/alt/hashery/0000755000004100000410000000000012712231704015431 5ustar www-datawww-datahashery-2.1.2/alt/hashery/statichash.rb0000644000004100000410000000003612712231704020110 0ustar www-datawww-datarequire 'hashery/static_hash' hashery-2.1.2/alt/hashery/queryhash.rb0000644000004100000410000000003512712231704017765 0ustar www-datawww-datarequire 'hashery/query_hash' hashery-2.1.2/alt/hashery/fuzzyhash.rb0000644000004100000410000000003512712231704020007 0ustar www-datawww-datarequire 'hashery/fuzzy_hash' hashery-2.1.2/alt/hashery/keyhash.rb0000644000004100000410000000003312712231704017406 0ustar www-datawww-datarequire 'hashery/key_hash' hashery-2.1.2/alt/hashery/orderedhash.rb0000644000004100000410000000003712712231704020246 0ustar www-datawww-datarequire 'hashery/ordered_hash' hashery-2.1.2/alt/hashery/castinghash.rb0000644000004100000410000000003712712231704020252 0ustar www-datawww-datarequire 'hashery/casting_hash' hashery-2.1.2/alt/hashery/propertyhash.rb0000644000004100000410000000004012712231704020500 0ustar www-datawww-datarequire 'hashery/property_hash' hashery-2.1.2/alt/hashery/linkedlist.rb0000644000004100000410000000003612712231704020117 0ustar www-datawww-datarequire 'hashery/linked_list' hashery-2.1.2/alt/hashery/openhash.rb0000644000004100000410000000003412712231704017560 0ustar www-datawww-datarequire 'hashery/open_hash' hashery-2.1.2/alt/hashery/opencascade.rb0000644000004100000410000000003712712231704020223 0ustar www-datawww-datarequire 'hashery/open_cascade' hashery-2.1.2/alt/hashery/lruhash.rb0000644000004100000410000000003312712231704017420 0ustar www-datawww-datarequire 'hashery/lru_hash' hashery-2.1.2/.yardopts0000644000004100000410000000013012712231704015046 0ustar www-datawww-data--plugin tomdoc --output-dir doc --title Hashery --protected --private lib/ - [A-Z]*.* hashery-2.1.2/NOTICE.txt0000644000004100000410000000205412712231704014731 0ustar www-datawww-dataAll copyright holders have released their wares with a compatible license or have given permission for their work to be distributed under the same license as Hashery. Dictionary is based on OrderedHash by Jan Molic. OrderHash 2.0 Copyright (c) 2005 Jan Molic. LRUHash is based on same by Robert Klemme Copyright (c) 2010 Robert Klemme Memoizer is based on same by Erik Veenstra Copyright (c) 2006 Erik Veenstra IniHash is based on Ini library by Jeena Paradies Copyright (c) 2007 Jeena Paradies LinkedList is based on same by Kirk Haines Copyright (C) 2006 Kirk Haines FuzzyHash is based on the same by Joshua Hull. Copyright (c) 2009 Joshua Hull PathHash is based on SlashedHash by Daniel Parker HashMagic by Daniel Parker Copyright (c) 2006 BehindLogic http://hash_magic.rubyforge.org BasicObject is based on Jim Weirich's BlankSlate class. BlankSlate Copyright 2004 by Jim Weirich (jim@weirichhouse.org). All rights reserved. hashery-2.1.2/hashery.gemspec0000644000004100000410000000757612712231705016236 0ustar www-datawww-data######################################################### # This file has been automatically generated by gem2tgz # ######################################################### # -*- encoding: utf-8 -*- Gem::Specification.new do |s| s.name = "hashery" s.version = "2.1.2" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Trans", "Kirk Haines", "Robert Klemme", "Jan Molic", "George Moschovitis", "Jeena Paradies", "Erik Veenstra"] s.date = "2016-05-01" s.description = "The Hashery is a tight collection of Hash-like classes. Included among its many offerings are the auto-sorting Dictionary class, the efficient LRUHash, the flexible OpenHash and the convenient KeyHash. Nearly every class is a subclass of the CRUDHash which defines a CRUD model on top of Ruby's standard Hash making it a snap to subclass and augment to fit any specific use case." s.email = ["transfire@gmail.com"] s.extra_rdoc_files = ["HISTORY.md", "LICENSE.txt", "NOTICE.txt", "README.md"] s.files = [".index", ".yardopts", "HISTORY.md", "Index.yml", "LICENSE.txt", "NOTICE.txt", "README.md", "alt/hashery/castinghash.rb", "alt/hashery/fuzzyhash.rb", "alt/hashery/keyhash.rb", "alt/hashery/linkedlist.rb", "alt/hashery/lruhash.rb", "alt/hashery/opencascade.rb", "alt/hashery/openhash.rb", "alt/hashery/orderedhash.rb", "alt/hashery/propertyhash.rb", "alt/hashery/queryhash.rb", "alt/hashery/statichash.rb", "demo/00_introduction.rdoc", "demo/01_open_hash.rdoc", "demo/02_query_hash.rdoc", "demo/03_casting_hash.rdoc", "demo/04_static_hash.rdoc", "demo/05_key_hash.rdoc", "demo/06_open_cascade.rdoc", "demo/07_fuzzy_hash.rdoc", "demo/08_propery_hash.rdoc", "demo/10_association.rdoc", "demo/applique/ae.rb", "demo/applique/hashery.rb", "lib/hashery.rb", "lib/hashery.yml", "lib/hashery/association.rb", "lib/hashery/casting_hash.rb", "lib/hashery/core_ext.rb", "lib/hashery/crud_hash.rb", "lib/hashery/dictionary.rb", "lib/hashery/fuzzy_hash.rb", "lib/hashery/ini_hash.rb", "lib/hashery/key_hash.rb", "lib/hashery/linked_list.rb", "lib/hashery/lru_hash.rb", "lib/hashery/open_cascade.rb", "lib/hashery/open_hash.rb", "lib/hashery/ordered_hash.rb", "lib/hashery/path_hash.rb", "lib/hashery/property_hash.rb", "lib/hashery/query_hash.rb", "lib/hashery/stash.rb", "lib/hashery/static_hash.rb", "test/case_association.rb", "test/case_casting_hash.rb", "test/case_core_ext.rb", "test/case_crud_hash.rb", "test/case_dictionary.rb", "test/case_ini_hash.rb", "test/case_key_hash.rb", "test/case_linked_list.rb", "test/case_lru_hash.rb", "test/case_open_cascade.rb", "test/case_open_hash.rb", "test/case_property_hash.rb", "test/case_query_hash.rb", "test/fixture/example.ini", "test/helper.rb"] s.homepage = "http://rubyworks.github.com/hashery" s.licenses = ["BSD-2-Clause"] s.require_paths = ["lib"] s.rubygems_version = "1.8.23" s.summary = "Facets-bread collection of Hash-like classes." s.test_files = ["test/case_association.rb", "test/case_casting_hash.rb", "test/case_core_ext.rb", "test/case_crud_hash.rb", "test/case_dictionary.rb", "test/case_ini_hash.rb", "test/case_key_hash.rb", "test/case_linked_list.rb", "test/case_lru_hash.rb", "test/case_open_cascade.rb", "test/case_open_hash.rb", "test/case_property_hash.rb", "test/case_query_hash.rb", "test/helper.rb"] if s.respond_to? :specification_version then s.specification_version = 4 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then s.add_development_dependency(%q, [">= 0"]) s.add_development_dependency(%q, [">= 0"]) s.add_development_dependency(%q, [">= 0"]) else s.add_dependency(%q, [">= 0"]) s.add_dependency(%q, [">= 0"]) s.add_dependency(%q, [">= 0"]) end else s.add_dependency(%q, [">= 0"]) s.add_dependency(%q, [">= 0"]) s.add_dependency(%q, [">= 0"]) end end hashery-2.1.2/README.md0000644000004100000410000001041612712231704014467 0ustar www-datawww-data# Hashery [![Gem Version](http://img.shields.io/gem/v/hashery.svg?style=flat)](http://rubygems.org/gem/hashery) [![Build Status](http://img.shields.io/travis/rubyworks/hashery.svg?style=flat)](http://travis-ci.org/rubyworks/hashery) [![Fork Me](http://img.shields.io/badge/scm-github-blue.svg?style=flat)](http://github.com/rubyworks/hashery) [![Report Issue](http://img.shields.io/github/issues/rubyworks/hashery.svg?style=flat)](http://github.com/rubyworks/hashery/issues) [![Gittip](http://img.shields.io/badge/gittip-$1/wk-green.svg?style=flat)](https://www.gittip.com/rubyworksorg/) [Homepage](http://rubyworks.github.com/hashery) · [Development](http://github.com/rubyworks/hashery) · [Report Issue](http://github.com/rubyworks/hashery/issues) · [Chat](https://kiwiirc.com/client/irc.freenode.net/?nick=user1|?#rubyworks) ## Description Among Ruby Facets most common additions were an assortment of Hash-like classes. To better support this collection of libraries it was deemed prudent to create a new project specifically for them. Hence the *Facets Hashery*. Included in this collection are the widely used OrderedHash, the related but more featured Dictionary class, a number of _open_ classes similar to the standard OpenStruct, some variations of the standard Hash class and a few other yummy morsels. ## Usage For instruction on usage, please see the individual library files included in this collection and read the demo documents which give examples of almost all features. ### Core Extensions Hashery adds four core extensions of Ruby's Hash class: `#retrieve`, `#rekey`, `#rekey!` and `Hash.create`. The first is simply an alias for `#[]`. The later two have proven too useful over the years to omit. And the last is a convenience class method for populating a new hash with another hash upon initialization. All of these are sorely missing for Ruby itself, which is why they are provided here. ## Installation To install with RubyGems simply open a console and type: $ sudo gem install hashery Or add it as a dependency to your project's Gemfile: gem "hashery" Tarball packages are available for manual site installations via [Ruby Setup](http://rubyworks.github.com/setup). ## Authors Developers who have contributed code to the project include: * Kirk Haines * Joshua Hull * Robert Klemme * Jan Molic * George Moschovitis * Jeena Paradies * Erik Veenstra ## Contributing Don't be a lump on a log. See an issue? Have a suggestion? Want to help? Well *git* in there! ### Communicating The project is hosted on Github so the easiest means of communication is via the [Issues](http://github.com/rubyworks/hashery/issues) page. For more direct communication you can try the **#rubyworks** IRC channel on **irc.freenode.net**.     [![IRC](https://kiwiirc.com/buttons/irc.freenode.net/rubyworks.png)](https://kiwiirc.com/client/irc.freenode.net/?nick=user1|?#rubyworks) ### Testing Hashery uses [QED](http://rubyworks.github.com/qed) and [Lemon](http://rubyworks.github.com/lemon) test frameworks. The QED framework to create well tested high-level documentation. Run the QED specs via: $ qed -Ilib demo/ Lemon is used to create low-level unit tests. Run these via the Rubytest: $ rubytest -Ilib -Itest test/ ### Patches Hashery's repository is hosted on [GitHub](http://github.com/rubyworks/hashery). If you'd like to offer up a fix or feature, fork the repo and submit a pull request (preferably in a topic branch). I assume you have heard all the talk about proper [practices](https://github.com/rubyworks/rubyworks.github.com/wiki/GitHub-Best-Pactices), so I won't bug you with it yet again. ### Donations Yes, we FOSS programmers need to eat too! ;-) No seriously, any help you can offer goes a long way toward continued development of Rubyworks projects, including Hashery. Hop over to our [Gittips](https://www.gittip.com/rubyworksorg/) page, or see the upper right-hand corner on the [Rubyworks](http://rubyworks.github.com) homepage. Thanks! ## Copyrights Copyright (c) 2010 Rubyworks Licensed under the *BSD-2-Clause* license. See LICENSE.txt file for further details. Some libraries included in the Hashery have special copyrights attributing specific authors. Please see each library script for specifics and the NOTICE.txt file for an overview.