sugar-high 0.4.0 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. data/VERSION +1 -1
  2. data/lib/sugar-high/array.rb +58 -7
  3. data/lib/sugar-high/class_ext.rb +11 -0
  4. data/lib/sugar-high/enumerable.rb +67 -0
  5. data/lib/sugar-high/file.rb +24 -76
  6. data/lib/sugar-high/file_ext.rb +65 -0
  7. data/lib/sugar-high/file_mutate.rb +45 -192
  8. data/lib/sugar-high/file_mutate/append_content.rb +17 -0
  9. data/lib/sugar-high/file_mutate/delete.rb +29 -0
  10. data/lib/sugar-high/file_mutate/insert_content.rb +62 -0
  11. data/lib/sugar-high/file_mutate/mutate.rb +58 -0
  12. data/lib/sugar-high/file_mutate/overwrite_content.rb +17 -0
  13. data/lib/sugar-high/file_mutate/remove_content.rb +33 -0
  14. data/lib/sugar-high/file_mutate/replace_content.rb +45 -0
  15. data/lib/sugar-high/kind_of.rb +8 -43
  16. data/lib/sugar-high/string.rb +5 -0
  17. data/spec/fixtures/application_file.rb +1 -0
  18. data/spec/fixtures/class_file.rb +15 -0
  19. data/spec/fixtures/content_file.txt +1 -0
  20. data/spec/fixtures/file.txt +1 -0
  21. data/spec/fixtures/routes_file.rb +16 -0
  22. data/spec/sugar-high/array_spec.rb +44 -3
  23. data/spec/sugar-high/file/file_dsl_spec.rb +4 -0
  24. data/spec/sugar-high/file_mutate/append_content_spec.rb +60 -0
  25. data/spec/sugar-high/file_mutate/delete_spec.rb +47 -0
  26. data/spec/sugar-high/file_mutate/insert_before_last_spec.rb +56 -0
  27. data/spec/sugar-high/file_mutate/insert_content_spec.rb +111 -0
  28. data/spec/sugar-high/file_mutate/overwrite_content_spec.rb +80 -0
  29. data/spec/sugar-high/file_mutate/remove_content_spec.rb +109 -0
  30. data/spec/sugar-high/file_mutate/replace_content_spec.rb +33 -0
  31. data/spec/sugar-high/{file/file_spec.rb → file_spec.rb} +1 -0
  32. data/sugar-high.gemspec +26 -27
  33. metadata +27 -28
  34. data/spec/sugar-high/file/file_mutate_spec.rb +0 -325
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.0
1
+ 0.4.3
@@ -1,26 +1,56 @@
1
1
  require 'sugar-high/kind_of'
2
+ require 'sugar-high/enumerable'
2
3
  require 'sugar-high/path'
3
4
 
4
5
  class Array
5
- def to_symbols option=nil
6
- res = self.flatten
7
- res.map!{|a| a.kind_of?(Fixnum) ? "_#{a}" : a} if option == :num
8
- res.select_labels.map(&:to_s).map(&:to_sym)
6
+ def to_symbols
7
+ self.flatten.select_labels.map{|a| a.to_s.to_sym }
9
8
  end
10
9
 
10
+ def to_symbols!
11
+ self.flatten!.select_labels!.map!{|a| a.to_s.to_sym }
12
+ end
13
+
14
+ def to_symbols_num
15
+ self.flatten.map{|a| a.kind_of?(Fixnum) ? "_#{a}" : a}.map{|a| a.to_s.to_sym }
16
+ end
17
+
18
+ def to_symbols_num!
19
+ self.flatten!.map!{|a| a.kind_of?(Fixnum) ? "_#{a}" : a}..map!{|a| a.to_s.to_sym }
20
+ end
21
+
22
+ def to_symbols_uniq
23
+ to_symbols.uniq
24
+ end
25
+
26
+ def to_symbols_uniq!
27
+ to_symbols!.uniq!
28
+ end
29
+
11
30
  def to_strings
