rubycut-babushka 0.10.6

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 (171) hide show
  1. data/Gemfile +8 -0
  2. data/Gemfile.lock +31 -0
  3. data/README.markdown +246 -0
  4. data/Rakefile +26 -0
  5. data/bin/babushka +11 -0
  6. data/deps/babushka.rb +101 -0
  7. data/deps/dev.rb +12 -0
  8. data/deps/fhs.rb +31 -0
  9. data/deps/git.rb +29 -0
  10. data/deps/homebrew.rb +30 -0
  11. data/deps/os_x.rb +33 -0
  12. data/deps/packages.rb +22 -0
  13. data/deps/pkg_managers.rb +110 -0
  14. data/deps/ruby.rb +23 -0
  15. data/deps/rubygems.rb +24 -0
  16. data/deps/system.rb +10 -0
  17. data/deps/templates/app.rb +68 -0
  18. data/deps/templates/external.rb +12 -0
  19. data/deps/templates/installer.rb +31 -0
  20. data/deps/templates/managed.rb +105 -0
  21. data/deps/templates/ppa.rb +24 -0
  22. data/deps/templates/src.rb +42 -0
  23. data/deps/templates/tmbundle.rb +15 -0
  24. data/lib/babushka.rb +28 -0
  25. data/lib/babushka/accepts_block_for.rb +72 -0
  26. data/lib/babushka/accepts_list_for.rb +49 -0
  27. data/lib/babushka/accepts_value_for.rb +24 -0
  28. data/lib/babushka/base.rb +78 -0
  29. data/lib/babushka/bug_reporter.rb +55 -0
  30. data/lib/babushka/cmdline.rb +133 -0
  31. data/lib/babushka/cmdline/handler.rb +41 -0
  32. data/lib/babushka/cmdline/helpers.rb +127 -0
  33. data/lib/babushka/cmdline/parser.rb +69 -0
  34. data/lib/babushka/colorizer.rb +59 -0
  35. data/lib/babushka/core_patches/array.rb +171 -0
  36. data/lib/babushka/core_patches/blank.rb +22 -0
  37. data/lib/babushka/core_patches/bytes.rb +52 -0
  38. data/lib/babushka/core_patches/hash.rb +107 -0
  39. data/lib/babushka/core_patches/hashish.rb +14 -0
  40. data/lib/babushka/core_patches/integer.rb +25 -0
  41. data/lib/babushka/core_patches/io.rb +8 -0
  42. data/lib/babushka/core_patches/numeric.rb +16 -0
  43. data/lib/babushka/core_patches/object.rb +27 -0
  44. data/lib/babushka/core_patches/string.rb +116 -0
  45. data/lib/babushka/core_patches/symbol.rb +12 -0
  46. data/lib/babushka/core_patches/try.rb +15 -0
  47. data/lib/babushka/core_patches/uri.rb +24 -0
  48. data/lib/babushka/dep.rb +470 -0
  49. data/lib/babushka/dep_context.rb +18 -0
  50. data/lib/babushka/dep_definer.rb +115 -0
  51. data/lib/babushka/dep_pool.rb +49 -0
  52. data/lib/babushka/dep_runner.rb +85 -0
  53. data/lib/babushka/dsl.rb +26 -0
  54. data/lib/babushka/git_repo.rb +185 -0
  55. data/lib/babushka/helpers/git_helpers.rb +32 -0
  56. data/lib/babushka/helpers/log_helpers.rb +176 -0
  57. data/lib/babushka/helpers/path_helpers.rb +34 -0
  58. data/lib/babushka/helpers/run_helpers.rb +145 -0
  59. data/lib/babushka/helpers/shell_helpers.rb +229 -0
  60. data/lib/babushka/helpers/suggest_helpers.rb +16 -0
  61. data/lib/babushka/helpers/uri_helpers.rb +36 -0
  62. data/lib/babushka/ip.rb +160 -0
  63. data/lib/babushka/lambda_chooser.rb +40 -0
  64. data/lib/babushka/levenshtein.rb +125 -0
  65. data/lib/babushka/meta_dep.rb +65 -0
  66. data/lib/babushka/meta_dep_context.rb +15 -0
  67. data/lib/babushka/parameter.rb +143 -0
  68. data/lib/babushka/pkg_helper.rb +81 -0
  69. data/lib/babushka/pkg_helpers/apt_helper.rb +61 -0
  70. data/lib/babushka/pkg_helpers/base_helper.rb +19 -0
  71. data/lib/babushka/pkg_helpers/binpkgsrc_helper.rb +48 -0
  72. data/lib/babushka/pkg_helpers/binports_helper.rb +34 -0
  73. data/lib/babushka/pkg_helpers/brew_helper.rb +110 -0
  74. data/lib/babushka/pkg_helpers/gem_helper.rb +120 -0
  75. data/lib/babushka/pkg_helpers/macports_helper.rb +22 -0
  76. data/lib/babushka/pkg_helpers/npm_helper.rb +45 -0
  77. data/lib/babushka/pkg_helpers/pacman_helper.rb +27 -0
  78. data/lib/babushka/pkg_helpers/pip_helper.rb +45 -0
  79. data/lib/babushka/pkg_helpers/src_helper.rb +16 -0
  80. data/lib/babushka/pkg_helpers/yum_helper.rb +25 -0
  81. data/lib/babushka/popen.rb +40 -0
  82. data/lib/babushka/prompt.rb +176 -0
  83. data/lib/babushka/renderable.rb +67 -0
  84. data/lib/babushka/resource.rb +215 -0
  85. data/lib/babushka/run_reporter.rb +60 -0
  86. data/lib/babushka/shell.rb +108 -0
  87. data/lib/babushka/source.rb +216 -0
  88. data/lib/babushka/source_pool.rb +146 -0
  89. data/lib/babushka/system_definitions.rb +97 -0
  90. data/lib/babushka/system_profile.rb +210 -0
  91. data/lib/babushka/task.rb +142 -0
  92. data/lib/babushka/vars.rb +108 -0
  93. data/lib/babushka/version_of.rb +65 -0
  94. data/lib/babushka/version_str.rb +57 -0
  95. data/lib/babushka/xml_string.rb +28 -0
  96. data/lib/components.rb +82 -0
  97. data/lib/fancypath/fancypath.rb +200 -0
  98. data/lib/inkan/inkan.rb +76 -0
  99. data/spec/acceptance/acceptance.rb +43 -0
  100. data/spec/acceptance_helper.rb +113 -0
  101. data/spec/archives/Blah.app.zip +0 -0
  102. data/spec/archives/archive.tar +0 -0
  103. data/spec/archives/archive.tar.bz2 +0 -0
  104. data/spec/archives/archive.tar.gz +0 -0
  105. data/spec/archives/archive.tbz2 +0 -0
  106. data/spec/archives/archive.tgz +0 -0
  107. data/spec/archives/archive.zip +0 -0
  108. data/spec/archives/content.txt +5 -0
  109. data/spec/archives/invalid_archive +5 -0
  110. data/spec/archives/nested archive/content.txt +5 -0
  111. data/spec/archives/nested_archive.tar +0 -0
  112. data/spec/archives/really_a_gzip.zip +0 -0
  113. data/spec/archives/test-0.3.1.tgz +0 -0
  114. data/spec/archives/tgz_archive +0 -0
  115. data/spec/archives/zip_without_extension +0 -0
  116. data/spec/babushka/accepts_for_spec.rb +174 -0
  117. data/spec/babushka/accepts_for_support.rb +72 -0
  118. data/spec/babushka/cmdline/console_spec.rb +11 -0
  119. data/spec/babushka/cmdline/help_spec.rb +61 -0
  120. data/spec/babushka/cmdline/version_spec.rb +10 -0
  121. data/spec/babushka/core_patches_spec.rb +171 -0
  122. data/spec/babushka/dep_context_spec.rb +58 -0
  123. data/spec/babushka/dep_definer_spec.rb +152 -0
  124. data/spec/babushka/dep_definer_support.rb +36 -0
  125. data/spec/babushka/dep_spec.rb +567 -0
  126. data/spec/babushka/dep_support.rb +29 -0
  127. data/spec/babushka/deps_spec.rb +113 -0
  128. data/spec/babushka/gem_helper_spec.rb +90 -0
  129. data/spec/babushka/git_repo_spec.rb +396 -0
  130. data/spec/babushka/ip_spec.rb +131 -0
  131. data/spec/babushka/lambda_chooser_spec.rb +115 -0
  132. data/spec/babushka/meta_dep_definer_spec.rb +127 -0
  133. data/spec/babushka/meta_dep_wrapper_spec.rb +32 -0
  134. data/spec/babushka/parameter_spec.rb +135 -0
  135. data/spec/babushka/path_helpers_spec.rb +102 -0
  136. data/spec/babushka/prompt_spec.rb +188 -0
  137. data/spec/babushka/renderable_spec.rb +100 -0
  138. data/spec/babushka/resource_spec.rb +141 -0
  139. data/spec/babushka/run_helpers_spec.rb +26 -0
  140. data/spec/babushka/shell_helpers_spec.rb +244 -0
  141. data/spec/babushka/shell_spec.rb +19 -0
  142. data/spec/babushka/source_pool_spec.rb +320 -0
  143. data/spec/babushka/source_pool_support.rb +31 -0
  144. data/spec/babushka/source_spec.rb +382 -0
  145. data/spec/babushka/source_support.rb +17 -0
  146. data/spec/babushka/system_profile_spec.rb +61 -0
  147. data/spec/babushka/task_spec.rb +141 -0
  148. data/spec/babushka/uri_spec.rb +13 -0
  149. data/spec/babushka/vars_spec.rb +59 -0
  150. data/spec/babushka/version_of_spec.rb +110 -0
  151. data/spec/babushka/version_str_spec.rb +130 -0
  152. data/spec/babushka/version_str_support.rb +37 -0
  153. data/spec/babushka/xml_string_spec.rb +98 -0
  154. data/spec/deps/bad/broken.rb +7 -0
  155. data/spec/deps/bad/working.rb +3 -0
  156. data/spec/deps/good/meta.rb +14 -0
  157. data/spec/deps/good/test.rb +11 -0
  158. data/spec/deps/outer/deps.rb +19 -0
  159. data/spec/deps/outer/more deps.rb +11 -0
  160. data/spec/deps/params/params.rb +10 -0
  161. data/spec/fancypath/fancypath_spec.rb +272 -0
  162. data/spec/fancypath_support.rb +10 -0
  163. data/spec/inkan/inkan_spec.rb +217 -0
  164. data/spec/renderable/different_example.conf.erb +4 -0
  165. data/spec/renderable/example.conf.erb +3 -0
  166. data/spec/renderable/example.sh +6 -0
  167. data/spec/renderable/with_binding.conf.erb +4 -0
  168. data/spec/renderable/xml_example.conf.erb +8 -0
  169. data/spec/repos/remote.git.tgz +0 -0
  170. data/spec/spec_helper.rb +87 -0
  171. metadata +238 -0
