hashery 1.0.0 → 1.1.0

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