12
- self.flatten.select_labels.map(&:to_s)
31
+ self.flatten!.select_labels!.map!(&:to_s)
32
+ end
33
+
34
+ def to_strings!
35
+ self.flatten.select_labels!.map!(&:to_s)
13
36
  end
14
37
 
15
38
  def to_filenames
16
39
  self.to_strings.map(&:underscore)
17
40
  end
18
41
 
42
+ def to_filenames!
43
+ self.to_strings!.map!(&:underscore)
44
+ end
19
45
 
20
46
  def to_paths
21
47
  self.map(&:path)
22
48
  end
23
49
 
50
+ def to_paths!
51
+ self.map!(&:path)
52
+ end
53
+
24
54
  def file_join
25
55
  File.join(*self.flatten)
26
56
  end
@@ -29,14 +59,35 @@ class Array
29
59
  self.map{|fp| fp.path.to_file }
30
60
  self.extend FilesArray
31
61
  end
62
+
63
+ def to_files!
64
+ self.map!{|fp| fp.path.to_file }
65
+ self.extend FilesArray
66
+ end
32
67
 
33
68
  def none?
34
69
  self.flatten.compact.empty?
35
70
  end
36
71
 
37
- def flat_uniq
72
+ def flat_uniq
38
73
  self.flatten.compact.uniq
39
- end
74
+ end
75
+
76
+ def flat_uniq!
77
+ self.flatten!.compact!.uniq!
78
+ end
79
+
80
+ def extract(sym)
81
+ map { |e| e.send(sym) }
82
+ end
83
+
84
+ def sum
85
+ inject( 0 ) { |sum,x| sum + x }
86
+ end
87
+
88
+ def mean
89
+ (size > 0) ? sum.to_f / size : 0
90
+ end
40
91
  end
41
92
 
42
93
  module FilesArray
@@ -0,0 +1,11 @@
1
+ class Class
2
+ def include_and_extend(the_module, options={})
3
+ options[:instance_methods] ||= :InstanceMethods
4
+ options[:class_methods] ||= :ClassMethods
5
+ # Mainly include but be flexible
6
+ main_module = const_get(the_module)
7
+ include main_module # for an extend_and_include method, change this to extend main_module
8
+ include main_module.const_get(options[:instance_methods]) if main_module.const_defined?(options[:instance_methods])
9
+ extend main_module.const_get(options[:class_methods]) if main_module.const_defined?(options[:class_methods])
10
+ end
11
+ end
@@ -0,0 +1,67 @@
1
+ module Enumerable
2
+ def only_kinds_of? *kinds
3
+ all?{|a| a.any_kind_of? *kinds }
4
+ end
5
+
6
+ def only_labels?
7
+ all?{|a| a.kind_of_label? }
8
+ end
9
+
10
+ def select_kinds_of *kinds
11
+ select{|a| a.any_kind_of? *kinds }
12
+ end
13
+
14
+ def select_kinds_of! *kinds
15
+ select!{|a| a.any_kind_of? *kinds }
16
+ end
17
+
18
+ def select_labels
19
+ select{|a| a.kind_of_label? }
20
+ end
21
+
22
+ def select_labels!
23
+ select! {|a| a.kind_of_label? }
24
+ end
25
+
26
+
27
+ def select_symbols
28
+ select_only :symbol
29
+ end
30
+
31
+ def select_symbols!
32
+ select_only! :symbol
33
+ end
34
+
35
+ def select_uniq_symbols!
36
+ select_only!(:symbol).uniq!
37
+ end
38
+
39
+ def select_strings
40
+ select_only :string
41
+ end
42
+
43
+ def select_strings
44
+ select_only :string
45
+ end
46
+
47
+ def select_only type
48
+ const = type.kind_of_label? ? "#{type.to_s.camelize}".constantize : type
49
+ select{|a| a.kind_of? const}
50
+ end
51
+
52
+ def select_only! type
53
+ const = type.kind_of_label? ? "#{type.to_s.camelize}".constantize : type
54
+ select!{|a| a.kind_of? const}
55
+ end
56
+
57
+ def all_kinds
58
+ map do |a|
59
+ case a
60
+ when Kinds
61
+ a.kinds
62
+ else
63
+ a if a.kind_of?(Module)
64
+ end
65
+ end.compact.uniq.flatten
66
+ end
67
+ end
@@ -4,67 +4,36 @@ require 'sugar-high/path'
4
4
  require 'sugar-high/regexp'