@@ -0,0 +1,65 @@
1
+ module Babushka
2
+ class VersionOf
3
+ module Helpers
4
+ module_function
5
+
6
+ def VersionOf first, *rest
7
+ # Convert the arguments into a VersionOf. If a single string argument is
8
+ # passed, try splitting it on space to separate name and version. Otherwise,
9
+ # pass the arguments as-is, splatting if required.
10
+ if rest.any?
11
+ Babushka::VersionOf.new(*[first].concat(rest))
12
+ elsif first.is_a?(String)
13
+ Babushka::VersionOf.new(*first.split(' ', 2))
14
+ elsif first.is_a?(Array)
15
+ Babushka::VersionOf.new(*first)
16
+ else
17
+ Babushka::VersionOf.new(first)
18
+ end
19
+ end
20
+ end
21
+
22
+ attr_accessor :name, :version
23
+
24
+ def initialize name, version = nil
25
+ @name = name.respond_to?(:name) ? name.name : name
26
+ @version = if version.nil?
27
+ name.version if name.respond_to?(:version)
28
+ elsif version.is_a? VersionStr
29
+ version
30
+ else
31
+ version.to_version
32
+ end
33
+ end
34
+
35
+ def == other
36
+ if other.is_a? VersionOf
37
+ name == other.name &&
38
+ version == other.version
39
+ else
40
+ to_s == other.to_s
41
+ end
42
+ end
43
+
44
+ def <=> other
45
+ raise ArgumentError, "You can't compare the versions of two different things (#{name}, #{other.name})." unless name == other.name
46
+ version <=> other.version
47
+ end
48
+
49
+ def matches? other
50
+ if other.is_a? VersionStr
51
+ version.nil? || other.send(version.operator, version)
52
+ else
53
+ matches? other.to_version
54
+ end
55
+ end
56
+
57
+ def to_s joinery = '-'
58
+ [name, version].compact * joinery
59
+ end
60
+
61
+ def inspect
62
+ "#<VersionOf #{name}#{", v#{version}" unless version.nil?}>"
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,57 @@
1
+ module Babushka
2
+ class VersionStrError < StandardError; end
3
+ class InvalidVersionOperator < VersionStrError; end
4
+ class InvalidVersionStr < VersionStrError; end
5
+
6
+ class VersionStr
7
+ include Comparable
8
+ attr_reader :pieces, :operator, :version
9
+ GemVersionOperators = %w[= == != > < >= <= ~>].freeze
10
+
11
+ def <=> other
12
+ other = other.to_version unless other.is_a? VersionStr
13
+ max_length = [pieces.length, other.pieces.length].max
14
+ (0...max_length).to_a.pick {|index|
15
+ result = compare_pieces pieces[index], other.pieces[index]
16
+ result unless result == 0
17
+ } || 0
18
+ end
19
+
20
+ def initialize str
21
+ @operator, @version = str.strip.scan(/^([^\s\w\-\.]+)?\s*v?([\w\-\.]+)$/i).first
22
+
23
+ if !(@operator.nil? || GemVersionOperators.include?(@operator))
24
+ raise InvalidVersionOperator, "VersionStr.new('#{str}'): invalid operator '#{@operator}'."
25
+ elsif @version.nil?
26
+ raise InvalidVersionStr, "VersionStr.new('#{str}'): couldn't parse a version number."
27
+ else
28
+ @pieces = @version.strip.scan(/\d+|[a-zA-Z]+|\w+/).map {|piece|
29
+ piece[/^\d+$/] ? piece.to_i : piece
30
+ }
31
+ @operator = '==' if @operator.nil? || @operator == '='
32
+ end
33
+ end
34
+
35
+ def to_s
36
+ @operator == '==' ? @version : "#{@operator} #{@version}"
37
+ end
38
+
39
+ define_method "!=" do |other|
40
+ !(self == other)
41
+ end
42
+
43
+ define_method "~>" do |other|
44
+ (self >= other) && pieces.starts_with?(other.pieces[0..-2])
45
+ end
46
+
47
+ private
48
+
49
+ def compare_pieces this, that
50
+ if this.is_a?(String) ^ that.is_a?(String)
51
+ this.is_a?(String) ? -1 : 1
52
+ else
53
+ (this || 0) <=> (that || 0)
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,28 @@
1
+ module Babushka
2
+ class XMLString < String
3
+ # This extracts values from XML, like that found in .plist files. For example,
4
+ #
5
+ # %Q{
6
+ # <key>SVNPath</key>
7
+ # <string>/trunk/src</string>
8
+ # <key>SVNRevision</key>
9
+ # <string>37609</string>
10
+ # }.val_for('SVNRevision') #=> "37609"
11
+ #
12
+ # It doesn't work for arrays, and probably doesn't work for boolean values.
13
+ # Patches welcome :)
14
+ def val_for key
15
+ split(/<\/[^>]+>\n\s*<key>/m).select {|i|
16
+ i[/#{Regexp.escape(key)}<\/key>/]
17
+ }.map {|i|
18
+ i.scan(/<[^\/>]+>(.*)$/m)
19
+ }.flatten.first
20
+ end
21
+ end
22
+ end
23
+
24
+ class String
25
+ def xml_val_for key
26
+ Babushka::XMLString.new(self).val_for(key)
27
+ end
28
+ end
data/lib/components.rb ADDED
@@ -0,0 +1,82 @@
1
+ require 'singleton'
2
+
3
+ module Babushka
4
+ ExternalComponents = %w[
5
+ fancypath/fancypath
6
+ inkan/inkan
7
+ ]
8
+
9
+ Components = %w[
10
+ core_patches/blank
11
+ core_patches/try
12
+ core_patches/array
13
+ core_patches/hash
14
+ core_patches/hashish
15
+ core_patches/integer
16
+ core_patches/io
17
+ core_patches/numeric
18
+ core_patches/bytes
19
+ core_patches/object
20
+ core_patches/string
21
+ core_patches/symbol
22
+ core_patches/uri
23
+ xml_string
24
+ helpers/log_helpers
25
+ helpers/shell_helpers
26
+ helpers/path_helpers
27
+ helpers/run_helpers
28
+ helpers/suggest_helpers
29
+ helpers/git_helpers
30
+ helpers/uri_helpers
31
+ popen
32
+ shell
33
+ git_repo
34
+ resource
35
+ prompt
36
+ lambda_chooser
37
+ ip
38
+ version_str
39
+ version_of
40
+ accepts_list_for
41
+ accepts_value_for
42
+ accepts_block_for
43
+ colorizer
44
+ levenshtein
45
+ cmdline/parser
46
+ cmdline/handler
47
+ cmdline/helpers
48
+ cmdline
49
+ base
50
+ renderable
51
+ system_definitions
52
+ system_profile
53
+ run_reporter
54
+ bug_reporter
55
+ pkg_helper
56
+ pkg_helpers/base_helper
57
+ pkg_helpers/apt_helper
58
+ pkg_helpers/yum_helper
59
+ pkg_helpers/brew_helper
60
+ pkg_helpers/gem_helper
61
+ pkg_helpers/macports_helper
62
+ pkg_helpers/src_helper
63
+ pkg_helpers/pip_helper
64
+ pkg_helpers/binpkgsrc_helper
65
+ pkg_helpers/binports_helper
66
+ pkg_helpers/npm_helper
67
+ pkg_helpers/pacman_helper
68
+ dsl
69
+ dep
70
+ dep_pool
71
+ task
72
+ source
73
+ source_pool
74
+ vars
75
+ parameter
76
+ dep_runner
77
+ dep_definer
78
+ dep_context
79
+ meta_dep
80
+ meta_dep_context
81
+ ]
82
+ end
@@ -0,0 +1,200 @@
1
+ require 'pathname'
2
+
3
+ class Fancypath < Pathname
4
+ module Helpers
5
+ require 'etc'
6
+ def to_fancypath
7
+ Fancypath.new to_tilde_expanded_path
8
+ end
9
+ def to_expanded_fancypath
10
+ Fancypath.new File.expand_path(to_tilde_expanded_path)
11
+ end
12
+ def to_tilde_expanded_path
13
+ sub(/^\~\/|^\~$/) {|_| Etc.getpwuid(Process.euid).dir.end_with('/') }
14
+ end
15
+ alias :p :to_expanded_fancypath
16
+ end
17
+
18
+ # methods are chainable and do what you think they do
19
+
20
+ alias_method :to_str, :to_s unless method_defined? :to_str
21
+
22
+ alias_method :dir, :dirname
23
+ alias_method :directory, :dirname
24
+
25
+ alias_method :dir?, :directory?
26
+
27
+ alias_method :expand, :expand_path
28
+ alias_method :abs, :expand_path
29
+ alias_method :absolute, :expand_path
30
+
31
+ alias_method :exists?, :exist?
32
+ alias_method :rename_to, :rename
33
+
34
+ def == other
35
+ if other.is_a? String
36
+ to_s == other
37
+ else
38
+ super
39
+ end
40
+ end
41
+
42
+ def length
43
+ to_s.length
44
+ end
45
+
46
+ def join(path)
47
+ path_str = path.to_s
48
+ super(path_str[0..0] == '/' ? path_str[1..-1] : path_str).p
49
+ end
50
+
51
+ alias_method :/, :join
52
+
53
+ # This method returns true if the path is writable (i.e. and already
54
+ # exists), or if the current user would be able to create it (i.e. if
55
+ # its closest existing parent is writable).
56
+ def hypothetically_writable?
57
+ writable? || (!exists? && !root? && parent.hypothetically_writable?)
58
+ end
59
+
60
+ # make file
61
+ def touch
62
+ `touch '#{self}'`
63
+ self
64
+ end
65
+
66
+ def create_dir
67
+ mkpath unless exist?
68
+ self
69
+ end
70
+
71
+ alias_method :create, :create_dir
72
+
73
+ def copy(dest)
74
+ `cp -pPR '#{self}' '#{dest}'`
75
+ self
76
+ end
77
+
78
+ alias_method :cp, :copy
79
+
80
+ # file or dir
81
+ def remove
82
+ directory? ? rmtree : delete if exist?
83
+ self
84
+ end
85
+ alias_method :rm, :remove
86
+
87
+ def read
88
+ super.chomp if exists?
89
+ end
90
+
91
+ def readlink
92
+ if !symlink?
93
+ self
94
+ elsif
95
+ target = super
96
+ target.absolute? ? target : (dir / target)
97
+ end
98
+ end
99
+
100
+ def mkdir
101
+ `mkdir -p '#{self}'`
102
+ self
103
+ end
104
+
105
+ def glob expr = nil, flags = File::FNM_CASEFOLD, &block
106
+ Dir.glob((expr.nil? ? self : (self / expr)).to_s, flags, &block)
107
+ end
108
+
109
+ def write(contents, mode='wb')
110
+ dirname.create
111
+ open(mode) { |f| f.write contents }
112
+ self
113
+ end
114
+
115
+ def append(contents)
116
+ write(contents,'a+')
117
+ self
118
+ end
119
+
120
+ def move(dest)
121
+ self.rename(dest)
122
+ dest.p
123
+ end
124
+
125
+ def tail(bytes)
126
+ return self.read if self.size < bytes
127
+ open('r') do |f|
128
+ f.seek(-bytes, IO::SEEK_END)
129
+ f.read
130
+ end
131
+ end
132
+
133
+ alias_method :mv, :move
134
+
135
+ def set_extension(ext)
136
+ "#{without_extension}.#{ext}".p
137
+ end
138
+
139
+ alias_method :change_extension, :set_extension
140
+
141
+ def without_extension
142
+ to_s[/^ (.+?) (\. ([^\.]+))? $/x, 1].p
143
+ end
144
+
145
+ def has_extension?(ext)
146
+ !!(self.to_s =~ /\.#{ext}$/)
147
+ end
148
+
149
+ def parent
150
+ super.p
151
+ end
152
+
153
+ alias_method :all_children, :children
154
+
155
+ def children
156
+ super.reject { |c| c.basename.to_s =~ /^\./ }
157
+ end
158
+
159
+ # only takes sym atm
160
+ def select(*args)
161
+ return args.map { |arg| select(arg) }.flatten.uniq if args.size > 1
162
+
163
+ case arg = args.first
164
+ when Symbol
165
+ Dir["#{self}/*.#{arg}"].map { |p| self.class.new(p) }
166
+ when Regexp
167
+ children.select { |child| child.to_s =~ arg }
168
+ else
169
+ Dir["#{self}/#{arg}"].map { |p| self.class.new(p) }
170
+ end
171
+ end
172
+
173
+ def empty?
174
+ directory? ? children.size == 0 : self.size == 0
175
+ end
176
+
177
+ def owner
178
+ Etc.getpwuid(File.stat(to_s).uid).name
179
+ end
180
+
181
+ def group
182
+ Etc.getgrgid(File.stat(to_s).gid).name
183
+ end
184
+
185
+ def inspect
186
+ super.sub('Pathname','Fancypath')
187
+ end
188
+
189
+ def to_fancypath
190
+ self
191
+ end
192
+
193
+ end
194
+
195
+ class Pathname
196
+ include Fancypath::Helpers
197
+ end
198
+ class String
199
+ include Fancypath::Helpers
200
+ end
@@ -0,0 +1,76 @@
1
+ class Inkan
2
+ attr_accessor :credit, :comment, :comment_suffix
3
+
4
+ def self.legitimate?(filename)
5
+ File.open(filename) do |file|
6
+ file_content = file.read
7
+ seal, content = if file_content[/\A#!/]
8
+ hashbang, seal, remaining_content = file_content.split("\n", 3)
9
+ [seal, "#{hashbang}\n#{remaining_content}"]
10
+ else
11
+ file_content.split("\n", 2)
12
+ end
13
+
14
+ !seal[/\s#{sha(content || '')}\s*$/].nil?
15
+ end
16
+ end
17
+
18
+ def self.seal(file)
19
+ new(file).tap {|inkan| yield inkan }.seal
20
+ end
21
+
22
+ def self.render
23
+ new(nil).tap {|inkan| yield inkan }.render
24
+ end
25
+
26
+ def self.sha(content)
27
+ require 'digest/sha1'
28
+ Digest::SHA1.hexdigest(content)
29
+ end
30
+
31
+ def initialize(file)
32
+ @file = file
33
+
34
+ # Set Defaults
35
+ @credit = 'Generated by Inkan'
36
+ @comment = '#'
37
+ @comment_suffix = ''
38
+ end
39
+
40
+ def print(string)
41
+ file_content << string
42
+ end
43
+
44
+ def puts(string)
45
+ file_content << string << "\n"
46
+ end
47
+
48
+ def seal
49
+ File.open(@file, 'w') do |f|
50
+ f.print render
51
+ end
52
+ end
53
+
54
+ def render
55
+ if file_content[/\A#!/]
56
+ hashbang, remaining_content = file_content.split("\n", 2)
57
+ "#{hashbang}\n#{render_seal}\n#{remaining_content}"
58
+ else
59
+ "#{render_seal}\n#{file_content}"
60
+ end
61
+ end
62
+
63
+ private
64
+
65
+ def render_seal
66
+ "#{comment} #{credit}. #{sha} #{comment_suffix}"
67
+ end
68
+
69
+ def sha
70
+ self.class.sha(file_content)
71
+ end
72
+
73
+ def file_content
74
+ @file_content ||= ''
75
+ end
76
+ end