treet 0.14.1 → 0.15.0

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