genprovider 0.2.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.
Files changed (94) hide show
  1. data/CHANGELOG +8 -0
  2. data/CHANGELOG~ +4 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +58 -0
  5. data/README.rdoc +50 -0
  6. data/Rakefile +6 -0
  7. data/bin/genprovider +256 -0
  8. data/bin/regprovider +105 -0
  9. data/features/003-create.feature +10 -0
  10. data/features/004-modify.feature +9 -0
  11. data/features/005-delete.feature +7 -0
  12. data/features/datatypes.feature +13 -0
  13. data/features/ensure-format.feature +28 -0
  14. data/features/have-instances.feature +19 -0
  15. data/features/mof/trivial.mof +20 -0
  16. data/features/registration.feature +12 -0
  17. data/features/run-genprovider.feature +10 -0
  18. data/features/show-context.feature +9 -0
  19. data/features/step_definitions/genprovider.rb +52 -0
  20. data/features/step_definitions/mof.rb +3 -0
  21. data/features/step_definitions/registration.rb +21 -0
  22. data/features/step_definitions/wbemcli.rb +58 -0
  23. data/features/support/env.rb +20 -0
  24. data/genprovider.gemspec +36 -0
  25. data/lib/genprovider/class.rb +200 -0
  26. data/lib/genprovider/classinfo.rb +88 -0
  27. data/lib/genprovider/output.rb +104 -0
  28. data/lib/genprovider/provider.rb +721 -0
  29. data/lib/genprovider/rdoc.rb +149 -0
  30. data/lib/genprovider/registration.rb +22 -0
  31. data/lib/genprovider/testcase.rb +139 -0
  32. data/lib/genprovider/version.rb +3 -0
  33. data/lib/genprovider.rb +35 -0
  34. data/samples/mof/LMI_Embedded.mof +6 -0
  35. data/samples/mof/RCP_ArrayDataTypes.mof +27 -0
  36. data/samples/mof/RCP_ClassMethod.mof +7 -0
  37. data/samples/mof/RCP_ComplexMethod.mof +14 -0
  38. data/samples/mof/RCP_IndicationGenerator.mof +13 -0
  39. data/samples/mof/RCP_PassCData.mof +10 -0
  40. data/samples/mof/RCP_ShowContext.mof +11 -0
  41. data/samples/mof/RCP_SimpleClass.mof +7 -0
  42. data/samples/mof/RCP_SimpleDataTypes.mof +27 -0
  43. data/samples/mof/RCP_SimpleMethod.mof +9 -0
  44. data/samples/mof/qualifiers.mof +20 -0
  45. data/samples/provider/lmi_embedded.rb +148 -0
  46. data/samples/provider/rcp_array_data_types.rb +219 -0
  47. data/samples/provider/rcp_class_method.rb +54 -0
  48. data/samples/provider/rcp_complex_method.rb +170 -0
  49. data/samples/provider/rcp_pass_c_data.rb +130 -0
  50. data/samples/provider/rcp_show_context.rb +134 -0
  51. data/samples/provider/rcp_simple_class.rb +124 -0
  52. data/samples/provider/rcp_simple_data_types.rb +152 -0
  53. data/samples/provider/rcp_simple_method.rb +143 -0
  54. data/samples/registration/LMI_Embedded.registration +7 -0
  55. data/samples/registration/RCP_ArrayDataTypes.registration +7 -0
  56. data/samples/registration/RCP_ClassMethod.registration +8 -0
  57. data/samples/registration/RCP_ComplexMethod.registration +8 -0
  58. data/samples/registration/RCP_PassCData.registration +7 -0
  59. data/samples/registration/RCP_ShowContext.registration +7 -0
  60. data/samples/registration/RCP_SimpleDataTypes.registration +7 -0
  61. data/samples/registration/RCP_SimpleMethod.registration +8 -0
  62. data/samples/sfcb.reg/RCP_ComputerSystem.reg +5 -0
  63. data/samples/sfcb.reg/RCP_OSProcess.reg +5 -0
  64. data/samples/sfcb.reg/RCP_OperatingSystem.reg +5 -0
  65. data/samples/sfcb.reg/RCP_PhysicalMemory.reg +5 -0
  66. data/samples/sfcb.reg/RCP_Processor.reg +5 -0
  67. data/samples/sfcb.reg/RCP_RunningOS.reg +5 -0
  68. data/samples/sfcb.reg/RCP_SimpleClass.reg +5 -0
  69. data/samples/sfcb.reg/RCP_UnixProcess.reg +5 -0
  70. data/sfcbd +4 -0
  71. data/stress.sh +4 -0
  72. data/tasks/clean.rake +4 -0
  73. data/tasks/doc.rake +16 -0
  74. data/tasks/features.rake +8 -0
  75. data/tasks/prepstage.rake +16 -0
  76. data/tasks/registration.rake +10 -0
  77. data/tasks/sfcb.rake +3 -0
  78. data/tasks/test.rake +10 -0
  79. data/test/env.rb +23 -0
  80. data/test/helper.rb +23 -0
  81. data/test/mkreg.rb +32 -0
  82. data/test/mof/RCP_ClassMethod.rb +15 -0
  83. data/test/mof/RCP_ComplexMethod.rb +16 -0
  84. data/test/mof/RCP_SimpleMethod.rb +15 -0
  85. data/test/registration.rb +37 -0
  86. data/test/sfcb.rb +94 -0
  87. data/test/test_lmi_embedded.rb +64 -0
  88. data/test/test_rcp_array_data_types.rb +140 -0
  89. data/test/test_rcp_class_method.rb +31 -0
  90. data/test/test_rcp_complex_method.rb +68 -0
  91. data/test/test_rcp_simple_data_types.rb +66 -0
  92. data/test/test_rcp_simple_method.rb +47 -0
  93. data/valgrind +8 -0
  94. metadata +288 -0
