valise 0.3

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.
Files changed (87) hide show
  1. data/doc/README +69 -0
  2. data/doc/Specification +72 -0
  3. data/doc/Specifications +81 -0
  4. data/doc/coverage/assets/0.5.3/app.js +88 -0
  5. data/doc/coverage/assets/0.5.3/fancybox/blank.gif +0 -0
  6. data/doc/coverage/assets/0.5.3/fancybox/fancy_close.png +0 -0
  7. data/doc/coverage/assets/0.5.3/fancybox/fancy_loading.png +0 -0
  8. data/doc/coverage/assets/0.5.3/fancybox/fancy_nav_left.png +0 -0
  9. data/doc/coverage/assets/0.5.3/fancybox/fancy_nav_right.png +0 -0
  10. data/doc/coverage/assets/0.5.3/fancybox/fancy_shadow_e.png +0 -0
  11. data/doc/coverage/assets/0.5.3/fancybox/fancy_shadow_n.png +0 -0
  12. data/doc/coverage/assets/0.5.3/fancybox/fancy_shadow_ne.png +0 -0
  13. data/doc/coverage/assets/0.5.3/fancybox/fancy_shadow_nw.png +0 -0
  14. data/doc/coverage/assets/0.5.3/fancybox/fancy_shadow_s.png +0 -0
  15. data/doc/coverage/assets/0.5.3/fancybox/fancy_shadow_se.png +0 -0
  16. data/doc/coverage/assets/0.5.3/fancybox/fancy_shadow_sw.png +0 -0
  17. data/doc/coverage/assets/0.5.3/fancybox/fancy_shadow_w.png +0 -0
  18. data/doc/coverage/assets/0.5.3/fancybox/fancy_title_left.png +0 -0
  19. data/doc/coverage/assets/0.5.3/fancybox/fancy_title_main.png +0 -0
  20. data/doc/coverage/assets/0.5.3/fancybox/fancy_title_over.png +0 -0
  21. data/doc/coverage/assets/0.5.3/fancybox/fancy_title_right.png +0 -0
  22. data/doc/coverage/assets/0.5.3/fancybox/fancybox-x.png +0 -0
  23. data/doc/coverage/assets/0.5.3/fancybox/fancybox-y.png +0 -0
  24. data/doc/coverage/assets/0.5.3/fancybox/fancybox.png +0 -0
  25. data/doc/coverage/assets/0.5.3/fancybox/jquery.fancybox-1.3.1.css +363 -0
  26. data/doc/coverage/assets/0.5.3/fancybox/jquery.fancybox-1.3.1.pack.js +44 -0
  27. data/doc/coverage/assets/0.5.3/favicon_green.png +0 -0
  28. data/doc/coverage/assets/0.5.3/favicon_red.png +0 -0
  29. data/doc/coverage/assets/0.5.3/favicon_yellow.png +0 -0
  30. data/doc/coverage/assets/0.5.3/highlight.css +129 -0
  31. data/doc/coverage/assets/0.5.3/highlight.pack.js +1 -0
  32. data/doc/coverage/assets/0.5.3/jquery-1.6.2.min.js +18 -0
  33. data/doc/coverage/assets/0.5.3/jquery.dataTables.min.js +152 -0
  34. data/doc/coverage/assets/0.5.3/jquery.timeago.js +141 -0
  35. data/doc/coverage/assets/0.5.3/jquery.url.js +174 -0
  36. data/doc/coverage/assets/0.5.3/loading.gif +0 -0
  37. data/doc/coverage/assets/0.5.3/magnify.png +0 -0
  38. data/doc/coverage/assets/0.5.3/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  39. data/doc/coverage/assets/0.5.3/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  40. data/doc/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  41. data/doc/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  42. data/doc/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  43. data/doc/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  44. data/doc/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  45. data/doc/coverage/assets/0.5.3/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  46. data/doc/coverage/assets/0.5.3/smoothness/images/ui-icons_222222_256x240.png +0 -0
  47. data/doc/coverage/assets/0.5.3/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  48. data/doc/coverage/assets/0.5.3/smoothness/images/ui-icons_454545_256x240.png +0 -0
  49. data/doc/coverage/assets/0.5.3/smoothness/images/ui-icons_888888_256x240.png +0 -0
  50. data/doc/coverage/assets/0.5.3/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  51. data/doc/coverage/assets/0.5.3/smoothness/jquery-ui-1.8.4.custom.css +295 -0
  52. data/doc/coverage/assets/0.5.3/stylesheet.css +383 -0
  53. data/doc/coverage/index.html +5843 -0
  54. data/doc/coverage/jquery-1.3.2.min.js +19 -0
  55. data/doc/coverage/jquery.tablesorter.min.js +15 -0
  56. data/doc/coverage/lib-fileset-errors_rb.html +231 -0
  57. data/doc/coverage/lib-fileset-item_rb.html +303 -0
  58. data/doc/coverage/lib-fileset-populator_rb.html +249 -0
  59. data/doc/coverage/lib-fileset-search-root_rb.html +1053 -0
  60. data/doc/coverage/lib-fileset-utils_rb.html +453 -0
  61. data/doc/coverage/lib-fileset_rb.html +789 -0
  62. data/doc/coverage/print.css +12 -0
  63. data/doc/coverage/rcov.js +42 -0
  64. data/doc/coverage/screen.css +270 -0
  65. data/lib/valise/errors.rb +30 -0
  66. data/lib/valise/item.rb +105 -0
  67. data/lib/valise/path-matcher.rb +113 -0
  68. data/lib/valise/search-root.rb +166 -0
  69. data/lib/valise/stack.rb +169 -0
  70. data/lib/valise/stem-decorator.rb +56 -0
  71. data/lib/valise/utils.rb +65 -0
  72. data/lib/valise.rb +219 -0
  73. data/spec/addable.rb +41 -0
  74. data/spec/dump_load.rb +32 -0
  75. data/spec/error_handling.rb +9 -0
  76. data/spec/fileset.rb +170 -0
  77. data/spec/glob_handling.rb +28 -0
  78. data/spec/item.rb +35 -0
  79. data/spec/merge_diff.rb +93 -0
  80. data/spec/population.rb +51 -0
  81. data/spec/search_root.rb +24 -0
  82. data/spec/stemming.rb +33 -0
  83. data/spec_help/file-sandbox.rb +164 -0
  84. data/spec_help/gem_test_suite.rb +17 -0
  85. data/spec_help/spec_helper.rb +3 -0
  86. data/spec_help/ungemmer.rb +37 -0
  87. 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
@@ -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
@@ -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