genprovider 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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