5
5
  require 'sugar-high/string'
6
6
  require 'sugar-high/file_mutate'
7
+ require 'sugar-high/file_ext'
7
8
 
8
9
  class File
9
- def self.blank? file_name
10
- raise ArgumentError, "Filename argument must not be blank" if file_name.blank?
11
- raise ArgumentError, "There is no file at: #{file_name}" if !File.file?(file_name)
12
- File.zero?(file_name)
13
- end
14
-
15
- def blank?
16
- File.zero?(self.path)
17
- end
10
+ include SugarHigh::FileExt
11
+ extend SugarHigh::FileExt::ClassMethods
12
+ end
18
13
 
19
- def self.has_content? file_name, content_matcher, &block
20
- File.new(file_name).has_content? content_matcher, &block
14
+ class Symbol
15
+ def as_filename
16
+ self.to_s.underscore
21
17
  end
22
-
23
- def has_content? content_matcher = nil, &block
24
- content_matcher ||= yield
25
- begin
26
- content_matcher = content_matcher.to_regexp
27
- rescue
28
- raise ArgumentError, "Content match must be specified as either a String or Regexp"
29
- end
30
- !(self.read =~ content_matcher).nil?
18
+
19
+ def valid_file_command?
20
+ [:read, :remove, :delete].include? self
31
21
  end
22
+
23
+ def file
24
+ as_filename.file
25
+ end
26
+ end
32
27
 
33
- def read_content options = {}, &block
34
- File.read_from self.path, options, &block
28
+ class NilClass
29
+ def valid_file_command?
30
+ false
35
31
  end
36
- alias_method :with_content, :read_content
37
-
38
- class << self
39
-
40
- def read_from file_name, options = {}, &block
41
- raise ArgumentError, "File to read from not found or not a file: #{file_name}" if !File.file? file_name
42
- content = File.read file_name
43
-
44
- if options[:before]
45
- begin
46
- regexp = options[:before].to_regexp
47
- index = content.match(regexp).offset_before
48
- content = content[0..index]
49
- rescue
50
- raise ArgumentError, ":before option must be a string or regular expression, was : #{options[:before]}"
51
- end
52
- end
32
+ end
53
33
 
