delano-storable 0.5.1 → 0.5.2

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/CHANGES.txt CHANGED
@@ -1,6 +1,18 @@
1
1
  STORABLE, CHANGES
2
2
 
3
3
 
4
+ #### 0.5.2 (2009-05-12) #############################
5
+
6
+ * CHANGE: Put OrderedHash into Storable namespace and imported merge fix from Caesars
7
+ * FIXED: Circular dependency with Sysinfo
8
+
9
+
10
+ #### 0.5.1 (2009-05-07) #############################
11
+
12
+ * FIXED: Bug in from_hash which was incorrectly parsing some data types (incl. Integer)
13
+ * ADDED: bin/example
14
+ * ADDED: OrderedHash for Ruby 1.8.x (still unordered in JRuby. Need to investigate.)
15
+
4
16
  #### 0.5 (2009-05-07) ###############################
5
17
 
6
18
  * First public release. See commit history for solutious-stella, solutious-rudy,
data/README.rdoc CHANGED
@@ -2,6 +2,30 @@
2
2
 
3
3
  Marshal Ruby classes into and out of multiple formats (yaml, json, csv, tsv)
4
4
 
5
+ == Example
6
+
7
+ require 'storable'
8
+
9
+ class Machine < Storable
10
+ field :environment # Define field names for Machine. The
11
+ field :role # default type is String, but you can
12
+ field :position => Integer # specify a type using a hash syntax.
13
+ end
14
+
15
+ mac1 = Machine.new # Instances of Machine have accessors
16
+ mac1.environment = "stage" # just like regular attributes.
17
+ mac1.role = "app"
18
+ mac1.position = 1
19
+
20
+ puts "# YAML", mac1.to_yaml # Note: the field order is maintained
21
+ puts "# CSV", mac1.to_csv # => stage,app,1
22
+ puts "# JSON", mac1.to_json # Note: field order not maintained.
23
+
24
+ mac2 = Machine.from_yaml(mac1.to_yaml)
25
+ puts mac2.environment # => "stage"
26
+ puts mac2.position.class # => Fixnum
27
+
28
+
5
29
  == Installation
6
30
 
7
31
  Via Rubygems, one of:
@@ -14,9 +38,15 @@ or via download:
14
38
  * storable-latest.zip[http://github.com/delano/storable/zipball/latest]
15
39
 
16
40
 
41
+ == Prerequisites
42
+
43
+ * Ruby 1.8, Ruby 1.9, or JRuby 1.2
44
+
45
+
17
46
  == Credits
18
47
 
19
48
  * Delano Mandelbaum (delano@solutious.com)
49
+ * OrderedHash implementation by Jan Molic
20
50
 
21
51
  == License
22
52
 
@@ -0,0 +1,199 @@
1
+ # AUTHOR
2
+ # jan molic /mig/at/1984/dot/cz/
3
+ #
4
+ # DESCRIPTION
5
+ # Hash with preserved order and some array-like extensions
6
+ # Public domain.
7
+ #
8
+ # THANKS
9
+ # Andrew Johnson for his suggestions and fixes of Hash[],
10
+ # merge, to_a, inspect and shift
11
+ class Storable::OrderedHash < ::Hash
12
+ attr_accessor :order
13
+
14
+ class << self
15
+ def [] *args
16
+ hsh = Storable::OrderedHash.new
17
+ if Hash === args[0]
18
+ hsh.replace args[0]
19
+ elsif (args.size % 2) != 0
20
+ raise ArgumentError, "odd number of elements for Hash"
21
+ else
22
+ 0.step(args.size - 1, 2) do |a|
23
+ b = a + 1
24
+ hsh[args[a]] = args[b]
25
+ end
26
+ end
27
+ hsh
28
+ end
29
+ end
30
+ def initialize(*a, &b)
31
+ super
32
+ @order = []
33
+ end
34
+ def store_only a,b
35
+ store a,b
36
+ end
37
+ alias orig_store store
38
+ def store a,b
39
+ @order.push a unless has_key? a
40
+ super a,b
41
+ end
42
+ alias []= store
43
+ def == hsh2
44
+ return false if @order != hsh2.order
45
+ super hsh2
46
+ end
47
+ def clear
48
+ @order = []
49
+ super
50
+ end
51
+ def delete key
52
+ @order.delete key
53
+ super
54
+ end
55
+ def each_key
56
+ @order.each { |k| yield k }
57
+ self
58
+ end
59
+ def each_value
60
+ @order.each { |k| yield self[k] }
61
+ self
62
+ end
63
+ def each
64
+ @order.each { |k| yield k,self[k] }
65
+ self
66
+ end
67
+ alias each_pair each
68
+ def delete_if
69
+ @order.clone.each { |k|
70
+ delete k if yield(k)
71
+ }
72
+ self
73
+ end
74
+ def values
75
+ ary = []
76
+ @order.each { |k| ary.push self[k] }
77
+ ary
78
+ end
79
+ def keys
80
+ @order
81
+ end
82
+ def first
83
+ {@order.first => self[@order.first]}
84
+ end
85
+ def last
86
+ {@order.last => self[@order.last]}
87
+ end
88
+ def invert
89
+ hsh2 = Hash.new
90
+ @order.each { |k| hsh2[self[k]] = k }
91
+ hsh2
92
+ end
93
+ def reject &block
94
+ self.dup.delete_if &block
95
+ end
96
+ def reject! &block
97
+ hsh2 = reject &block
98
+ self == hsh2 ? nil : hsh2
99
+ end
100
+ def replace hsh2
101
+ @order = hsh2.keys
102
+ super hsh2
103
+ end
104
+ def shift
105
+ key = @order.first
106
+ key ? [key,delete(key)] : super
107
+ end
108
+ def unshift k,v
109
+ unless self.include? k
110
+ @order.unshift k
111
+ orig_store(k,v)
112
+ true
113
+ else
114
+ false
115
+ end
116
+ end
117
+ def push k,v
118
+ unless self.include? k
119
+ @order.push k
120
+ orig_store(k,v)
121
+ true
122
+ else
123
+ false
124
+ end
125
+ end
126
+ def pop
127
+ key = @order.last
128
+ key ? [key,delete(key)] : nil
129
+ end
130
+ def to_a
131
+ ary = []
132
+ each { |k,v| ary << [k,v] }
133
+ ary
134
+ end
135
+ def to_s
136
+ self.to_a.to_s
137
+ end
138
+ def inspect
139
+ ary = []
140
+ each {|k,v| ary << k.inspect + "=>" + v.inspect}
141
+ '{' + ary.join(", ") + '}'
142
+ end
143
+ def update hsh2
144
+ hsh2.each { |k,v| self[k] = v }
145
+ self
146
+ end
147
+ alias :merge! update
148
+ def merge hsh2
149
+ ##self.dup update(hsh2) ## 2009-05-12 -- delano
150
+ update hsh2 ## dup doesn't take an argument
151
+ ## and there's no need for it here
152
+ end
153
+ def select
154
+ ary = []
155
+ each { |k,v| ary << [k,v] if yield k,v }
156
+ ary
157
+ end
158
+ def class
159
+ Hash
160
+ end
161
+ def __class__
162
+ Storable::OrderedHash
163
+ end
164
+
165
+ attr_accessor "to_yaml_style"
166
+ def yaml_inline= bool
167
+ if respond_to?("to_yaml_style")
168
+ self.to_yaml_style = :inline
169
+ else
170
+ unless defined? @__yaml_inline_meth
171
+ @__yaml_inline_meth =
172
+ lambda {|opts|
173
+ YAML::quick_emit(object_id, opts) {|emitter|
174
+ emitter << '{ ' << map{|kv| kv.join ': '}.join(', ') << ' }'
175
+ }
176
+ }
177
+ class << self
178
+ def to_yaml opts = {}
179
+ begin
180
+ @__yaml_inline ? @__yaml_inline_meth[ opts ] : super
181
+ rescue
182
+ @to_yaml_style = :inline
183
+ super
184
+ end
185
+ end
186
+ end
187
+ end
188
+ end
189
+ @__yaml_inline = bool
190
+ end
191
+ def yaml_inline!() self.yaml_inline = true end
192
+
193
+ def each_with_index
194
+ @order.each_with_index { |k, index| yield k, self[k], index }
195
+ self
196
+ end
197
+ end # class Storable::OrderedHash
198
+
199
+
data/lib/storable.rb CHANGED
@@ -1,20 +1,24 @@
1
1
  #--
2
2
  # TODO: Handle nested hashes and arrays.
3
3
  # TODO: to_xml, see: http://codeforpeople.com/lib/ruby/xx/xx-2.0.0/README
4
- # TODO: Rename to Stuffany
5
4
  #++
6
5
 
7
- require 'yaml'
8
- require 'fileutils'
9
6
 
7
+ USE_ORDERED_HASH = (RUBY_VERSION =~ /1.9/).nil?
8
+
9
+ require 'json' rescue nil
10
10
 
11
+ require 'yaml'
12
+ require 'fileutils'
13
+
11
14
  # Storable makes data available in multiple formats and can
12
15
  # re-create objects from files. Fields are defined using the
13
16
  # Storable.field method which tells Storable the order and
14
17
  # name.
15
18
  class Storable
19
+ require 'storable/orderedhash' if USE_ORDERED_HASH
16
20
  unless defined?(SUPPORTED_FORMATS) # We can assume all are defined
17
- VERSION = 5
21
+ VERSION = 0.5
18
22
  NICE_TIME_FORMAT = "%Y-%m-%d@%H:%M:%S".freeze
19
23
  SUPPORTED_FORMATS = [:tsv, :csv, :yaml, :json, :s, :string].freeze
20
24
  end
@@ -46,7 +50,7 @@ class Storable
46
50
  # The value is not touched when the type is not provided.
47
51
  def self.field(args={})
48
52
  # TODO: Examine casting from: http://codeforpeople.com/lib/ruby/fattr/fattr-1.0.3/
49
- args = {args => nil} unless args.is_a? Hash
53
+ args = {args => nil} unless args.kind_of?(Hash)
50
54
 
51
55
  args.each_pair do |m,t|
52
56
 
@@ -127,14 +131,15 @@ class Storable
127
131
 
128
132
  if field_types[index] == Array
129
133
  ((value ||= []) << stored_value).flatten
130
- elsif field_types[index] == Hash
134
+ elsif field_types[index].kind_of?(Hash)
131
135
 
132
136
  value = stored_value
133
137
  else
134
138
 
135
139
  # SimpleDB stores attribute shit as lists of values
136
- value = stored_value.first if stored_value.is_a?(Array) && stored_value.size == 1
137
-
140
+ ##value = stored_value.first if stored_value.is_a?(Array) && stored_value.size == 1
141
+ value = (stored_value.is_a?(Array) && stored_value.size == 1) ? stored_value.first : stored_value
142
+
138
143
  if field_types[index] == Time
139
144
  value = Time.parse(value)
140
145
  elsif field_types[index] == DateTime
@@ -145,10 +150,11 @@ class Storable
145
150
  value = value.to_f
146
151
  elsif field_types[index] == Integer
147
152
  value = value.to_i
148
- elsif field_types[index].kind_of?(Storable) && stored_value.is_a?(Hash)
149
- value = field_types[index].from_hash(stored_value)
150
- else
151
- value = (stored_value.is_a?(Array) && stored_value.size == 1) ? stored_value.first : stored_value
153
+ elsif field_types[index].kind_of?(Storable) && stored_value.kind_of?(Hash)
154
+ # I don't know why this is here so I'm going to raise an exception
155
+ # and wait a while for an error in one of my other projects.
156
+ #value = field_types[index].from_hash(stored_value)
157
+ raise "Delano, delano, delano. Clean up Storable!"
152
158
  end
153
159
  end
154
160
 
@@ -162,7 +168,7 @@ class Storable
162
168
  # Return the object data as a hash
163
169
  # +with_titles+ is ignored.
164
170
  def to_hash(with_titles=true)
165
- tmp = {}
171
+ tmp = USE_ORDERED_HASH ? Storable::OrderedHash.new : {}
166
172
  field_names.each do |fname|
167
173
  tmp[fname] = self.send(fname)
168
174
  end
@@ -170,12 +176,11 @@ class Storable
170
176
  end
171
177
 
172
178
  # Create a new instance of the object from YAML.
173
- # +from+ a YAML string split into an array by line.
174
- def self.from_yaml(from=[])
175
- # from is an array of strings
176
- from_str = from.join('')
179
+ # +from+ a YAML String or Array (split into by line).
180
+ def self.from_yaml(*from)
181
+ from_str = [from].flatten.compact.join('')
177
182
  hash = YAML::load(from_str)
178
- hash = from_hash(hash) if hash.is_a? Hash
183
+ hash = from_hash(hash) if hash.kind_of?(Hash)
179
184
  hash
180
185
  end
181
186
  def to_yaml(with_titles=true)
@@ -183,21 +188,18 @@ class Storable
183
188
  end
184
189
 
185
190
  # Create a new instance of the object from a JSON string.
186
- # +from+ a JSON string split into an array by line.
187
- def self.from_json(from=[])
188
- require 'json'
189
- # from is an array of strings
190
- from_str = from.join('')
191
+ # +from+ a YAML String or Array (split into by line).
192
+ def self.from_json(*from)
193
+ from_str = [from].flatten.compact.join('')
191
194
  tmp = JSON::load(from_str)
192
195
  hash_sym = tmp.keys.inject({}) do |hash, key|
193
196
  hash[key.to_sym] = tmp[key]
194
197
  hash
195
198
  end
196
- hash_sym = from_hash(hash_sym) if hash_sym.is_a? Hash
199
+ hash_sym = from_hash(hash_sym) if hash_sym.kind_of?(Hash)
197
200
  hash_sym
198
201
  end
199
202
  def to_json(with_titles=true)
200
- require 'json'
201
203
  to_hash.to_json
202
204
  end
203
205
 
@@ -255,7 +257,7 @@ class Storable
255
257
  next unless values[index]
256
258
  hash[key.to_sym] = values[index]
257
259
  end
258
- hash = from_hash(hash) if hash.is_a? Hash
260
+ hash = from_hash(hash) if hash.kind_of?(Hash)
259
261
  hash
260
262
  end
261
263
 
data/storable.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  @spec = Gem::Specification.new do |s|
2
2
  s.name = "storable"
3
3
  s.rubyforge_project = "storable"
4
- s.version = "0.5.1"
4
+ s.version = "0.5.2"
5
5
  s.summary = "Storable: Marshal Ruby classes into and out of multiple formats (yaml, json, csv, tsv)"
6
6
  s.description = s.summary
7
7
  s.author = "Delano Mandelbaum"
@@ -16,8 +16,7 @@
16
16
 
17
17
  # = DEPENDENCIES =
18
18
  # Add all gem dependencies
19
- s.add_dependency 'sysinfo', '>= 0.5.0'
20
-
19
+
21
20
  # = MANIFEST =
22
21
  # The complete list of files to be included in the release. When GitHub packages your gem,
23
22
  # it doesn't allow you to run any command that accesses the filesystem. You will get an
@@ -30,6 +29,7 @@
30
29
  README.rdoc
31
30
  Rakefile
32
31
  lib/storable.rb
32
+ lib/storable/orderedhash.rb
33
33
  storable.gemspec
34
34
  )
35
35
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: delano-storable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Delano Mandelbaum
@@ -12,16 +12,6 @@ cert_chain: []
12
12
  date: 2009-04-08 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
- - !ruby/object:Gem::Dependency
16
- name: sysinfo
17
- type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
20
- requirements:
21
- - - ">="
22
- - !ruby/object:Gem::Version
23
- version: 0.5.0
24
- version:
25
15
  - !ruby/object:Gem::Dependency
26
16
  name: RedCloth
27
17
  type: :runtime
@@ -47,6 +37,7 @@ files:
47
37
  - README.rdoc
48
38
  - Rakefile
49
39
  - lib/storable.rb
40
+ - lib/storable/orderedhash.rb
50
41
  - storable.gemspec
51
42
  has_rdoc: true
52
43
  homepage: http://solutious.com/