treet 0.14.1 → 0.15.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/lib/treet/gitrepo.rb CHANGED
@@ -186,7 +186,7 @@ class Treet::Gitrepo < Treet::Repo
186
186
  end
187
187
  end
188
188
 
189
- data
189
+ Treet::Hash.new(data)
190
190
  end
191
191
 
192
192
  def commit_id_for(tagname)
data/lib/treet/hash.rb CHANGED
@@ -1,11 +1,16 @@
1
1
  # encoding: UTF-8
2
2
 
3
+ require "map"
3
4
  require "json"
4
5
  require "digest/sha1"
6
+ require "forwardable"
5
7
 
6
8
  class Treet::Hash
7
9
  attr_reader :data
8
10
 
11
+ extend Forwardable
12
+ def_delegators :@data, :keys, :values, :hash, :[], :merge, :empty?, :any?
13
+
9
14
  # when loading an Array (at the top level), members are always sorted
10
15
  # so that array comparisons will be order-independent
11
16
  def initialize(source)
@@ -16,7 +21,11 @@ class Treet::Hash
16
21
  # treat as filename
17
22
  JSON.load(File.read(source))
18
23
  else
19
- raise "Invalid source data type #{source.class} for Treet::Hash"
24
+ if source.respond_to?(:to_hash)
25
+ initialize(source.to_hash)
26
+ else
27
+ raise "Invalid source data type #{source.class} for Treet::Hash"
28
+ end
20
29
  end
21
30
 
22
31
  @data = normalize(d)
@@ -29,17 +38,39 @@ class Treet::Hash
29
38
  end
30
39
 
31
40
  def to_hash
32
- data.to_hash
41
+ data #.to_hash
33
42
  end
34
43
 
44
+ # def normalized_data
45
+ # data.each_with_object({}) do |(k,v),h|
46
+ # h[k.to_s] = case v
47
+ # when Array
48
+ # v.sort_by {|x| x.hash}
49
+ # else
50
+ # v
51
+ # end
52
+ # end
53
+ # end
54
+ # def hash
55
+ # data.hash
56
+ # # normalized_data.hash
57
+ # end
58
+
35
59
  def compare(target)
36
60
  # HashDiff.diff(data, target.to_hash)
37
61
  Treet::Hash.diff(data.to_hash, target.to_hash)
38
62
  end
39
63
 
64
+ def ==(target)
65
+ eql?(target)
66
+ end
67
+ def eql?(target)
68
+ self.hash.eql?(Treet::Hash.new(target).hash)
69
+ end
40
70
  # apply diffs (created via the `#compare` function) to create a new object
41
71
  def patch(diffs)
42
- newhash = Treet::Hash.patch(self.to_hash, diffs)
72
+ # newhash = Treet::Hash.patch(self.to_hash, diffs)
73
+ newhash = Treet::Hash.patch(data, diffs)
43
74
  Treet::Hash.new(newhash)
44
75
  end
45
76
 
@@ -92,17 +123,21 @@ class Treet::Hash
92
123
  end
93
124
 
94
125
  def normalize(hash)
95
- hash.each_with_object({}) do |(k,v),h|
126
+ Map.new(hash).sort_by(&:first).each_with_object(Map.new) do |(k,v),h|
127
+ # Map.new(hash).each_with_object(Map.new) do |(k,v),h|
128
+ # hash.each_with_object(Map.new) do |(k,v),h|
96
129
  case v
97
130
  when Array
98
- if v.map(&:class).uniq == Hash
99
- # all elements are Hashes
100
- h[k] = v.sort do |a,b|
101
- a.to_a.sort_by(&:first).flatten <=> b.to_a.sort_by(&:first).flatten
102
- end
103
- else
104
- h[k] =v
105
- end
131
+ h[k] = v.uniq.sort_by(&:hash) if v.any?
132
+ # if v.map(&:class).uniq == Map
133
+ # # all elements are Maps
134
+ # h[k] = v.sort_by(&:hash)
135
+ # # h[k] = v.sort do |a,b|
136
+ # # a.to_a.sort_by(&:first).flatten <=> b.to_a.sort_by(&:first).flatten
137
+ # # end
138
+ # else
139
+ # h[k] = v
140
+ # end
106
141
 
107
142
  else
108
143
  h[k] = v
@@ -175,7 +210,7 @@ class Treet::Hash
175
210
  result = hash.dup
176
211
 
177
212
  diffs.each do |diff|
