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 +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
|