hashery 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/HISTORY CHANGED
@@ -1,3 +1,24 @@
1
+ = RELEASE HISTORY
2
+
3
+ == 1.1.0 // 2010-04-28
4
+
5
+ A follow-up release of Hashery that adds two new libraries:
6
+ Association and SparseArray. Both of these may seem like odd
7
+ entries, but they each belong in a unique way. An Association
8
+ is akin to a single entry Hash --it represents a pairing.
9
+ While a SpareArray, though compatible with the Array class,
10
+ is completely under-pinned by a Hash in order to make it
11
+ effcient when no ebtries are given for a set of indexes,
12
+ hence "sparse".
13
+
14
+ Changes:
15
+
16
+ * 2 New Libraries
17
+
18
+ * Added association.rb
19
+ * Added sparsearray.rb
20
+
21
+
1
22
  == 1.0.0 // 2010-04-21
2
23
 
3
24
  This is the first release of the Facets Hashery.
@@ -0,0 +1,160 @@
1
+ # Copyright (c) 2005 Thomas Sawyer
2
+
3
+ # = Association
4
+ #
5
+ # General binary association allows one object to be
6
+ # associated with another. It has a variety of uses,
7
+ # link-lists, simple ordered maps and mixed collections,
8
+ # among them.
9
+ #
10
+ # NOTE: This class is still fairly experimental.
11
+ #
12
+ # == Usage
13
+ #
14
+ # Associations can be used to draw simple relationships.
15
+ #
16
+ # :Apple >> :Fruit
17
+ # :Apple >> :Red
18
+ #
19
+ # :Apple.associations #=> [ :Fruit, :Red ]
20
+ #
21
+ # It can also be used for simple lists of ordered pairs.
22
+ #
23
+ # c = [ :a >> 1, :b >> 2 ]
24
+ # c.each { |k,v| puts "#{k} associated with #{v} }
25
+ #
26
+ # produces
27
+ #
28
+ # a associated with 1
29
+ # b associated with 2
30
+ #
31
+ # == Limitations
32
+ #
33
+ # The method :>> is used to construct the association.
34
+ # It is a rarely used method so it is generally available.
35
+ # But you can't use it for any of the following classes
36
+ # becuase they use #>> for other things.
37
+ #
38
+ # Bignum
39
+ # Fixnum
40
+ # Date
41
+ # IPAddr
42
+ # Process::Status
43
+ #
44
+ #--
45
+ # TODO: Should associations be singleton?
46
+ #
47
+ # TODO: Is it really wise to keep a table of all associations?
48
+ #++
49
+
50
+ class Association
51
+ include Comparable
52
+
53
+ class << self
54
+ # Store association references.
55
+ def reference
56
+ @reference ||= Hash.new{ |h,k,v| h[k]=[] }
57
+ end
58
+
59
+ def [](index, value)
60
+ new(index, value)
61
+ end
62
+
63
+ #def new(index, value)
64
+ # lookup[[index, value]] ||= new(index, value)
65
+ #end
66
+
67
+ #def lookup
68
+ # @lookup ||= {}
69
+ #end
70
+ end
71
+
72
+ attr_accessor :index
73
+ attr_accessor :value
74
+
75
+ def initialize(index, value=nil)
76
+ @index = index
77
+ @value = value
78
+
79
+ unless index.associations.include?(value)
80
+ index.associations << value
81
+ end
82
+ end
83
+
84
+ def <=>(assoc)
85
+ return -1 if self.value < assoc.value
86
+ return 1 if self.value > assoc.value
87
+ return 0 if self.value == assoc.value
88
+ end
89
+
90
+ def invert!
91
+ temp = @index
92
+ @index = @value
93
+ @value = temp
94
+ end
95
+
96
+ def to_s
97
+ return "#{index.to_s}#{value.to_s}"
98
+ end
99
+
100
+ def inspect
101
+ %{#{@index.inspect} >> #{@value.inspect}}
102
+ end
103
+
104
+ def to_ary
105
+ [ @index, @value ]
106
+ end
107
+
108
+ # Object extensions.
109
+ #
110
+ module Kernel
111
+
112
+ # Define an association with +self+.
113
+ def >>(to)
114
+ Association.new(self, to)
115
+ end
116
+
117
+ def associations
118
+ Association.reference[self]
119
+ end
120
+
121
+ end
122
+
123
+ end
124
+
125
+ class Object #:nodoc:
126
+ include Association::Kernel
127
+ end
128
+
129
+
130
+ #--
131
+ # Setup the >> method in classes that use it already.
132
+ #
133
+ # This is a bad idea b/c it can cause backward compability issues.
134
+ #
135
+ # class Bignum
136
+ # alias_method( :rshift, :>>) if method_defined?(:>>)
137
+ # remove_method :>>
138
+ # end
139
+ #
140
+ # class Fixnum
141
+ # alias_method( :rshift, :>>) if method_defined?(:>>)
142
+ # remove_method :>>
143
+ # end
144
+ #
145
+ # class Date
146
+ # alias_method( :months_later, :>>) if method_defined?(:>>)
147
+ # remove_method :>>
148
+ # end
149
+ #
150
+ # class IPAddr
151
+ # alias_method( :rshift, :>>) if method_defined?(:>>)
152
+ # remove_method :>>
153
+ # end
154
+ #
155
+ # class Process::Status
156
+ # alias_method( :rshift, :>>) if method_defined?(:>>)
157
+ # remove_method :>>
158
+ # end
159
+ #++
160
+
@@ -0,0 +1,267 @@
1
+ # ini.rb - read and write ini files
2
+ #
3
+ # Copyright (C) 2007 Jeena Paradies
4
+ # License: GPL
5
+ # Author: Jeena Paradies (info@jeenaparadies.net)
6
+ #
7
+ # This file provides a read-wite handling for ini files.
8
+ # The data of a ini file is represented by a object which
9
+ # is populated with strings.
10
+
11
+ # Class with methods to read from and write into ini files.
12
+ #
13
+ # A ini file is a text file in a specific format,
14
+ # it may include several fields which are sparated by
15
+ # field headlines which are enclosured by "[]".
16
+ # Each field may include several key-value pairs.
17
+ #
18
+ # Each key-value pair is represented by one line and
19
+ # the value is sparated from the key by a "=".
20
+ #
21
+ # == Examples
22
+ #
23
+ # === Example ini file
24
+ #
25
+ # # this is the first comment which will be saved in the comment attribute
26
+ # mail=info@example.com
27
+ # domain=example.com # this is a comment which will not be saved
28
+ # [database]
29
+ # db=example
30
+ # user=john
31
+ # passwd=very-secure
32
+ # host=localhost
33
+ # # this is another comment
34
+ # [filepaths]
35
+ # tmp=/tmp/example
36
+ # lib=/home/john/projects/example/lib
37
+ # htdocs=/home/john/projects/example/htdocs
38
+ # [ texts ]
39
+ # wellcome=Wellcome on my new website!
40
+ # Website description = This is only a example. # and another comment
41
+ #
42
+ # === Example object
43
+ #
44
+ # A Ini#comment stores:
45
+ # "this is the first comment which will be saved in the comment attribute"
46
+ #
47
+ # A Ini object stores:
48
+ #
49
+ # {
50
+ # "mail" => "info@example.com",
51
+ # "domain" => "example.com",
52
+ # "database" => {
53
+ # "db" => "example",
54
+ # "user" => "john",
55
+ # "passwd" => "very-secure",
56
+ # "host" => "localhost"
57
+ # },
58
+ # "filepaths" => {
59
+ # "tmp" => "/tmp/example",
60
+ # "lib" => "/home/john/projects/example/lib",
61
+ # "htdocs" => "/home/john/projects/example/htdocs"
62
+ # }
63
+ # "texts" => {
64
+ # "wellcome" => "Wellcome on my new website!",
65
+ # "Website description" => "This is only a example."
66
+ # }
67
+ # }
68
+ #
69
+ # As you can see this module gets rid of all comments, linebreaks
70
+ # and unnecessary spaces at the beginning and the end of each
71
+ # field headline, key or value.
72
+ #
73
+ # === Using the object
74
+ #
75
+ # Using the object is stright forward:
76
+ #
77
+ # ini = Ini.new("path/settings.ini")
78
+ # ini["mail"] = "info@example.com"
79
+ # ini["filepaths"] = { "tmp" => "/tmp/example" }
80
+ # ini.comment = "This is\na comment"
81
+ # puts ini["filepaths"]["tmp"]
82
+ # # => /tmp/example
83
+ # ini.write()
84
+ #
85
+
86
+ class Ini
87
+
88
+
89
+ #
90
+ # :inihash is a hash which holds all ini data
91
+ # :comment is a string which holds the comments on the top of the file
92
+ #
93
+ attr_accessor :inihash, :comment
94
+
95
+ #
96
+ # Creating a new Ini object
97
+ #
98
+ # +path+ is a path to the ini file
99
+ # +load+ if nil restores the data if possible
100
+ # if true restores the data, if not possible raises an error
101
+ # if false does not resotre the data
102
+ #
103
+ def initialize(path, load=nil)
104
+ @path = path
105
+ @inihash = {}
106
+
107
+ if load or ( load.nil? and FileTest.readable_real? @path )
108
+ restore()
109
+ end
110
+ end
111
+
112
+ #
113
+ # Retrive the ini data for the key +key+
114
+ #
115
+ def [](key)
116
+ @inihash[key]
117
+ end
118
+
119
+ #
120
+ # Set the ini data for the key +key+
121
+ #
122
+ def []=(key, value)
123
+ raise TypeError, "String expected" unless key.is_a? String
124
+ raise TypeError, "String or Hash expected" unless value.is_a? String or value.is_a? Hash
125
+
126
+ @inihash[key] = value
127
+ end
128
+
129
+ #
130
+ # Restores the data from file into the object
131
+ #
132
+ def restore()
133
+ @inihash = Ini.read_from_file(@path)
134
+ @comment = Ini.read_comment_from_file(@path)
135
+ end
136
+
137
+ #
138
+ # Store data from the object in the file
139
+ #
140
+ def update()
141
+ Ini.write_to_file(@path, @inihash, @comment)
142
+ end
143
+
144
+ #
145
+ def to_h
146
+ @inihash.dup
147
+ end
148
+
149
+ #
150
+ # Reading data from file
151
+ #
152
+ # +path+ is a path to the ini file
153
+ #
154
+ # returns a hash which represents the data from the file
155
+ #
156
+ def Ini.read_from_file(path)
157
+
158
+ inihash = {}
159
+ headline = nil
160
+
161
+ IO.foreach(path) do |line|
162
+
163
+ line = line.strip.split(/#/)[0]
164
+
165
+ # read it only if the line doesn't begin with a "=" and is long enough
166
+ unless line.length < 2 and line[0,1] == "="
167
+
168
+ # it's a headline if the line begins with a "[" and ends with a "]"
169
+ if line[0,1] == "[" and line[line.length - 1, line.length] == "]"
170
+
171
+ # get rid of the [] and unnecessary spaces
172
+ headline = line[1, line.length - 2 ].strip
173
+ inihash[headline] = {}
174
+ else
175
+
176
+ key, value = line.split(/=/, 2)
177
+
178
+ key = key.strip unless key.nil?
179
+ value = value.strip unless value.nil?
180
+
181
+ unless headline.nil?
182
+ inihash[headline][key] = value
183
+ else
184
+ inihash[key] = value unless key.nil?
185
+ end
186
+ end
187
+ end
188
+ end
189
+
190
+ inihash
191
+ end
192
+
193
+ #
194
+ # Reading comments from file
195
+ #
196
+ # +path+ is a path to the ini file
197
+ #
198
+ # Returns a string with comments from the beginning of the
199
+ # ini file.
200
+ #
201
+ def Ini.read_comment_from_file(path)
202
+ comment = ""
203
+
204
+ IO.foreach(path) do |line|
205
+ line.strip!
206
+ break unless line[0,1] == "#" or line == ""
207
+
208
+ comment << "#{line[1, line.length ].strip}\n"
209
+ end
210
+
211
+ comment
212
+ end
213
+
214
+ #
215
+ # Writing a ini hash into a file
216
+ #
217
+ # +path+ is a path to the ini file
218
+ # +inihash+ is a hash representing the ini File. Default is a empty hash.
219
+ # +comment+ is a string with comments which appear on the
220
+ # top of the file. Each line will get a "#" before.
221
+ # Default is no comment.
222
+ #
223
+ def Ini.write_to_file(path, inihash={}, comment=nil)
224
+ raise TypeError, "String expected" unless comment.is_a? String or comment.nil?
225
+
226
+ raise TypeError, "Hash expected" unless inihash.is_a? Hash
227
+ File.open(path, "w") { |file|
228
+
229
+ unless comment.nil?
230
+ comment.each do |line|
231
+ file << "# #{line}"
232
+ end
233
+ end
234
+
235
+ file << Ini.to_s(inihash)
236
+ }
237
+ end
238
+
239
+ #
240
+ # Turn a hash (up to 2 levels deepness) into a ini string
241
+ #
242
+ # +inihash+ is a hash representing the ini File. Default is a empty hash.
243
+ #
244
+ # Returns a string in the ini file format.
245
+ #
246
+ def Ini.to_s(inihash={})
247
+ str = ""
248
+
249
+ inihash.each do |key, value|
250
+
251
+ if value.is_a? Hash
252
+ str << "[#{key.to_s}]\n"
253
+
254
+ value.each do |under_key, under_value|
255
+ str << "#{under_key.to_s}=#{under_value.to_s unless under_value.nil?}\n"
256
+ end
257
+
258
+ else
259
+ str << "#{key.to_s}=#{value.to_s unless value2.nil?}\n"
260
+ end
261
+ end
262
+
263
+ str
264
+ end
265
+
266
+ end
267
+