Class: Gash::Tree

Inherits:
Hash
  • Object
show all
Includes:
Helpers
Defined in:
lib/gash.rb

Overview

A Tree is a Hash which can store other instances of Tree and Blob.

Special methods

Internally, a tree is being stored like this:

{
  "README" => blob,
  "examples" => {
    "test.rb" => blob,
    "yay.rb" => blob
  }
}

So you have to do tree["examples"].delete("test.rb") instead of tree.delete("examples/test.rb"). However, there are some methods which supports the slash. All of these will work:

tree["examples/test.rb"]
tree.fetch("examples/test.rb")
tree["examples/another.rb"] = "Content"
tree.store("examples/another.rb", "Content") # Exactly the same as above.

tree["examples"]["test.rb"] # Or, you could use this

Documentation

The point of Tree is that it should be as close to Hash as possible. Therefore, methods which behaves exactly equally in Gash and Hash will not be documentated below. Please see the Ruby documentation if you wonder what you can do.

See also: Helpers, Blob

Instance Attribute Summary

Attributes included from Helpers

#mode, #parent, #sha1

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Helpers

#blob?, #changed!, #changed?, #gash, #initialize, #normalize, #tree?

Class Method Details

.[](*val) ⇒ Object



242
243
244
# File 'lib/gash.rb', line 242

def self.[](*val)
  new.merge!(Hash[*val])
end

Instance Method Details

#/Object

Retrieves the value stored as key:

tree["FILE"] == File.read("FILE")
tree["DIR/FILE"] == tree["DIR"]["FILE"] == File.read("DIR/FILE")

Lazy loading

By default, this method will automatically load the blob/tree from the repo. If you rather want to load it later, simply set lazy to true:

blob = tree["FILE", true]
# do some other stuff...
blob.load! # Load it now!


156
157
158
159
160
# File 'lib/gash.rb', line 156

def [](key, lazy = nil)
  ret = fetch(key, default)
ensure
  ret.load! if ret.respond_to?(:load!) && !lazy
end

#==(other) ⇒ Object



246
247
248
249
250
251
252
# File 'lib/gash.rb', line 246

def ==(other)
  if other.is_a?(Tree) && sha1 && other.sha1
    sha1 == other.sha1
  else
    super
  end
end

#[](key, lazy = nil) ⇒ Object

Retrieves the value stored as key:

tree["FILE"] == File.read("FILE")
tree["DIR/FILE"] == tree["DIR"]["FILE"] == File.read("DIR/FILE")

Lazy loading

By default, this method will automatically load the blob/tree from the repo. If you rather want to load it later, simply set lazy to true:

blob = tree["FILE", true]
# do some other stuff...
blob.load! # Load it now!


151
152
153
154
155
# File 'lib/gash.rb', line 151

def [](key, lazy = nil)
  ret = fetch(key, default)
ensure
  ret.load! if ret.respond_to?(:load!) && !lazy
end

#[]=(key, value, not_changed = nil) ⇒ Object Also known as: store

Stores the given value at key:

tree["FILE"] = "Content"

It uses Helpers#normalize in order convert it to a blob/tree, and will always set the parent to itself:

tree["FILE"] = "Content"
  # is the same as:
tree["FILE"] = Gash::Blob.new(:content => "Content", :parent => tree)

Mark as changed

By default, the object will be marked as changed (using Helpers#changed!). If this is not what you want, simply set not_changed to true.

However, if you give it three arguments, then the second one will act as not_changed, not the third:

       1       2        3
tree["FILE", true] = "Test"
tree["FILE"].changed? # => false


181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/gash.rb', line 181

def []=(key, value, not_changed = nil)
  key, value, not_changed = if not_changed.nil?
    [key, value]
  else
    [key, not_changed, value]
  end
  
  if key.include?("/")
    keys = key.split("/")
    name = keys.pop
    keys.inject(self) do |memo, i|
      memo[i, not_changed] = Tree.new(:parent => self) unless memo.include?(i)
      memo[i, true]
    end[name, not_changed] = value
  else
    value = normalize(value)
    value.parent = self
    super(key, value)
  end
ensure
  self.changed! unless not_changed
end

#delete(key) ⇒ Object



238
239
240
# File 'lib/gash.rb', line 238

def delete(key)
  super && changed!
end

#fetch(*args) ⇒ Object

:stopdoc:



214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/gash.rb', line 214

def fetch(*args)
  key = args.first.to_s
  
  case args.length
  when 1
    r = true
  when 2
    r = false
    default = args.last
  else
    raise ArgumentError, "wrong number of arguments (#{args.length} for 2)"
  end
  
  if key.include?("/")
    key, rest = key.split("/", 2)
    value = super(key)
    value.fetch(rest)
  else
    super(key)
  end
rescue IndexError => e
  (r && raise(e)) || default
end

#merge(hash) ⇒ Object



254
255
256
257
# File 'lib/gash.rb', line 254

def merge(hash)
  tree = self.dup
  tree.merge!(hash)
end

#merge!(hash) ⇒ Object Also known as: update



259
260
261
262
263
264
# File 'lib/gash.rb', line 259

def merge!(hash)
  hash.each do |key, value|
    self[key] = value
  end
  self
end

#replace(hash) ⇒ Object



267
268
269
270
271
272
273
274
# File 'lib/gash.rb', line 267

def replace(hash)
  if hash.is_a?(Gash::Tree)
    super
  else
    clear
    merge!(hash)
  end
end

#to_hashObject

Converts the tree to a Hash.



206
207
208
209
210
211
# File 'lib/gash.rb', line 206

def to_hash
  inject({}) do |memo, (key, value)|
    memo[key] = value.respond_to?(:to_hash) ? value.to_hash : value.to_s
    memo
  end
end