54
- if options[:after]
55
- begin
56
- regexp = options[:after].to_regexp
57
- index = content.match(regexp).offset_after
58
- content = content[index..-1]
59
- rescue
60
- raise ArgumentError, ":after option must be a string or regular expression, was : #{options[:after]}"
61
- end
62
- end
63
- yield content if block
64
- content
65
- end
66
- alias_method :read_content_from, :read_from
67
- alias_method :with_content_from, :read_from
34
+ class Array
35
+ def file_names ext = '*'
36
+ self.map{|a| a.gsub( /(.*)\//, '').gsub(/\.#{Regexp.escape(ext.to_s)}/, '')}
68
37
  end
69
38
  end
70
39
 
@@ -72,7 +41,7 @@ class String
72
41
  def as_filename
73
42
  self.underscore
74
43
  end
75
-
44
+
76
45
  def valid_file_command?
77
46
  self.to_sym.valid_file_command?
78
47
  end
@@ -86,7 +55,7 @@ class String
86
55
  return ::Dir.new(self) if ::File.directory?(self)
87
56
  raise "No file found at #{self}"
88
57
  end
89
-
58
+
90
59
  def new_file
91
60
  begin
92
61
  file
@@ -96,24 +65,3 @@ class String
96
65
  end
97
66
  end
98
67
 
99
- class Symbol
100
- def as_filename
101
- self.to_s.underscore
102
- end
103
-
104
- def valid_file_command?
105
- [:read, :remove, :delete].include? self
106
- end
107
- end
108
-
109
- class NilClass
110
- def valid_file_command?
111
- false
112
- end
113
- end
114
-
115
- class Array
116
- def file_names ext = '*'
117
- self.map{|a| a.gsub( /(.*)\//, '').gsub(/\.#{Regexp.escape(ext.to_s)}/, '')}
118
- end
119
- end
@@ -0,0 +1,65 @@
1
+ module SugarHigh
2
+ module FileExt
3
+ module ClassMethods
4
+ def blank? file_name
5
+ raise ArgumentError, "Filename argument must not be blank" if file_name.blank?
6
+ raise ArgumentError, "There is no file at: #{file_name}" if !File.file?(file_name)
7
+ File.zero?(file_name)
8
+ end
9
+
10
+ def has_content? file_name, content_matcher, &block
11
+ file = get_file file_name
12
+ file.has_content? content_matcher, &block
13
+ end
14
+
15
+ def read_from file_name, options = {}, &block
16
+ raise ArgumentError, "File to read from not found or not a file: #{file_name}" if !File.file? file_name
17
+ content = File.read file_name
18
+
19
+ if options[:before]
20
+ begin
21
+ regexp = options[:before].to_regexp
22
+ index = content.match(regexp).offset_before
23
+ content = content[0..index]
24
+ rescue
25
+ raise ArgumentError, ":before option must be a string or regular expression, was : #{options[:before]}"
26
+ end
27
+ end
28
+
29
+ if options[:after]
30
+ begin
31
+ regexp = options[:after].to_regexp
32
+ index = content.match(regexp).offset_after
33
+ content = content[index..-1]
34
+ rescue
35
+ raise ArgumentError, ":after option must be a string or regular expression, was : #{options[:after]}"
36
+ end
37
+ end
38
+ yield content if block
39
+ content
40
+ end
41
+ alias_method :read_content_from, :read_from
42
+ alias_method :with_content_from, :read_from
43
+ end
44
+
45
+ def blank?
46
+ File.zero?(self.path)
47
+ end
48
+
49
+ def has_content? content_matcher = nil, &block
50
+ content_matcher ||= yield
51
+ begin
52
+ content_matcher = content_matcher.to_regexp
53
+ rescue
54
+ raise ArgumentError, "Content match must be specified as either a String or Regexp"
55
+ end
56
+ matched = self.read_content =~ content_matcher
57
+ !(matched).nil?
58
+ end
59
+
60
+ def read_content options = {}, &block
61
+ File.read_from self.path, options, &block
62
+ end
63
+ alias_method :with_content, :read_content
64
+ end
65
+ end
@@ -4,203 +4,56 @@ require 'sugar-high/path'
4
4
  require 'sugar-high/regexp'
5
5
  require 'sugar-high/string'
6
6
  require 'sugar-high/file'
7
-
8
- class File
9
- class << self
10
- def delete! name
11
- return nil if !File.exist?(name)
12
- File.delete name
7
+ require 'sugar-high/array'
8
+
9
+ require 'sugar-high/file_mutate/delete'
10
+ require 'sugar-high/file_mutate/overwrite_content'
11
+ require 'sugar-high/file_mutate/append_content'
12
+ require 'sugar-high/file_mutate/remove_content'
13
+ require 'sugar-high/file_mutate/replace_content'
14
+ require 'sugar-high/file_mutate/insert_content'
15
+ require 'sugar-high/file_mutate/extras'
16
+
17
+ require 'sugar-high/class_ext'
18
+ require 'active_support/inflector'
19
+
20
+ module SugarHigh
21
+ module FileMutate
22
+ autoload :Mutate, 'sugar-high/file_mutate/mutate'
23
+ autoload :Delete, 'sugar-high/file_mutate/delete'
24
+ autoload :AppendContent, 'sugar-high/file_mutate/append_content'
25
+ autoload :InsertContent, 'sugar-high/file_mutate/insert_content'
26
+ autoload :OverwriteContent, 'sugar-high/file_mutate/overwrite_content'
27
+ autoload :RemoveContent, 'sugar-high/file_mutate/remove_content'
28
+ autoload :ReplaceContent, 'sugar-high/file_mutate/replace_content'
29
+ end
30
+ end
31
+
32
+
33
+ class File
34
+ def self.mutate_ext name
35
+ if name == :all
36
+ add_mutate_exts mutate_apis
37
+ return
13
38
  end
14
- alias_method :delete_file!, :delete!
15
- end
16
-
17
- def delete!
18
- File.delete(self.path)
39
+ raise ArgumentError, "Unknown FileMutate API: #{name}, must be one of: #{mutate_apis}" if !mutate_apis.include? name
40
+ add_mutate_exts [:mutate, name]
19
41
  end
20
- alias_method :delete_file!, :delete!
21
42
 
43
+ protected
22
44
 
23
- def overwrite content=nil, &block
24
- File.overwrite self.path, content, &block
25
- end
26
-
27
- def self.overwrite file, content=nil, &block
28
- filepath = case file
29
- when PathString, String
30
- file
31
- when File
32
- file.path
33
- else
34
- raise ArgumentError, "Expected first argument to be a File instance or a path indicating file to overwrite"
35
- end
36
- File.open(filepath, 'w') do |f|
37
- f.puts content ||= yield
38
- end
39
- end
40
-
41
- def append content=nil, &block
42
- File.append self.path, content, &block
43
- end
44
-
45
- def self.append path, content=nil, &block
46
- File.open(path, 'a') do |f|
47
- f.puts content ||= yield
48
- end
49
- end
50
-
51
- def remove_content options=nil, &block
52
- opt_str = case options
53
- when String
54
- options
55
- when Hash
56
- content = options[:content] || options[:where]
57
- raise ArgumentError, "Bad :content value in Hash" if !content || content.strip.empty?
58
- content.strip
59
- else
60
- raise ArgumentError, "non-block argument must be either String or Hash with a :content option" if !block
61
- end
62
- content = block ? yield : opt_str
63
- File.remove_content_from self.path, :content => content, :with => '', &block
64
- end
65
- alias_method :remove, :remove_content
66
-
67
- def self.remove_from file_name, content=nil, &block
68
- content ||= yield
69
- replace_content_from file_name, :content => content, :with => '', &block
70
- end
71
-
72
- def self.remove_content_from file_name, options = {}, &block
73
- replace_content_from file_name, options.merge(:with => ''), &block
74
- end
75
-
76
- def replace_content options = {}, &block
77
- File.replace_content_from self.path, options, &block
78
- end
79
-
80
- # replaces content found at replacement_expr with content resulting from yielding block
81
- # File.replace_content_from 'myfile.txt', where => /HelloWorld/, with => 'GoodBye'
82
- def self.replace_content_from file_name, options = {}, &block
83
- replacement_expr = options[:where] || options[:content]
84
- new_content = options[:with]
85
-
86
- begin
87
- replacement_expr = replacement_expr.to_regexp
88
- rescue
89
- raise ArgumentError, "Content to be replaced must be specified as either a String or Regexp in a :where or :content option"
90
- end
91
-
92
- # get existing file content
93
- content = File.read file_name
94
-
95
- # return nil if no mathing replacement found
96
- return nil if !(content =~ replacement_expr)
97
-
98
- new_content ||= yield if block
99
-
100
- raise ArgumentError, "Content to be replaced with must be specified as a :with option or as a block" if !new_content
101
-
102
- # remove content that matches expr, by replacing with empty
103
- mutated_content = content.gsub replacement_expr, new_content
104
-
105
- # write mutated content as new file
106
- File.overwrite file_name, mutated_content
107
-
108
- true # signal success!
109
- end
110
-
111
- def insert *args, &block
112
- File.insert_into self.path, *args, &block
113
- end
45
+ def self.mutate_apis
46
+ [:delete, :mutate, :append_content, :insert_content, :overwrite_content, :remove_content, :replace_content]
47
+ end
114
48
 
115
- # insert_into 'my_file.txt', :after => 'Blip', :content => 'Hello
116
- # insert_into 'my_file.txt', 'Hello', :after => 'Blip'
117
- # insert_into 'my_file.txt', :after => 'Blip' do
118
- # 'Hello'
119
- # end
120
- def self.insert_into file_name, *args, &block
121
- options = last_option args
122
- content = Insert.content options, *args, &block
123
-
124
- file = File.new(file_name)
125
- return nil if !File.exist?(file)
126
-
127
- # already inserted?
128
- return nil if content.blank?
129
- return nil if !options[:repeat] && (file.read =~ /#{Regexp.escape(content.to_s)}/)
130
-
131
- place, marker = if options[:before]
132
- [ :before, options[:before] ]
133
- elsif options[:before_last]
134
- [ :before_last, options[:before_last] ]
135
- else
136
- [ :after, options[:after] ]
137
- end
138
-
139
- marker = Insert.get_marker marker
140
- marker_found = (File.new(file.path).read =~ /#{marker}/)
141
- return nil if !marker_found
142
-
143
- res = Mutate.mutate_file file.path, marker, place do
144
- content
49
+ def self.add_mutate_exts *names
50
+ names.flat_uniq.each do |api|
51
+ ns = "SugarHigh::FileMutate::#{api.to_s.camelize}"
52
+ begin
53
+ self.send :include, ns.constantize
54
+ self.extend "#{ns}::ClassMethods".constantize
55
+ end
145
56
  end
146
- res
147
- end
148
-
149
- module EscapedString
150
- def escaped?
151
- true
152
- end
153
- end
154
-
155
- module Insert
156
- def self.get_marker marker
157
- return marker if marker.respond_to?(:escaped?) && marker.escaped?
158
- marker = case marker
159
- when Regexp
160
- marker
161
- when String
162
- Regexp.escape(marker).extend(EscapedString)
163
- end
164
- end
165
-
166
- def self.content options = {}, *args, &block
167
- case args.first
168
- when String
169
- args.first
170
- when Hash
171
- options[:content] || (yield if block)
172
- else
173
- return yield if block
174
- raise ArgumentError, "You must supply content to insert, either as a String before the options hash, a :content option or a block"
175
- end
176
- end
177
- end
178
-
179
- module Mutate
180
- def self.mutate_file file, marker, place, &block
181
- raise ArgumentError, "You must define a replacement marker for a :before, :before_last or :after key" if !marker
182
-
183
- if place == :before_last
184
- content = File.read(file)
185
- content = content.insert_before_last yield, marker
186
- File.open(file, 'wb') { |file| file.write(content) }
187
- return
188
- end
189
-
190
- marker = Insert.get_marker marker
191
-
192
- marker_found = (File.new(file.path).read =~ /#{marker}/)
193
- return nil if !marker_found
194
-
195
- replace_in_file file, /(#{marker})/mi do |match|
196
- place == :after ? "#{match}\n #{yield}" : "#{yield}\n #{match}"
197
- end
198
- true
199
- end
200
-
201
- def self.replace_in_file(path, regexp, *args, &block)
202
- content = File.read(path).gsub(regexp, *args, &block)
203
- File.open(path, 'wb') { |file| file.write(content) }
204
- end
205
57
  end
58
+
206
59
  end