valise 0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/doc/README +69 -0
- data/doc/Specification +72 -0
- data/doc/Specifications +81 -0
- data/doc/coverage/assets/0.5.3/app.js +88 -0
- data/doc/coverage/assets/0.5.3/fancybox/blank.gif +0 -0
- data/doc/coverage/assets/0.5.3/fancybox/fancy_close.png +0 -0
- data/doc/coverage/assets/0.5.3/fancybox/fancy_loading.png +0 -0
- data/doc/coverage/assets/0.5.3/fancybox/fancy_nav_left.png +0 -0
- data/doc/coverage/assets/0.5.3/fancybox/fancy_nav_right.png +0 -0
- data/doc/coverage/assets/0.5.3/fancybox/fancy_shadow_e.png +0 -0
- data/doc/coverage/assets/0.5.3/fancybox/fancy_shadow_n.png +0 -0
- data/doc/coverage/assets/0.5.3/fancybox/fancy_shadow_ne.png +0 -0
- data/doc/coverage/assets/0.5.3/fancybox/fancy_shadow_nw.png +0 -0
- data/doc/coverage/assets/0.5.3/fancybox/fancy_shadow_s.png +0 -0
- data/doc/coverage/assets/0.5.3/fancybox/fancy_shadow_se.png +0 -0
- data/doc/coverage/assets/0.5.3/fancybox/fancy_shadow_sw.png +0 -0
- data/doc/coverage/assets/0.5.3/fancybox/fancy_shadow_w.png +0 -0
- data/doc/coverage/assets/0.5.3/fancybox/fancy_title_left.png +0 -0
- data/doc/coverage/assets/0.5.3/fancybox/fancy_title_main.png +0 -0
- data/doc/coverage/assets/0.5.3/fancybox/fancy_title_over.png +0 -0
- data/doc/coverage/assets/0.5.3/fancybox/fancy_title_right.png +0 -0
- data/doc/coverage/assets/0.5.3/fancybox/fancybox-x.png +0 -0
- data/doc/coverage/assets/0.5.3/fancybox/fancybox-y.png +0 -0
- data/doc/coverage/assets/0.5.3/fancybox/fancybox.png +0 -0
- data/doc/coverage/assets/0.5.3/fancybox/jquery.fancybox-1.3.1.css +363 -0
- data/doc/coverage/assets/0.5.3/fancybox/jquery.fancybox-1.3.1.pack.js +44 -0
- data/doc/coverage/assets/0.5.3/favicon_green.png +0 -0
- data/doc/coverage/assets/0.5.3/favicon_red.png +0 -0
- data/doc/coverage/assets/0.5.3/favicon_yellow.png +0 -0
- data/doc/coverage/assets/0.5.3/highlight.css +129 -0
- data/doc/coverage/assets/0.5.3/highlight.pack.js +1 -0
- data/doc/coverage/assets/0.5.3/jquery-1.6.2.min.js +18 -0
- data/doc/coverage/assets/0.5.3/jquery.dataTables.min.js +152 -0
- data/doc/coverage/assets/0.5.3/jquery.timeago.js +141 -0
- data/doc/coverage/assets/0.5.3/jquery.url.js +174 -0
- data/doc/coverage/assets/0.5.3/loading.gif +0 -0
- data/doc/coverage/assets/0.5.3/magnify.png +0 -0
- data/doc/coverage/assets/0.5.3/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/doc/coverage/assets/0.5.3/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/doc/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/doc/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/doc/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/doc/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/doc/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/doc/coverage/assets/0.5.3/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/doc/coverage/assets/0.5.3/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/doc/coverage/assets/0.5.3/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/doc/coverage/assets/0.5.3/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/doc/coverage/assets/0.5.3/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/doc/coverage/assets/0.5.3/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/doc/coverage/assets/0.5.3/smoothness/jquery-ui-1.8.4.custom.css +295 -0
- data/doc/coverage/assets/0.5.3/stylesheet.css +383 -0
- data/doc/coverage/index.html +5843 -0
- data/doc/coverage/jquery-1.3.2.min.js +19 -0
- data/doc/coverage/jquery.tablesorter.min.js +15 -0
- data/doc/coverage/lib-fileset-errors_rb.html +231 -0
- data/doc/coverage/lib-fileset-item_rb.html +303 -0
- data/doc/coverage/lib-fileset-populator_rb.html +249 -0
- data/doc/coverage/lib-fileset-search-root_rb.html +1053 -0
- data/doc/coverage/lib-fileset-utils_rb.html +453 -0
- data/doc/coverage/lib-fileset_rb.html +789 -0
- data/doc/coverage/print.css +12 -0
- data/doc/coverage/rcov.js +42 -0
- data/doc/coverage/screen.css +270 -0
- data/lib/valise/errors.rb +30 -0
- data/lib/valise/item.rb +105 -0
- data/lib/valise/path-matcher.rb +113 -0
- data/lib/valise/search-root.rb +166 -0
- data/lib/valise/stack.rb +169 -0
- data/lib/valise/stem-decorator.rb +56 -0
- data/lib/valise/utils.rb +65 -0
- data/lib/valise.rb +219 -0
- data/spec/addable.rb +41 -0
- data/spec/dump_load.rb +32 -0
- data/spec/error_handling.rb +9 -0
- data/spec/fileset.rb +170 -0
- data/spec/glob_handling.rb +28 -0
- data/spec/item.rb +35 -0
- data/spec/merge_diff.rb +93 -0
- data/spec/population.rb +51 -0
- data/spec/search_root.rb +24 -0
- data/spec/stemming.rb +33 -0
- data/spec_help/file-sandbox.rb +164 -0
- data/spec_help/gem_test_suite.rb +17 -0
- data/spec_help/spec_helper.rb +3 -0
- data/spec_help/ungemmer.rb +37 -0
- metadata +220 -0
@@ -0,0 +1,166 @@
|
|
1
|
+
require 'valise/errors'
|
2
|
+
require 'valise/utils'
|
3
|
+
require 'valise/item'
|
4
|
+
require 'fileutils'
|
5
|
+
#require 'enum'
|
6
|
+
|
7
|
+
module Valise
|
8
|
+
class SearchRoot
|
9
|
+
include Unpath
|
10
|
+
include Enumerable
|
11
|
+
|
12
|
+
def initialize(path)
|
13
|
+
@segments = unpath(path)
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :segments
|
17
|
+
|
18
|
+
def each
|
19
|
+
paths = [[]]
|
20
|
+
until paths.empty?
|
21
|
+
rel = paths.shift
|
22
|
+
path = repath(@segments + rel)
|
23
|
+
#symlinks?
|
24
|
+
if(File::directory?(path))
|
25
|
+
Dir.entries(path).each do |entry|
|
26
|
+
next if entry == "."
|
27
|
+
next if entry == ".."
|
28
|
+
paths.push(rel + [entry])
|
29
|
+
end
|
30
|
+
elsif(File::file?(path))
|
31
|
+
yield(unpath(rel))
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def inspect
|
37
|
+
"#{self.class.name.split(":").last}:#{[*@segments].join("/")}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def full_path(segments)
|
41
|
+
repath(@segments + segments)
|
42
|
+
end
|
43
|
+
|
44
|
+
def write(item)
|
45
|
+
return if item.contents.nil?
|
46
|
+
FileUtils::mkdir_p(::File::dirname(item.full_path))
|
47
|
+
File::open(item.full_path, "w") do |file|
|
48
|
+
file.write(item.dump_contents)
|
49
|
+
end
|
50
|
+
item
|
51
|
+
end
|
52
|
+
|
53
|
+
def writable?(segments)
|
54
|
+
path = full_path(segments)
|
55
|
+
return (!File::exists?(path) or File::writable?(path))
|
56
|
+
end
|
57
|
+
|
58
|
+
def present?(segments)
|
59
|
+
return File::exists?(full_path(segments))
|
60
|
+
end
|
61
|
+
|
62
|
+
def insert(item)
|
63
|
+
if(File::exists?(item.full_path))
|
64
|
+
raise WouldClobber.new(Item.new(item.stack.segments, self, nil))
|
65
|
+
else
|
66
|
+
write(item)
|
67
|
+
return item
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def get_from(item)
|
72
|
+
File::read(item.full_path)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class ReadOnlySearchRoot < SearchRoot
|
77
|
+
def writable?(segments)
|
78
|
+
false
|
79
|
+
end
|
80
|
+
|
81
|
+
def write(item)
|
82
|
+
raise ReadOnly
|
83
|
+
end
|
84
|
+
|
85
|
+
def insert(item)
|
86
|
+
raise ReadOnly
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
class DefinedDefaults < ReadOnlySearchRoot
|
91
|
+
def initialize
|
92
|
+
@files = {}
|
93
|
+
end
|
94
|
+
|
95
|
+
def segments
|
96
|
+
raise VirtualSearchPath, "does not have a real path"
|
97
|
+
end
|
98
|
+
|
99
|
+
def present?(segments)
|
100
|
+
@files.has_key?(segments)
|
101
|
+
end
|
102
|
+
|
103
|
+
def each
|
104
|
+
@files.each_key do |path|
|
105
|
+
yield(unpath(path))
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def get_from(item)
|
110
|
+
return @files[item.segments]
|
111
|
+
end
|
112
|
+
|
113
|
+
def define(&block)
|
114
|
+
unless block.nil?
|
115
|
+
definer = DefinitionHelper.new(self)
|
116
|
+
definer.instance_eval &block
|
117
|
+
end
|
118
|
+
return self
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.define(&block)
|
122
|
+
return self.new.define(&block)
|
123
|
+
end
|
124
|
+
|
125
|
+
def add_item(path, contents)
|
126
|
+
check_path = path[0..-2]
|
127
|
+
until check_path.empty?
|
128
|
+
if @files.has_key?(check_path)
|
129
|
+
raise MalformedTree, "Tried to add items below #{path[0..-2]} which is not a directory"
|
130
|
+
end
|
131
|
+
check_path.pop
|
132
|
+
end
|
133
|
+
@files[path] = contents
|
134
|
+
end
|
135
|
+
|
136
|
+
def add_dir(path)
|
137
|
+
#add_item(path, ValiseWorks::Directory.new(path))
|
138
|
+
end
|
139
|
+
|
140
|
+
def add_file(path, data = nil)
|
141
|
+
add_item(path, data)
|
142
|
+
end
|
143
|
+
|
144
|
+
class DefinitionHelper
|
145
|
+
def initialize(target)
|
146
|
+
@target = target
|
147
|
+
@prefix = []
|
148
|
+
end
|
149
|
+
|
150
|
+
def dir(name)
|
151
|
+
path = @prefix + [name]
|
152
|
+
@target.add_dir(path)
|
153
|
+
@prefix.push(name)
|
154
|
+
yield if block_given?
|
155
|
+
@prefix.pop
|
156
|
+
end
|
157
|
+
|
158
|
+
def file(name, data=nil)
|
159
|
+
path = @prefix + [name.to_s]
|
160
|
+
@target.add_file(path, data)
|
161
|
+
end
|
162
|
+
|
163
|
+
include StringTools
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
data/lib/valise/stack.rb
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
# New plan here: Stack is returned by "find" and responds to many of the
|
2
|
+
# methods that Item current responds to. It caches results, essentially, of
|
3
|
+
# the find search - maybe at creation, with possiblity for reload/update.
|
4
|
+
# Also, makes possible use cases like file promotion, merging, etc.
|
5
|
+
#
|
6
|
+
# Still need to resolve the interface for parsing and merging files.
|
7
|
+
#
|
8
|
+
# * something from the Valise definition - would have to be part of defaults,
|
9
|
+
# which further is a problem if a file doesn't exist in the defaults
|
10
|
+
#
|
11
|
+
# * a filetype mapping
|
12
|
+
#
|
13
|
+
# * Is it a find-time user thing
|
14
|
+
|
15
|
+
|
16
|
+
module Valise
|
17
|
+
module ItemEnum
|
18
|
+
include Enumerable
|
19
|
+
|
20
|
+
class Enumerator
|
21
|
+
include ItemEnum
|
22
|
+
|
23
|
+
def initialize(list, &filter)
|
24
|
+
@list = list
|
25
|
+
@filter = proc(&filter)
|
26
|
+
end
|
27
|
+
|
28
|
+
def each
|
29
|
+
@list.each do |item|
|
30
|
+
next unless @filter[item]
|
31
|
+
yield(item)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def writable
|
37
|
+
Enumerator.new(self) do |item|
|
38
|
+
item.writable?
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def absent
|
43
|
+
Enumerator.new(self) do |item|
|
44
|
+
not item.present?
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def present
|
49
|
+
Enumerator.new(self) do |item|
|
50
|
+
item.present?
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class MergeDiff
|
56
|
+
@@classes = {}
|
57
|
+
def self.[](index)
|
58
|
+
@@classes[index]
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.register(index)
|
62
|
+
@@classes[index] = self
|
63
|
+
end
|
64
|
+
|
65
|
+
def initialize(stack)
|
66
|
+
@stack = stack
|
67
|
+
end
|
68
|
+
|
69
|
+
class TopMost < MergeDiff
|
70
|
+
register :topmost
|
71
|
+
|
72
|
+
def merge(item)
|
73
|
+
item.load_contents
|
74
|
+
end
|
75
|
+
|
76
|
+
def diff(item, value)
|
77
|
+
value
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class HashMerge < MergeDiff
|
82
|
+
register :hash_merge
|
83
|
+
|
84
|
+
def merge(item)
|
85
|
+
merge_stack(@stack.not_above(item).reverse)
|
86
|
+
end
|
87
|
+
|
88
|
+
def merge_stack(stack)
|
89
|
+
stack.inject({}) do |hash, item|
|
90
|
+
deep_merge(hash, item.load_contents)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def deep_merge(collect, item)
|
95
|
+
item.each_pair do |key, value|
|
96
|
+
case value
|
97
|
+
when Hash
|
98
|
+
collect[key] ||= {}
|
99
|
+
deep_merge(collect[key], value)
|
100
|
+
else
|
101
|
+
collect[key] = value
|
102
|
+
end
|
103
|
+
end
|
104
|
+
collect
|
105
|
+
end
|
106
|
+
|
107
|
+
def diff(item, new_contents)
|
108
|
+
diff_with = merge_stack(@stack.below(item).reverse)
|
109
|
+
result = new_contents.dup
|
110
|
+
|
111
|
+
diff_with.each_pair do |key, value|
|
112
|
+
if result.has_key?(key)
|
113
|
+
if result[key] == value
|
114
|
+
result.delete(key)
|
115
|
+
end
|
116
|
+
else
|
117
|
+
result[key] = nil
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
result
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
class Stack
|
127
|
+
include Unpath
|
128
|
+
include ItemEnum
|
129
|
+
|
130
|
+
def inspect
|
131
|
+
"<default>:#{@segments.join "/"} #{@valise.inspect}"
|
132
|
+
end
|
133
|
+
|
134
|
+
def initialize(path, set, merge_class, dump_load)
|
135
|
+
@segments = unpath(path)
|
136
|
+
@valise = set
|
137
|
+
@merge_diff = (merge_class || MergeDiff::TopMost).new(self)
|
138
|
+
@dump_load = dump_load
|
139
|
+
end
|
140
|
+
|
141
|
+
attr_reader :segments
|
142
|
+
|
143
|
+
def merged(item)
|
144
|
+
@merge_diff.merge(item)
|
145
|
+
end
|
146
|
+
|
147
|
+
def diffed(item, value)
|
148
|
+
@merge_diff.diff(item, value)
|
149
|
+
end
|
150
|
+
|
151
|
+
def not_above(item)
|
152
|
+
Stack.new(@segments, @valise.not_above(item.root), @merge_diff.class, @dump_load)
|
153
|
+
end
|
154
|
+
|
155
|
+
def below(item)
|
156
|
+
Stack.new(@segments, @valise.below(item.root), @merge_diff.class, @dump_load)
|
157
|
+
end
|
158
|
+
|
159
|
+
def each
|
160
|
+
@valise.each do |root|
|
161
|
+
yield(Item.new(self, root, @dump_load))
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def reverse
|
166
|
+
Stack.new(@segments, @valise.reverse, @merge_diff.class, @dump_load)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Valise
|
2
|
+
class StemDecorator < SearchRoot
|
3
|
+
def initialize(stem, search_root)
|
4
|
+
@stem, @search_root = stem, search_root
|
5
|
+
end
|
6
|
+
|
7
|
+
def under_stem(path)
|
8
|
+
segments = unpath(path)
|
9
|
+
top_part = segments[0...@stem.length]
|
10
|
+
if top_part == @stem
|
11
|
+
return segments[@stem.length..-1]
|
12
|
+
else
|
13
|
+
raise PathOutsideOfRoot
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def inspect
|
18
|
+
"#{self.class.name.split(":").last}:[#{@stem.join("/")}]#{@search_root.inspect}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def each
|
22
|
+
@search_root.each do |path|
|
23
|
+
yield(@stem + path)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def full_path(segments)
|
28
|
+
segments = under_stem(segments)
|
29
|
+
@search_root.full_path(segments)
|
30
|
+
end
|
31
|
+
|
32
|
+
def write(item)
|
33
|
+
@search_root.write(item)
|
34
|
+
end
|
35
|
+
|
36
|
+
def writable?(segments)
|
37
|
+
@search_root.writable?(under_stem(segments))
|
38
|
+
rescue PathOutsideOfRoot
|
39
|
+
return false
|
40
|
+
end
|
41
|
+
|
42
|
+
def present?(segments)
|
43
|
+
@search_root.present?(under_stem(segments))
|
44
|
+
rescue PathOutsideOfRoot
|
45
|
+
return false
|
46
|
+
end
|
47
|
+
|
48
|
+
def insert(item)
|
49
|
+
@search_root.insert(item)
|
50
|
+
end
|
51
|
+
|
52
|
+
def get_from(item)
|
53
|
+
@search_root.get_from(item)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/valise/utils.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
module Valise
|
2
|
+
module StringTools
|
3
|
+
def align(string)
|
4
|
+
lines = string.split(/\n/)
|
5
|
+
first = lines.shift
|
6
|
+
match = /^(\s*)<<</.match(first)
|
7
|
+
unless(match.nil?)
|
8
|
+
catch(:haircut) do
|
9
|
+
return lines.map do |line|
|
10
|
+
raise line if /^#{match[1]}|^\s*$/ !~ line
|
11
|
+
throw :haircut if /^#{match[1]}|^\s*$/ !~ line
|
12
|
+
line.sub(/^#{match[1]}/, "")
|
13
|
+
end.join("\n")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
return string
|
17
|
+
end
|
18
|
+
module_function :align
|
19
|
+
end
|
20
|
+
|
21
|
+
module Unpath
|
22
|
+
def unpath(parts)
|
23
|
+
if Array === parts and parts.length == 1
|
24
|
+
parts = parts[0]
|
25
|
+
end
|
26
|
+
|
27
|
+
case parts
|
28
|
+
when Array
|
29
|
+
if (parts.find{|part| not (String === part or Symbol === part)}.nil?)
|
30
|
+
parts = parts.map{|part| part.to_s}
|
31
|
+
else
|
32
|
+
raise "path must be composed of strings or symbols"
|
33
|
+
end
|
34
|
+
when String
|
35
|
+
parts = parts.split(::File::Separator)
|
36
|
+
when Symbol
|
37
|
+
parts = [parts.to_s]
|
38
|
+
when ::File
|
39
|
+
parts = parts.path
|
40
|
+
parts = parts.split(::File::Separator)
|
41
|
+
else
|
42
|
+
raise "path must be String, Array of Strings or File"
|
43
|
+
end
|
44
|
+
|
45
|
+
parts = parts.map do |part|
|
46
|
+
if /^~/ =~ part
|
47
|
+
::File::expand_path(part).split(::File::Separator)
|
48
|
+
else
|
49
|
+
part
|
50
|
+
end
|
51
|
+
end.flatten
|
52
|
+
|
53
|
+
return parts
|
54
|
+
end
|
55
|
+
|
56
|
+
def repath(segments)
|
57
|
+
case segments
|
58
|
+
when Array
|
59
|
+
return segments.join(::File::Separator)
|
60
|
+
when String
|
61
|
+
return segments
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/valise.rb
ADDED
@@ -0,0 +1,219 @@
|
|
1
|
+
require 'valise/errors'
|
2
|
+
require 'valise/search-root'
|
3
|
+
require 'valise/utils'
|
4
|
+
require 'valise/stack'
|
5
|
+
require 'valise/path-matcher'
|
6
|
+
require 'valise/stem-decorator'
|
7
|
+
|
8
|
+
module Valise
|
9
|
+
module Debugging
|
10
|
+
def remark
|
11
|
+
end
|
12
|
+
|
13
|
+
class << self
|
14
|
+
attr_reader :remark_to
|
15
|
+
|
16
|
+
def enable(destination)
|
17
|
+
@remark_to = destination
|
18
|
+
class_eval do
|
19
|
+
def remark
|
20
|
+
self.class.remark_to.puts(yield)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class Set
|
28
|
+
include Debugging
|
29
|
+
include Enumerable
|
30
|
+
|
31
|
+
class StemmedDefiner
|
32
|
+
include Unpath
|
33
|
+
def initialize(path, set)
|
34
|
+
@segments = unpath(path)
|
35
|
+
@target = set
|
36
|
+
end
|
37
|
+
|
38
|
+
def rw(name)
|
39
|
+
@target.add_search_root(
|
40
|
+
StemDecorator.new(@segments, SearchRoot.new(name)))
|
41
|
+
end
|
42
|
+
|
43
|
+
def ro(name)
|
44
|
+
@target.add_search_root(
|
45
|
+
StemDecorator.new(@segments, ReadOnlySearchRoot.new(name)))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Definer
|
50
|
+
include Unpath
|
51
|
+
def initialize(set)
|
52
|
+
@target = set
|
53
|
+
end
|
54
|
+
|
55
|
+
def rw(name, path = nil)
|
56
|
+
@target.add_search_root(SearchRoot.new(name))
|
57
|
+
end
|
58
|
+
|
59
|
+
def ro(name, path = nil)
|
60
|
+
@target.add_search_root(ReadOnlySearchRoot.new(name))
|
61
|
+
end
|
62
|
+
|
63
|
+
def stemmed(path, &block)
|
64
|
+
definer = StemmedDefiner.new(path, @target)
|
65
|
+
definer.instance_eval(&block) unless block.nil?
|
66
|
+
return definer
|
67
|
+
end
|
68
|
+
|
69
|
+
def from_here(rel_path)
|
70
|
+
m = /(.*):\d+/.match(caller[0])
|
71
|
+
dir = ::File::dirname(::File::expand_path(m[1]))
|
72
|
+
|
73
|
+
unpath(dir) + unpath(rel_path)
|
74
|
+
end
|
75
|
+
|
76
|
+
def handle(path, serialization, merge_diff = nil)
|
77
|
+
@target.add_handler(unpath(path),
|
78
|
+
Valise::Serialization[serialization],
|
79
|
+
Valise::MergeDiff[merge_diff])
|
80
|
+
end
|
81
|
+
|
82
|
+
def defaults(name=nil, &block)
|
83
|
+
loc = DefinedDefaults.define(&block)
|
84
|
+
@target.add_search_root(loc)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def initialize
|
89
|
+
@search_roots = []
|
90
|
+
@merge_diff = PathMatcher.new
|
91
|
+
@serialization = PathMatcher.new
|
92
|
+
end
|
93
|
+
|
94
|
+
def inspect
|
95
|
+
@search_roots.inspect
|
96
|
+
end
|
97
|
+
|
98
|
+
def reverse
|
99
|
+
set = Set.new
|
100
|
+
set.search_roots = @search_roots.reverse
|
101
|
+
set
|
102
|
+
end
|
103
|
+
|
104
|
+
def define(&block)
|
105
|
+
definer = Definer.new(self)
|
106
|
+
definer.instance_eval(&block)
|
107
|
+
return self
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.define(&block)
|
111
|
+
return self.new.define(&block)
|
112
|
+
end
|
113
|
+
|
114
|
+
def prepend_search_root(search_root)
|
115
|
+
@search_roots.unshift(search_root)
|
116
|
+
end
|
117
|
+
|
118
|
+
def add_search_root(search_root)
|
119
|
+
@search_roots << search_root
|
120
|
+
end
|
121
|
+
|
122
|
+
def add_handler(segments, serialization_class, merge_diff_class)
|
123
|
+
@merge_diff[segments] = merge_diff_class unless merge_diff_class.nil?
|
124
|
+
@serialization[segments] = serialization_class unless serialization_class.nil?
|
125
|
+
end
|
126
|
+
|
127
|
+
def +(other)
|
128
|
+
result = self.class.new
|
129
|
+
result.search_roots = @search_roots + other.search_roots
|
130
|
+
result.merge_handlers(*other.handler_lists)
|
131
|
+
result.merge_handlers(*handler_lists)
|
132
|
+
return result
|
133
|
+
end
|
134
|
+
|
135
|
+
attr_accessor :search_roots
|
136
|
+
protected :search_roots, :search_roots=
|
137
|
+
|
138
|
+
include Unpath
|
139
|
+
def get(path)
|
140
|
+
return Stack.new(path, self,
|
141
|
+
merge_diff(path),
|
142
|
+
serialization(path))
|
143
|
+
end
|
144
|
+
|
145
|
+
def merge_diff(path)
|
146
|
+
@merge_diff[unpath(path)]
|
147
|
+
end
|
148
|
+
|
149
|
+
def serialization(path)
|
150
|
+
@serialization[unpath(path)]
|
151
|
+
end
|
152
|
+
|
153
|
+
def merge_handlers(merge_diff, serialization)
|
154
|
+
@merge_diff.merge!(merge_diff)
|
155
|
+
@serialization.merge!(serialization)
|
156
|
+
end
|
157
|
+
|
158
|
+
def handler_lists
|
159
|
+
[@merge_diff, @serialization]
|
160
|
+
end
|
161
|
+
|
162
|
+
def find(path)
|
163
|
+
return get(path).present.first
|
164
|
+
end
|
165
|
+
|
166
|
+
def each(&block)
|
167
|
+
@search_roots.each(&block)
|
168
|
+
end
|
169
|
+
|
170
|
+
def files
|
171
|
+
unless block_given?
|
172
|
+
return self.enum_for(:files)
|
173
|
+
end
|
174
|
+
|
175
|
+
visited = {}
|
176
|
+
@search_roots.each do |root|
|
177
|
+
root.each do |segments|
|
178
|
+
unless visited.has_key?(segments)
|
179
|
+
item = find(segments)
|
180
|
+
visited[segments] = item
|
181
|
+
yield(item)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
return visited
|
186
|
+
end
|
187
|
+
|
188
|
+
def not_above(root)
|
189
|
+
index = @search_roots.index(root)
|
190
|
+
raise RootNotInSet if index.nil?
|
191
|
+
set = self.class.new
|
192
|
+
set.search_roots = @search_roots[index..-1]
|
193
|
+
set
|
194
|
+
end
|
195
|
+
|
196
|
+
def below(root)
|
197
|
+
index = @search_roots.index(root)
|
198
|
+
raise RootNotInSet if index.nil?
|
199
|
+
set = self.class.new
|
200
|
+
set.search_roots = @search_roots[(index+1)..-1]
|
201
|
+
set
|
202
|
+
end
|
203
|
+
|
204
|
+
def [](index)
|
205
|
+
return @search_roots[index]
|
206
|
+
end
|
207
|
+
|
208
|
+
def populate(to = self)
|
209
|
+
files do |item|
|
210
|
+
contents = item.contents
|
211
|
+
to_stack = to.get(item.segments)
|
212
|
+
to_stack = yield(to_stack) if block_given?
|
213
|
+
target = to_stack.writable.first
|
214
|
+
next if target.present?
|
215
|
+
target.contents = contents
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
data/spec/addable.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'valise'
|
2
|
+
require 'file-sandbox'
|
3
|
+
|
4
|
+
describe Valise do
|
5
|
+
include FileSandbox
|
6
|
+
|
7
|
+
before do
|
8
|
+
sandbox.new :directory => "etc/conductor"
|
9
|
+
sandbox.new :directory => "home/.conductor"
|
10
|
+
sandbox.new :directory => ".conductor"
|
11
|
+
sandbox.new :directory => "spec"
|
12
|
+
sandbox.new :file => "home/.conductor/existed", :with_contents => "TEST"
|
13
|
+
one = Valise::Set.define do
|
14
|
+
handle "test", :yaml
|
15
|
+
rw ".conductor"
|
16
|
+
end
|
17
|
+
|
18
|
+
two = Valise::Set.define do
|
19
|
+
handle "test", nil, :hash_merge
|
20
|
+
defaults do
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
@sum = one + two
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
it "should be addable" do
|
29
|
+
@sum.should be_an_instance_of(Valise::Set)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should add in order" do
|
33
|
+
@sum[0].should be_an_instance_of(Valise::SearchRoot)
|
34
|
+
@sum[1].should be_an_instance_of(Valise::DefinedDefaults)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should combine file handlers" do
|
38
|
+
@sum.merge_diff("test").should == Valise::MergeDiff::HashMerge
|
39
|
+
@sum.serialization("test").should == Valise::Serialization::YAML
|
40
|
+
end
|
41
|
+
end
|