@@ -0,0 +1,52 @@
1
+ Then /^I should see a short usage explanation$/ do
2
+ @output =~ /Usage:/
3
+ end
4
+
5
+ Then /^I should see an "([^"]*)" file$/ do |arg1| #"
6
+ File.exists? arg1
7
+ end
8
+
9
+ Then /^I should see an error message$/ do
10
+ File.stat(File.join(TMPDIR,"std.err")).size > 0
11
+ end
12
+
13
+ Then /^comment lines should not exceed (\d+) characters$/ do |arg1| #"
14
+ maxcolumn = arg1.to_i
15
+ @output.scan(/^\s*\#.*$/).each do |l|
16
+ return false if l.chomp.size > maxcolumn
17
+ end
18
+ true
19
+ end
20
+
21
+ Then /^its output should be accepted by Ruby$/ do
22
+ Dir.foreach($sfcb.providers_dir) do |f|
23
+ next unless f =~ /.rb$/
24
+ res = system "ruby", File.join($sfcb.providers_dir, f)
25
+ raise unless res && $? == 0
26
+ end
27
+ end
28
+
29
+ When /^I run genprovider with no arguments$/ do
30
+ @output = `ruby -I #{LIBDIR} #{GENPROVIDER} 2> #{TMPDIR}/std.err`
31
+ raise if $? == 0
32
+ end
33
+
34
+ def generate_provider_for mof
35
+ cmd = "ruby -I #{LIBDIR} #{GENPROVIDER} -f -n #{NAMESPACE} -o #{$sfcb.providers_dir} #{TOPLEVEL}/samples/mof/qualifiers.mof #{File.join(TOPLEVEL, mof)} 2> #{TMPDIR}/std.err"
36
+ # STDERR.puts "Run #{cmd}"
37
+ @output = `#{cmd}`
38
+ raise unless $? == 0
39
+ end
40
+
41
+ When /^I pass "([^"]*)" to genprovider$/ do |arg1| #"
42
+ generate_provider_for arg1
43
+ end
44
+
45
+ Given /^a generated provider for "(.*?)"$/ do |arg1|
46
+ raise unless File.exists?(File.join(TOPLEVEL,arg1))
47
+ end
48
+
49
+ When /^I run genprovider with "([^"]*)"$/ do |arg1| #"
50
+ @output = `ruby -I #{LIBDIR} #{GENPROVIDER} #{arg1} 2> #{TMPDIR}/std.err`
51
+ raise unless $? == 0
52
+ end
@@ -0,0 +1,3 @@
1
+ Given /^I have a mof file called "([^"]*)"$/ do |arg1|
2
+ File.exists?("mof/#{arg1}")
3
+ end
@@ -0,0 +1,21 @@
1
+ When /^I register "([^"]*)" using "([^"]*)" with sfcb$/ do |mofpath,regname|
2
+ return if ENV['NO_REGISTER']
3
+ $sfcb.stop
4
+ tmpregname = File.join(TMPDIR, File.basename(regname, ".registration") + ".reg")
5
+ sfcb_transform_to tmpregname, File.join("#{TOPLEVEL}/samples/registration", regname)
6
+ cmd = "sfcbstage -s #{$sfcb.stage_dir} -n #{NAMESPACE} -r #{tmpregname} #{File.join(TOPLEVEL, mofpath)}"
7
+ # STDERR.puts cmd
8
+ res = `#{cmd} 2> #{TMPDIR}/sfcbstage.err`
9
+ raise unless $? == 0
10
+ cmd = "sfcbrepos -f -s #{$sfcb.stage_dir} -r #{$sfcb.registration_dir}"
11
+ # STDERR.puts cmd
12
+ res = `#{cmd} 2> #{TMPDIR}/sfcbrepos.err`
13
+ raise unless $? == 0
14
+ $sfcb.start
15
+ end
16
+
17
+ When /^"([^"]*)" is registered in namespace "([^"]*)"$/ do |arg1,arg2| #"
18
+ out = `wbemecn #{$sfcb.url}/#{arg2} 2> #{TMPDIR}/wbemecn.err`
19
+ # STDERR.puts "wbemecn expects '#{arg1}', returns '#{out}'"
20
+ raise unless out =~ Regexp.new(arg1)
21
+ end
@@ -0,0 +1,58 @@
1
+ Given /^an instance of "([^"]*)" with property "([^"]*)" set to "([^"]*)"$/ do |arg1, arg2, arg3| #"
2
+ url = $sfcb.url
3
+ cmd = "wbemein #{url}/test/test:#{arg1}"
4
+ # STDERR.puts "Calling #{cmd}"
5
+ out = `#{cmd}`
6
+ # STDERR.puts "Enum instance names returned '#{out}'"
7
+ raise unless out =~ Regexp.new(arg1)
8
+ @instance = out.chomp
9
+ out = `wbemgi http://#{out}`
10
+ # STDERR.puts "Get instance returned '#{out}'"
11
+ raise unless out.include? "#{arg2}=\"#{arg3}\""
12
+ end
13
+
14
+ Then /^I should see "([^"]*)" in enumerated class names$/ do |arg1| #"
15
+ url = $sfcb.url
16
+ out = `wbemecn #{url}`
17
+ raise unless out =~ Regexp.new(arg1)
18
+ end
19
+
20
+ Then /^I should see "([^"]*)" in namespace "([^"]*)"$/ do |arg1, arg2|
21
+ url = $sfcb.url
22
+ out = `wbemecn #{url}/#{arg2}`
23
+ raise unless out =~ Regexp.new(arg1)
24
+ end
25
+
26
+ Then /^I should see "([^"]*)" in enumerated instance names$/ do |arg1| #"
27
+ url = $sfcb.url
28
+ cmd = "wbemein #{url}/test/test:#{arg1}"
29
+ # STDERR.puts "Calling #{cmd}"
30
+ out = `#{cmd}`
31
+ raise unless out =~ Regexp.new(arg1)
32
+ end
33
+
34
+ Then /^the instance of "([^"]*)" should have property "([^"]*)" set to "([^"]*)"$/ do |arg1, arg2, arg3| #"
35
+ url = $sfcb.url
36
+ cmd = "wbemein #{url}/test/test:#{arg1}"
37
+ # STDERR.puts "Calling #{cmd}"
38
+ out = `#{cmd}`
39
+ # STDERR.puts "-> '#{out}'"
40
+ out = `wbemgi http://#{out}`
41
+ # STDERR.puts "-> '#{out}'"
42
+ raise unless out.include? "#{arg2}=\"#{arg3}\""
43
+ end
44
+
45
+ When /^I create an instance of "([^"]*)" with "([^"]*)" set to "([^"]*)"$/ do |arg1, arg2, arg3| #"
46
+ url = $sfcb.url
47
+ cmd = "wbemci '#{url}/test/test:#{arg1}.#{arg2}=\"#{arg3}\"' '#{arg2}=\"#{arg3}\"'"
48
+ # $stderr.puts "Calling #{cmd}"
49
+ out = `#{cmd}`
50
+ raise unless $? == 0
51
+ end
52
+
53
+ When /^I change the property "([^"]*)" to "([^"]*)"$/ do |arg1, arg2|
54
+ cmd = "wbemmi http://#{@instance} #{arg1}=\"#{arg2}\""
55
+ # $stderr.puts "Calling #{cmd}"
56
+ out = `#{cmd}`
57
+ # STDERR.puts "Modify instance returned '#{out}'"
58
+ end
@@ -0,0 +1,20 @@
1
+ #
2
+ # features/support/env.rb
3
+ #
4
+
5
+ require 'rubygems'
6
+ require "test/unit"
7
+
8
+ require_relative "../../test/env"
9
+
10
+ require_relative "./sfcb"
11
+
12
+ # directory with test .mof files
13
+ MOFDIR = File.join(TOPLEVEL,"features","mof")
14
+
15
+ $sfcb = Sfcb.new :tmpdir => TMPDIR,
16
+ :provider => "#{TOPLEVEL}/samples/provider"
17
+ $sfcb.start
18
+ at_exit do
19
+ $sfcb.stop
20
+ end
@@ -0,0 +1,36 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "genprovider/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "genprovider"
7
+ s.version = Genprovider::VERSION
8
+
9
+ s.platform = Gem::Platform::RUBY
10
+ s.authors = ["Klaus Kämpf"]
11
+ s.email = ["kkaempf@suse.de"]
12
+ s.homepage = "https://github.com/kkaempf/genprovider"
13
+ s.summary = %q{A generator for Ruby based CIM providers}
14
+ s.description = %q{Generates Ruby provider templates for use with cmpi-bindings}
15
+
16
+ s.requirements << %q{sblim-cmpi-base (for provider-register.sh)}
17
+ s.requirements << %q{sblim-sfcb for testing}
18
+
19
+ s.add_dependency("cim", ["~> 1.0"])
20
+ s.add_dependency("mof", ["~> 1.0"])
21
+ s.add_dependency("rdoc")
22
+
23
+ s.add_development_dependency('rake')
24
+ s.add_development_dependency('sfcc')
25
+ s.add_development_dependency('bundler')
26
+ s.add_development_dependency('cucumber')
27
+
28
+ s.rubyforge_project = "genprovider"
29
+
30
+ s.files = `git ls-files`.split("\n")
31
+ s.files.reject! { |fn| fn == '.gitignore' }
32
+ s.extra_rdoc_files = Dir['README*', 'TODO*', 'CHANGELOG*', 'LICENSE']
33
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
34
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
35
+ s.require_paths = ["lib"]
36
+ end
@@ -0,0 +1,200 @@
1
+ #
2
+ # Genprovider::Class
3
+ #
4
+
5
+ #
6
+ # make element description
7
+ #
8
+
9
+ module Genprovider
10
+ class Class
11
+ def self.mkdescription out, element
12
+ p = element.qualifiers["description", :string]
13
+ out.comment
14
+ out.comment(p.value).comment if p
15
+ end
16
+
17
+ def self.keyargs c, out, first = true
18
+ keyargs c.parent, first, out if c.parent
19
+ c.each_key do |k|
20
+ if first
21
+ first = false
22
+ else
23
+ out.write ", "
24
+ end
25
+ out.write(k.name.decamelize)
26
+ end
27
+ end
28
+
29
+ #
30
+ # make initializer
31
+ #
32
+
33
+ def mkinitialize c, out
34
+
35
+ out.def "initialize", "reference", "properties"
36
+ if c.parent
37
+ out.puts "super reference,properties"
38
+ end
39
+ out.end
40
+ end
41
+
42
+ #
43
+ # make static methods
44
+ #
45
+
46
+ def mkstatic c, out
47
+ out.comment "each: yield CMPIObjectPath references"
48
+ out.comment " full => false: set only key properties (instance name)"
49
+ out.comment " true: with full information to create instances"
50
+ out.def "self.each", "reference", "properties", "full = false"
51
+ out.comment "Retrieve names, adapt reference, and yield CMPIObjectPath"
52
+ out.comment
53
+ out.comment "YOUR CODE HERE"
54
+ out.comment
55
+ out.end
56
+ out.def "self.delete", "reference", "properties = nil"
57
+ out.comment "Remove by reference"
58
+ out.comment
59
+ out.comment "YOUR CODE HERE"
60
+ out.comment
61
+ out.end
62
+ end
63
+
64
+ #
65
+ # make feature definition
66
+ #
67
+
68
+ def mkdef out, feature
69
+ Genprovider::Class.mkdescription out, feature
70
+ case feature
71
+ when CIM::Property
72
+ # skip
73
+ when CIM::Reference then out.comment "Reference"
74
+ when CIM::Method then out.comment "Method"
75
+ else
76
+ raise "Unknown feature class #{feature.class}"
77
+ end
78
+ out.comment feature.type.to_s + " : " + feature.name
79
+ out.comment "*Key*" if feature.key?
80
+ out.comment
81
+
82
+ args = nil
83
+ if feature.method?
84
+ feature.parameters.each do |p|
85
+ args ||= []
86
+ if p.qualifiers.include?(:out,:bool)
87
+ args << "#{p.name.decamelize}_out"
88
+ else
89
+ args << p.name.decamelize
90
+ end
91
+ end
92
+ end
93
+ n = feature.name.decamelize
94
+ out.def n, args
95
+ out.puts "@#{n}"
96
+ out.end
97
+ if feature.property? && feature.qualifiers.include?(:write)
98
+ out.def "#{n}=", "_arg"
99
+ out.puts "@#{n} = _arg"
100
+ out.end
101
+ end
102
+ end
103
+
104
+ #
105
+ # generate code for property
106
+ #
107
+
108
+ def mkproperty property, out
109
+ mkdef out, property
110
+ end
111
+
112
+ #
113
+ # generate code for reference
114
+ #
115
+
116
+ def mkreference reference, out
117
+ mkdef out, reference
118
+ end
119
+
120
+ #
121
+ # generate code for method
122
+ #
123
+
124
+ def mkmethod method, out
125
+ mkdef out, method
126
+ end
127
+
128
+ #
129
+ # generate provider code for features matching match
130
+ #
131
+
132
+ def mkfeatures features, out, match
133
+ features.each do |f|
134
+ next unless f.instance_of? match
135
+ case f
136
+ when CIM::Property then mkproperty f, out
137
+ when CIM::Reference then mkreference f, out
138
+ when CIM::Method then mkmethod f, out
139
+ else
140
+ raise "Unknown feature class #{f.class}"
141
+ end
142
+ end
143
+ end
144
+
145
+ #
146
+ # yield class features recursively
147
+ # which => nil : all
148
+ # :keys : keys only
149
+ # :nokeys : nokeys only
150
+ #
151
+ def all_features(klass, option)
152
+ while klass
153
+ klass.features.each do |f|
154
+ next if option == :nokeys && f.key?
155
+ next if option == :keys && !f.key?
156
+ yield "- #{f.type} #{f.name} (-> #{klass.name})"
157
+ end
158
+ klass = klass.parent
159
+ end
160
+ end
161
+ #
162
+ # generate provider code for class 'c'
163
+ #
164
+
165
+ def initialize c, out
166
+ out.comment
167
+ out.comment "Generated by genprovider"
168
+ out.comment
169
+ out.puts("require 'cmpi'").puts
170
+ out.puts("module Cmpi").inc
171
+
172
+ Genprovider::Class.mkdescription out, c
173
+
174
+ if c.superclass
175
+ out.puts "d = File.dirname(__FILE__)"
176
+ out.puts "$: << d unless $:.include? d"
177
+ out.puts "require '#{c.superclass.decamelize}'"
178
+ end
179
+ out.comment.comment "Properties:"
180
+ all_features(c, :keys) { |comment| out.comment "[key] #{comment}" }
181
+ all_features(c, :nokeys) { |comment| out.comment comment }
182
+ out.comment
183
+ out.printf("class #{c.name}")
184
+ out.write(" < #{c.superclass}") if c.superclass
185
+ out.puts.inc
186
+ # class functions
187
+ mkstatic c, out
188
+ # initializer
189
+ mkinitialize c, out
190
+ # normal properties
191
+ mkfeatures c.features, out, CIM::Property
192
+ # reference properties
193
+ mkfeatures c.features, out, CIM::Reference
194
+ # methods
195
+ mkfeatures c.features, out, CIM::Method
196
+ out.end # class
197
+ out.end # module
198
+ end
199
+ end
200
+ end
@@ -0,0 +1,88 @@
1
+ #
2
+ # classinfo.rb
3
+ #
4
+ # Generate class information (esp method invocation) for clients
5
+ #
6
+
7
+ module Genprovider
8
+ class ClassInfo
9
+
10
+ def initialize c, out
11
+ out.comment.comment "Class information for #{c.name}"
12
+ out.comment.comment "Generated by 'genprovider' for use with ruby-sfcc"
13
+ out.puts
14
+ out.puts "require 'rubygems'"
15
+ out.puts "require 'cim'"
16
+ s = c
17
+ while s.parent
18
+ s = s.parent
19
+ out.puts "require 'mof/#{s.name}'"
20
+ end
21
+ out.puts
22
+ s = c.superclass ? " < #{c.superclass}" : ""
23
+
24
+ # module MOF
25
+ out.puts "module MOF"
26
+ out.inc
27
+
28
+ # class <Class>
29
+ out.puts "class #{c.name}#{s}"
30
+ out.inc
31
+
32
+ # methods
33
+ method_count = 0
34
+ s = nil
35
+ c.features.each do |f|
36
+ next unless f.method?
37
+ if method_count == 0
38
+ out.puts "METHODS = {"
39
+ out.inc
40
+ end
41
+ if method_count > 0
42
+ out.puts "#{s}," if s
43
+ s = nil
44
+ end
45
+ s = "#{f.name.inspect} => { :type => #{f.type.to_sym.inspect}"
46
+ unless f.parameters.empty?
47
+ s << ", :parameters => {"
48
+
49
+ have_in = 0
50
+ f.parameters.each do |p|
51
+ next if p.out? # non-out parameters are input
52
+ if have_in == 0
53
+ s << ":in => ["
54
+ else
55
+ s << ", "
56
+ end
57
+ s << "#{p.name.inspect}, #{p.type.to_sym.inspect}"
58
+ have_in += 1
59
+ end
60
+ s << "]" if have_in > 0
61
+
62
+ have_out = 0
63
+ f.parameters.each do |p|
64
+ next unless p.out? # output parameters must have explicit qualifier
65
+ if have_out == 0
66
+ s << ", " if have_in > 0
67
+ s << ":out => ["
68
+ else
69
+ s << ", "
70
+ end
71
+ s << "#{p.name.inspect}, #{p.type.to_sym.inspect}"
72
+ have_out += 1
73
+ end
74
+ s << "]" if have_out > 0
75
+ s << "}"
76
+ end
77
+ s << " }"
78
+ method_count += 1
79
+ end
80
+ if method_count > 0
81
+ out.puts s
82
+ out.dec.puts "}"
83
+ end
84
+ out.end # class
85
+ out.end # module
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,104 @@
1
+ #
2
+ # Output - a class to output generated code with indendation
3
+ #
4
+ module Genprovider
5
+ class Output
6
+ private
7
+ def indent
8
+ @file.write( " " * @depth * @indent ) if @newline
9
+ end
10
+ public
11
+ attr_reader :name, :dir
12
+ def initialize file, force=false
13
+ if file.kind_of?(IO)
14
+ @file = file
15
+ @name = nil
16
+ else
17
+ if File.exist?(file) && !force
18
+ STDERR.puts "Not overwriting existing #{file}"
19
+ return
20
+ end
21
+ @file = File.open(file, "w+")
22
+ @name = File.basename file
23
+ @dir = File.expand_path(File.dirname file)
24
+ end
25
+ raise "Cannot create file at #{file}" unless @file
26
+ @newline = true
27
+ @indent = 0
28
+ @wrap = 75 # wrap at this column
29
+ @depth = 2 # indent depth
30
+ yield self if block_given?
31
+ end
32
+ def inc
33
+ @indent += 1
34
+ self
35
+ end
36
+ def dec
37
+ @indent -= 1
38
+ @indent = 0 if @indent < 0
39
+ self
40
+ end
41
+ def write str
42
+ @file.write str
43
+ @newline = false
44
+ self
45
+ end
46
+ def puts str=""
47
+ indent
48
+ @file.puts str
49
+ @newline = true
50
+ self
51
+ end
52
+ def def name, *args
53
+ if args.nil? || args.empty? || args[0].nil?
54
+ self.puts "def #{name}"
55
+ else
56
+ self.puts "def #{name}( #{args.join(', ')} )"
57
+ end
58
+ self.inc
59
+ end
60
+ def end
61
+ self.dec
62
+ self.puts "end"
63
+ end
64
+ def comment str=nil, lmargin = nil
65
+ if str =~ /\\n/
66
+ comment $`, lmargin
67
+ comment $', lmargin #' <- colorize helper
68
+ return self
69
+ end
70
+ wrap = @wrap - (@depth * @indent + 2) - ((lmargin)?lmargin:0)
71
+ if str && str.size > wrap # must wrap
72
+ # STDERR.puts "#{str.size} > #{wrap}"
73
+ pivot = wrap
74
+ while pivot > 0 && str[pivot,1] != " " # search space left of wrap
75
+ pivot -= 1
76
+ end
77
+ if pivot == 0 # no space left of wrap
78
+ pivot = wrap
79
+ while pivot < str.size && str[pivot,1] != " " # search space right of wrap
80
+ pivot += 1
81
+ end
82
+ end
83
+ if 0 < pivot && pivot < str.size
84
+ # puts "-wrap @ #{pivot}-"
85
+ comment str[0,pivot], lmargin
86
+ comment str[pivot+1..-1], lmargin
87
+ return self
88
+ end
89
+ end
90
+ indent
91
+ @file.write "#"
92
+ @file.write(" " * lmargin) if lmargin
93
+ @file.write " #{str}" if str
94
+ @file.puts
95
+ self
96
+ end
97
+ def printf format, *args
98
+ indent
99
+ Kernel.printf @file, format, *args
100
+ @newline = false
101
+ self
102
+ end
103
+ end
104
+ end