178
- flag, key, v1, v2 = diff
213
+ flag, key, v1, _ = diff
179
214
  if key =~ /\[/
180
215
  keyname, is_array = key.match(/^(.*)(\[\])$/).captures
181
216
  elsif key =~ /\./
@@ -197,7 +232,7 @@ class Treet::Hash
197
232
  when '+'
198
233
  # add something
199
234
  if subkey
200
- result[keyname] ||= {}
235
+ result[keyname] ||= Map.new
201
236
  result[keyname][subkey] = v1
202
237
  elsif is_array
203
238
  result[keyname] ||= []
@@ -218,8 +253,11 @@ class Treet::Hash
218
253
  end
219
254
  end
220
255
 
221
- result.delete_if {|k,v| v.nil? || v.empty?}
222
-
256
+ # result.delete_if {|k,v| v.nil? || v.empty?}
257
+ # TODO: delete_if started failing when I switched to Map, can't figure out why
258
+ result.each do |k,v|
259
+ result.delete(k) if v.nil? || v.empty?
260
+ end
223
261
  result
224
262
  end
225
263
  end
data/lib/treet/repo.rb CHANGED
@@ -144,7 +144,8 @@ class Treet::Repo
144
144
  end
145
145
 
146
146
  def expand(path)
147
- filenames(path).each_with_object({}) {|f,h| h[f] = expand_json("#{path}/#{f}")}
147
+ raw = filenames(path).each_with_object({}) {|f,h| h[f] = expand_json("#{path}/#{f}")}
148
+ Treet::Hash.new(raw)
148
149
  end
149
150
 
150
151
  def filenames(path)
data/lib/treet/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Treet
2
- VERSION = "0.14.1"
2
+ VERSION = "0.15.0"
3
3
  end
@@ -1,12 +1,26 @@
1
1
  # encoding: UTF-8
2
2
  require "spec_helper"
3
3
 
4
- describe "Hash" do
5
- it "should inject JSON" do
4
+ describe Treet::Hash do
5
+ it "should be indifferent about keys" do
6
+ h1 = Treet::Hash.new({:name => {:full => 'John Smith'}})
7
+ h2 = Treet::Hash.new({'name' => {'full' => 'John Smith'}})
8
+ h1.should == h2
9
+ end
10
+
11
+ it "should inject JSON and do indifferent comparison" do
6
12
  hash = Treet::Hash.new("#{File.dirname(__FILE__)}/../json/one.json")
7
13
  hash.data.should == {
8
14
  'name' => {'full' => 'John Bigbooté'}
9
15
  }
16
+ hash.data.should == {
17
+ :name => {:full => 'John Bigbooté'}
18
+ }
19
+ end
20
+
21
+ it "should allow no empty fields" do
22
+ hash = Treet::Hash.new({:empty => []})
23
+ hash.data.keys.should be_empty
10
24
  end
11
25
 
12
26
  it "should compare hashes to file trees" do
@@ -19,8 +33,10 @@ describe "Hash" do
19
33
  hash = Treet::Hash.new("#{File.dirname(__FILE__)}/../json/one.json")
20
34
 
21
35
  Dir.mktmpdir do |dir|
22
- hash.to_repo(dir)
36
+ repo = hash.to_repo(dir)
23
37
  JSON.load(File.open("#{dir}/name")).should == {'full' => 'John Bigbooté'}
38
+ repo.to_hash.should == hash
39
+ Treet::Repo.new(dir).to_hash.should == hash
24
40
  end
25
41
  end
26
42
 
@@ -32,6 +48,9 @@ describe "Hash" do
32
48
  hash.to_repo(dir)
33
49
  JSON.load(File.open("#{dir}/name")).should == {'full' => 'John Bigbooté'}
34
50
  end
51
+
52
+ hash2 = Treet::Hash.new({'name' => {'full' => 'John Bigbooté'}})
53
+ hash.eql?(hash2).should == true
35
54
  end
36
55
 
37
56
  it "should convert arrays to subdirs named with digests" do
@@ -57,6 +76,14 @@ describe "Hash" do
57
76
  hash1.compare(hash1).should == []
58
77
  hash1.compare(hash2).should == []
59
78
 
79
+ hash1.should == hash1
80
+ hash1.should == hash2
81
+
82
+ hash1.eql?(hash1).should == true
83
+ hash1.eql?(hash2).should == true
84
+
85
+ hash1.hash.should == hash2.hash
86
+
60
87
  hash = Treet::Hash.new("#{File.dirname(__FILE__)}/../json/two.json")
61
88
  repo = Treet::Repo.new("#{File.dirname(__FILE__)}/../repos/two")
62
89
 
@@ -111,22 +138,26 @@ describe "shallow comparison of hashes" do
111
138
  h1 = Treet::Hash.new("#{File.dirname(__FILE__)}/../json/bob1.json")
112
139
  h2 = Treet::Hash.new("#{File.dirname(__FILE__)}/../json/bob2.json")
113
140
  diffs = h1.compare(h2)
114
- # diffs.should include(["~", "name.full", "Bob Smith", "Robert Smith"])
115
- # diffs.should include(["+", "business.organization", "Acme Inc."])
116
- # diffs.should include(["-", "other.notes", "some commentary"])
117
- diffs.should == [
118
- ["~", "name.full", "Robert Smith", "Bob Smith"],
141
+ diffs.sort.should == [
142
+ ["+", "business.organization", "Acme Inc."],
143
+ ["+", "emails[]", {"label"=>"home", "email"=>"bob@newhome.com"}],
119
144
  ["-", "emails[]", {"label"=>"home", "email"=>"bob@home.com"}],
120
145
  ["-", "emails[]", {"label"=>"other", "email"=>"bob@vacation.com"}],
121
- ["+", "emails[]", {"label"=>"home", "email"=>"bob@newhome.com"}],
122
146
  ["-", "other.notes", "some commentary"],
123
- ["+", "business.organization", "Acme Inc."]
147
+ ["~", "name.full", "Robert Smith", "Bob Smith"],
124
148
  ]
125
149
 
126
150
  h3 = h1.patch(diffs)
127
151
  h3.compare(h2).should == []
128
152
  end
129
153
 
154
+ describe "comparison should ignore order of keys" do
155
+ h1 = Treet::Hash.new(:name => "foo", :addresses => [{:bar => 'baz'}, {:bar => 'biz'}, {:bar => 'boz'}], :phones => [{:label => 'home', :phone => '123-123-1234'}], :empty => [])
156
+ h2 = Treet::Hash.new('phones' => [{'label' => 'home', 'phone' => '123-123-1234'}], 'name' => 'foo', 'addresses' =>[{'bar' => 'boz'}, {'bar' => 'biz'}, {'bar' => 'baz'}, {'bar' => 'biz'}])
157
+ h1.should == h2
158
+ h1.hash.should == h2.hash
159
+ end
160
+
130
161
  describe "arrays of strings should build lists of filenames" do
131
162
  hash = Treet::Hash.new(
132
163
  :name => 'Foo Bar',
@@ -7,6 +7,9 @@ describe "Repo" do
7
7
  repo.to_hash.should == {
8
8
  'name' => {'full' => 'John Bigbooté'}
9
9
  }
10
+ repo.to_hash.should == {
11
+ :name => {:full => 'John Bigbooté'}
12
+ }
10
13
  end
11
14
 
12
15
  it "should reload on reset" do
@@ -67,6 +67,9 @@ class GitrepoTests < MiniTest::Spec
67
67
 
68
68
  it "should fetch data content" do
69
69
  johnb.to_hash.must_equal load_json('one')
70
+ johnb.to_hash.must_equal(Treet::Hash.new({:name => {:full => "John Bigbooté"}}))
71
+ jb2 = Treet::Gitrepo.new(johnb.root, :author => {})
72
+ jb2.to_hash.must_equal(Treet::Hash.new({:name => {:full => "John Bigbooté"}}))
70
73
  end
71
74
 
72
75
  it "should have no tags" do
data/treet.gemspec CHANGED
@@ -15,6 +15,7 @@ Gem::Specification.new do |gem|
15
15
  gem.require_paths = ["lib"]
16
16
  gem.version = Treet::VERSION
17
17
 
18
+ gem.add_dependency 'map'
18
19
  gem.add_dependency 'thor'
19
20
  gem.add_dependency 'rugged', "~> 0.17.0.b6"
20
21
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: treet
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.1
4
+ version: 0.15.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,24 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-18 00:00:00.000000000 Z
12
+ date: 2013-04-25 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: map
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
14
30
  - !ruby/object:Gem::Dependency
15
31
  name: thor
16
32
  requirement: !ruby/object:Gem::Requirement
@@ -206,7 +222,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
206
222
  version: '0'
207
223
  segments:
208
224
  - 0
209
- hash: -842133480250994706
225
+ hash: 3301508427182722923
210
226
  required_rubygems_version: !ruby/object:Gem::Requirement
211
227
  none: false
212
228
  requirements:
@@ -215,7 +231,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
215
231
  version: '0'
216
232
  segments:
217
233
  - 0
218
- hash: -842133480250994706
234
+ hash: 3301508427182722923
219
235
  requirements: []
220
236
  rubyforge_project:
221
237
  rubygems_version: 1.8.24