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 +1 -1
- data/lib/treet/hash.rb +54 -16
- data/lib/treet/repo.rb +2 -1
- data/lib/treet/version.rb +1 -1
- data/spec/lib/hash_spec.rb +41 -10
- data/spec/lib/repo_spec.rb +3 -0
- data/spec/lib/test_gitrepo.rb +3 -0
- data/treet.gemspec +1 -0
- metadata +20 -4
data/lib/treet/gitrepo.rb
CHANGED
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
|
-
|
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
|
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(
|
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
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
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,
|
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
data/spec/lib/hash_spec.rb
CHANGED
@@ -1,12 +1,26 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
require "spec_helper"
|
3
3
|
|
4
|
-
describe
|
5
|
-
it "should
|
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
|
-
|
115
|
-
|
116
|
-
|
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
|
-
["
|
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',
|
data/spec/lib/repo_spec.rb
CHANGED
data/spec/lib/test_gitrepo.rb
CHANGED
@@ -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
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.
|
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-
|
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:
|
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:
|
234
|
+
hash: 3301508427182722923
|
219
235
|
requirements: []
|
220
236
|
rubyforge_project:
|
221
237
|
rubygems_version: 1.8.24
|