bit-struct 0.13.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data/.gitignore +2 -0
  2. data/History.txt +102 -0
  3. data/README.txt +189 -0
  4. data/Rakefile +34 -0
  5. data/TODO +23 -0
  6. data/TODO-ALSO +71 -0
  7. data/examples/ara-player-data.rb +82 -0
  8. data/examples/bignum.rb +18 -0
  9. data/examples/bits.rb +19 -0
  10. data/examples/byte-bdy.rb +30 -0
  11. data/examples/field-ripper.rb +22 -0
  12. data/examples/fixed-point.rb +17 -0
  13. data/examples/ip.rb +81 -0
  14. data/examples/longlong.rb +30 -0
  15. data/examples/md.rb +23 -0
  16. data/examples/modular-def.rb +38 -0
  17. data/examples/native.rb +31 -0
  18. data/examples/nested.rb +33 -0
  19. data/examples/pad.rb +14 -0
  20. data/examples/ping-recv.rb +25 -0
  21. data/examples/ping.rb +73 -0
  22. data/examples/player-data.rb +75 -0
  23. data/examples/raw.rb +62 -0
  24. data/examples/rest.rb +30 -0
  25. data/examples/switch-endian.rb +49 -0
  26. data/examples/vector.rb +98 -0
  27. data/lib/bit-struct.rb +6 -0
  28. data/lib/bit-struct/bit-struct.rb +549 -0
  29. data/lib/bit-struct/char-field.rb +48 -0
  30. data/lib/bit-struct/fields.rb +273 -0
  31. data/lib/bit-struct/float-field.rb +61 -0
  32. data/lib/bit-struct/hex-octet-field.rb +20 -0
  33. data/lib/bit-struct/nested-field.rb +76 -0
  34. data/lib/bit-struct/octet-field.rb +45 -0
  35. data/lib/bit-struct/pad-field.rb +15 -0
  36. data/lib/bit-struct/signed-field.rb +258 -0
  37. data/lib/bit-struct/text-field.rb +44 -0
  38. data/lib/bit-struct/unsigned-field.rb +248 -0
  39. data/lib/bit-struct/vector-field.rb +77 -0
  40. data/lib/bit-struct/vector.rb +173 -0
  41. data/lib/bit-struct/yaml.rb +69 -0
  42. data/tasks/ann.rake +80 -0
  43. data/tasks/bones.rake +20 -0
  44. data/tasks/gem.rake +201 -0
  45. data/tasks/git.rake +40 -0
  46. data/tasks/notes.rake +27 -0
  47. data/tasks/post_load.rake +34 -0
  48. data/tasks/rdoc.rake +51 -0
  49. data/tasks/rubyforge.rake +55 -0
  50. data/tasks/setup.rb +292 -0
  51. data/tasks/spec.rake +54 -0
  52. data/tasks/svn.rake +47 -0
  53. data/tasks/test.rake +40 -0
  54. data/tasks/zentest.rake +36 -0
  55. data/test/test-endian.rb +39 -0
  56. data/test/test-vector.rb +38 -0
  57. data/test/test.rb +433 -0
  58. metadata +126 -0
@@ -0,0 +1,77 @@
1
+ require 'bit-struct/vector'
2
+
3
+ class BitStruct
4
+ # Class for embedding a BitStruct::Vector as a field within a BitStruct.
5
+ # Declared with BitStruct.vector.
6
+ class VectorField < Field
7
+ # Used in describe.
8
+ def self.class_name
9
+ @class_name ||= "vector"
10
+ end
11
+
12
+ # Used in describe.
13
+ def class_name
14
+ @class_name ||= vector_class.name[/\w+$/]
15
+ end
16
+
17
+ # Returns the subclass of Vector that is used to manage the value of this
18
+ # field. If the class was specified in the BitStruct.vector declaration,
19
+ # #vector_class will return it, otherwise it will be an anonymous class
20
+ # (which you can assign to a constant to make nonymous ;).
21
+ def vector_class
22
+ @vector_class ||= options[:vector_class] || options["vector_class"]
23
+ end
24
+
25
+ def describe opts # :nodoc:
26
+ if opts[:expand]
27
+ opts = opts.dup
28
+ opts[:byte_offset] = offset / 8
29
+ opts[:omit_header] = opts[:omit_footer] = true
30
+ vector_class.describe(nil, opts) {|desc| yield desc}
31
+ else
32
+ super
33
+ end
34
+ end
35
+
36
+ def add_accessors_to(cl, attr = name) # :nodoc:
37
+ unless offset % 8 == 0
38
+ raise ArgumentError,
39
+ "Bad offset, #{offset}, for vector field #{name}." +
40
+ " Must be multiple of 8."
41
+ end
42
+
43
+ unless length % 8 == 0
44
+ raise ArgumentError,
45
+ "Bad length, #{length}, for vector field #{name}." +
46
+ " Must be multiple of 8."
47
+ end
48
+
49
+ offset_byte = offset / 8
50
+ length_byte = length / 8
51
+ last_byte = offset_byte + length_byte - 1
52
+ byte_range = offset_byte..last_byte
53
+
54
+ vc = vector_class
55
+
56
+ cl.class_eval do
57
+ define_method attr do ||
58
+ vc.new(self[byte_range])
59
+ end
60
+
61
+ define_method "#{attr}=" do |val|
62
+ if val.length != length_byte
63
+ raise ArgumentError, "Size mismatch in vector field assignment " +
64
+ "to #{attr} with value #{val.inspect}"
65
+ end
66
+
67
+ if val.class != vc
68
+ warn "Type mismatch in vector field assignment " +
69
+ "to #{attr} with value #{val.inspect}"
70
+ end
71
+
72
+ self[byte_range] = val
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,173 @@
1
+ # A Vector is, like a BitStruct, a String. It retains all of the String
2
+ # methods, except for #[], #[]=, and #each. These methods operate on entries
3
+ # instead of chars. Other methods, including #length and #slice, are unchanged.
4
+ # Hence a Vector can be used directly with sockets, binary files, etc.
5
+ #
6
+ # Note that Vector is not a subclass of BitStruct. It cannot be used in
7
+ # a #nest declaration in a BitStruct. Instead, use the #vector declaration.
8
+ # See BitStruct::VectorField.
9
+ #
10
+ # Different instances of the same Vector class may have different lengths, and
11
+ # a single instance can change its length. The length should always be a
12
+ # multiple of the struct size.
13
+ class BitStruct::Vector < String
14
+ include Enumerable
15
+
16
+ @default_options = {}
17
+ @struct_class = nil
18
+
19
+ class << self
20
+ def inherited cl
21
+ cl.instance_eval do
22
+ @struct_class = nil
23
+ end
24
+ end
25
+
26
+ # Called as a class method with a single argument in a user-defined
27
+ # subclass to specify a particular BitStruct class to use for each entry,
28
+ # instead of generating an anonymous class. Called without arguments to
29
+ # access the struct class, generating an anonymous one if needed.
30
+ # The struct_class inherits from the struct_class of the parent Vector
31
+ # class.
32
+ def struct_class cl = nil
33
+ if cl
34
+ if @struct_class
35
+ warn "changing struct_class in #{self} to #{cl}"
36
+ end
37
+ @struct_class = cl
38
+ @struct_class.default_options default_options
39
+ else
40
+ unless @struct_class
41
+ @struct_class = self == BitStruct::Vector ? BitStruct :
42
+ Class.new(superclass.struct_class)
43
+ @struct_class.default_options default_options
44
+ end
45
+ end
46
+ @struct_class
47
+ end
48
+
49
+ def method_missing(*a, &block) # :nodoc:
50
+ struct_class.send(*a, &block)
51
+ end
52
+
53
+ alias :orig_respond_to? :respond_to?
54
+ def respond_to?(*m) # :nodoc:
55
+ orig_respond_to?(*m) || struct_class.respond_to?(*m)
56
+ end
57
+
58
+ # Get or set the hash of default options for the class, which apply to all
59
+ # fields in the entries. If +h+ is provided, update the default options
60
+ # with that hash. Default options are inherited.
61
+ #
62
+ # This is especially useful with the <tt>:endian => val</tt> option.
63
+ def default_options h = nil
64
+ @default_options ||= superclass.default_options.dup
65
+ if h
66
+ @default_options.merge! h
67
+ if @struct_class
68
+ @struct_class.default_options h
69
+ end
70
+ end
71
+ @default_options
72
+ end
73
+
74
+ def describe(*args)
75
+ fmt = args[0] || BitStruct.describe_format
76
+ if block_given?
77
+ struct_class.describe(*args){|desc| yield desc}
78
+ yield ["..."]*5
79
+ else
80
+ struct_class.describe(*args) + [fmt % (["..."]*5)]
81
+ end
82
+ end
83
+ end
84
+
85
+ # Convenience method for instances. Returns the BitStruct class that
86
+ # describes each entry.
87
+ def struct_class
88
+ self.class.struct_class
89
+ end
90
+
91
+ # Convenience method for instances. Returns the string length in bytes of
92
+ # each entry in the vector.
93
+ def struct_class_length
94
+ self.class.struct_class.round_byte_length
95
+ end
96
+
97
+ # +arg+ can be an integer (number of entries) or a string
98
+ # (binary data, such as another Vector of the same size).
99
+ def initialize arg # :yields: instance
100
+ case arg
101
+ when Integer
102
+ super(struct_class.initial_value * arg)
103
+
104
+ else
105
+ begin
106
+ super arg
107
+ rescue NameError
108
+ raise ArgumentError, "must be string or integer: #{arg.inspect}"
109
+ end
110
+ end
111
+
112
+ yield self if block_given?
113
+ end
114
+
115
+ # Get the +i+-th entry. Returns a *copy* of the entry. If you want to
116
+ # use this copy to modify the entry, you must modify the copy and then
117
+ # use #[]= to replace the entry with the copy.
118
+ def [](i)
119
+ sc = self.class.struct_class
120
+ entry_length = sc.round_byte_length
121
+
122
+ unless (0...(length / entry_length)).include? i
123
+ raise ArgumentError, "index out of range: #{i}"
124
+ end
125
+
126
+ sc.new slice(entry_length * i, entry_length)
127
+ end
128
+
129
+ alias _old_replace_substr []=
130
+
131
+ # Set the +i+-th entry to +val+.
132
+ def []=(i,val)
133
+ entry_length = struct_class_length
134
+
135
+ unless (0...(length / entry_length)).include? i
136
+ raise ArgumentError, "index out of range: #{i}"
137
+ end
138
+
139
+ unless val.length == entry_length
140
+ raise ArgumentError, "wrong entry length: #{val.length} != #{entry_length}"
141
+ end
142
+
143
+ _old_replace_substr(entry_length * i, entry_length, val)
144
+ end
145
+
146
+ ## TODO: [i..j] etc.
147
+
148
+ # Iterate over entries.
149
+ def each
150
+ entry_length = struct_class_length
151
+ (length / entry_length).times do |i|
152
+ yield self[i]
153
+ end
154
+ end
155
+
156
+ def inspect(opts = BitStruct::DEFAULT_INSPECT_OPTS)
157
+ if opts[:include_class]
158
+ opts = opts.dup
159
+ opts[:include_class] = false
160
+ s = self.class.inspect + ": "
161
+ else
162
+ s = ""
163
+ end
164
+
165
+ s << entries.map{|entry| entry.inspect(opts)}.join(opts[:separator])
166
+ lb, rb = opts[:brackets]
167
+ [lb, s, rb].join
168
+ end
169
+
170
+ def inspect_detailed
171
+ inspect(BitStruct::DETAILED_INSPECT_OPTS)
172
+ end
173
+ end
@@ -0,0 +1,69 @@
1
+ require 'yaml'
2
+
3
+ class BitStruct
4
+ if RUBY_VERSION == "1.8.2"
5
+ def is_complex_yaml? # :nodoc:
6
+ true
7
+ end
8
+
9
+ YAML.add_ruby_type(/^bitstruct/) do |type, val|
10
+ subtype, subclass = YAML.read_type_class(type, Object)
11
+ subclass.new(val)
12
+ end
13
+
14
+ def to_yaml_type # :nodoc:
15
+ "!ruby/bitstruct:#{self.class}"
16
+ end
17
+
18
+ def to_yaml( opts = {} ) # :nodoc:
19
+ opts[:DocType] = self.class if Hash === opts
20
+ YAML.quick_emit(self.object_id, opts) do |out|
21
+ out.map(to_yaml_type) do |map|
22
+ fields.each do |field|
23
+ fn = field.name
24
+ map.add(fn, send(fn))
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ else
31
+ yaml_as "tag:path.berkeley.edu,2006:bitstruct"
32
+
33
+ def to_yaml_properties # :nodoc:
34
+ yaml_fields = fields.select {|field| field.inspectable?}
35
+ props = yaml_fields.map {|f| f.name.to_s}
36
+ if (rest_field = self.class.rest_field)
37
+ props << rest_field.name.to_s
38
+ end
39
+ props
40
+ end
41
+
42
+ # Return YAML representation of the BitStruct.
43
+ def to_yaml( opts = {} )
44
+ YAML::quick_emit( object_id, opts ) do |out|
45
+ out.map( taguri, to_yaml_style ) do |map|
46
+ to_yaml_properties.each do |m|
47
+ map.add( m, send( m ) )
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ def self.yaml_new( klass, tag, val ) # :nodoc:
54
+ unless Hash === val
55
+ raise YAML::TypeError, "Invalid BitStruct: " + val.inspect
56
+ end
57
+
58
+ bitstruct_name, bitstruct_type = YAML.read_type_class( tag, BitStruct )
59
+
60
+ st = bitstruct_type.new
61
+
62
+ val.each do |k,v|
63
+ st.send( "#{k}=", v )
64
+ end
65
+
66
+ st
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,80 @@
1
+
2
+ begin
3
+ require 'bones/smtp_tls'
4
+ rescue LoadError
5
+ require 'net/smtp'
6
+ end
7
+ require 'time'
8
+
9
+ namespace :ann do
10
+
11
+ # A prerequisites task that all other tasks depend upon
12
+ task :prereqs
13
+
14
+ file PROJ.ann.file do
15
+ ann = PROJ.ann
16
+ puts "Generating #{ann.file}"
17
+ File.open(ann.file,'w') do |fd|
18
+ fd.puts("#{PROJ.name} version #{PROJ.version}")
19
+ fd.puts(" by #{Array(PROJ.authors).first}") if PROJ.authors
20
+ fd.puts(" #{PROJ.url}") if PROJ.url.valid?
21
+ fd.puts(" (the \"#{PROJ.release_name}\" release)") if PROJ.release_name
22
+ fd.puts
23
+ fd.puts("== DESCRIPTION")
24
+ fd.puts
25
+ fd.puts(PROJ.description)
26
+ fd.puts
27
+ fd.puts(PROJ.changes.sub(%r/^.*$/, '== CHANGES'))
28
+ fd.puts
29
+ ann.paragraphs.each do |p|
30
+ fd.puts "== #{p.upcase}"
31
+ fd.puts
32
+ fd.puts paragraphs_of(PROJ.readme_file, p).join("\n\n")
33
+ fd.puts
34
+ end
35
+ fd.puts ann.text if ann.text
36
+ end
37
+ end
38
+
39
+ desc "Create an announcement file"
40
+ task :announcement => ['ann:prereqs', PROJ.ann.file]
41
+
42
+ desc "Send an email announcement"
43
+ task :email => ['ann:prereqs', PROJ.ann.file] do
44
+ ann = PROJ.ann
45
+ from = ann.email[:from] || Array(PROJ.authors).first || PROJ.email
46
+ to = Array(ann.email[:to])
47
+
48
+ ### build a mail header for RFC 822
49
+ rfc822msg = "From: #{from}\n"
50
+ rfc822msg << "To: #{to.join(',')}\n"
51
+ rfc822msg << "Subject: [ANN] #{PROJ.name} #{PROJ.version}"
52
+ rfc822msg << " (#{PROJ.release_name})" if PROJ.release_name
53
+ rfc822msg << "\n"
54
+ rfc822msg << "Date: #{Time.new.rfc822}\n"
55
+ rfc822msg << "Message-Id: "
56
+ rfc822msg << "<#{"%.8f" % Time.now.to_f}@#{ann.email[:domain]}>\n\n"
57
+ rfc822msg << File.read(ann.file)
58
+
59
+ params = [:server, :port, :domain, :acct, :passwd, :authtype].map do |key|
60
+ ann.email[key]
61
+ end
62
+
63
+ params[3] = PROJ.email if params[3].nil?
64
+
65
+ if params[4].nil?
66
+ STDOUT.write "Please enter your e-mail password (#{params[3]}): "
67
+ params[4] = STDIN.gets.chomp
68
+ end
69
+
70
+ ### send email
71
+ Net::SMTP.start(*params) {|smtp| smtp.sendmail(rfc822msg, from, to)}
72
+ end
73
+ end # namespace :ann
74
+
75
+ desc 'Alias to ann:announcement'
76
+ task :ann => 'ann:announcement'
77
+
78
+ CLOBBER << PROJ.ann.file
79
+
80
+ # EOF
@@ -0,0 +1,20 @@
1
+
2
+ if HAVE_BONES
3
+
4
+ namespace :bones do
5
+
6
+ desc 'Show the PROJ open struct'
7
+ task :debug do |t|
8
+ atr = if t.application.top_level_tasks.length == 2
9
+ t.application.top_level_tasks.pop
10
+ end
11
+
12
+ if atr then Bones::Debug.show_attr(PROJ, atr)
13
+ else Bones::Debug.show PROJ end
14
+ end
15
+
16
+ end # namespace :bones
17
+
18
+ end # HAVE_BONES
19
+
20
+ # EOF
@@ -0,0 +1,201 @@
1
+
2
+ require 'find'
3
+ require 'rake/packagetask'
4
+ require 'rubygems/user_interaction'
5
+ require 'rubygems/builder'
6
+
7
+ module Bones
8
+ class GemPackageTask < Rake::PackageTask
9
+ # Ruby GEM spec containing the metadata for this package. The
10
+ # name, version and package_files are automatically determined
11
+ # from the GEM spec and don't need to be explicitly provided.
12
+ #
13
+ attr_accessor :gem_spec
14
+
15
+ # Tasks from the Bones gem directory
16
+ attr_reader :bones_files
17
+
18
+ # Create a GEM Package task library. Automatically define the gem
19
+ # if a block is given. If no block is supplied, then +define+
20
+ # needs to be called to define the task.
21
+ #
22
+ def initialize(gem_spec)
23
+ init(gem_spec)
24
+ yield self if block_given?
25
+ define if block_given?
26
+ end
27
+
28
+ # Initialization tasks without the "yield self" or define
29
+ # operations.
30
+ #
31
+ def init(gem)
32
+ super(gem.name, gem.version)
33
+ @gem_spec = gem
34
+ @package_files += gem_spec.files if gem_spec.files
35
+ @bones_files = []
36
+
37
+ local_setup = File.join(Dir.pwd, %w[tasks setup.rb])
38
+ if !test(?e, local_setup)
39
+ Dir.glob(::Bones.path(%w[lib bones tasks *])).each {|fn| bones_files << fn}
40
+ end
41
+ end
42
+
43
+ # Create the Rake tasks and actions specified by this
44
+ # GemPackageTask. (+define+ is automatically called if a block is
45
+ # given to +new+).
46
+ #
47
+ def define
48
+ super
49
+ task :prereqs
50
+ task :package => ['gem:prereqs', "#{package_dir_path}/#{gem_file}"]
51
+ file "#{package_dir_path}/#{gem_file}" => [package_dir_path] + package_files + bones_files do
52
+ when_writing("Creating GEM") {
53
+ chdir(package_dir_path) do
54
+ Gem::Builder.new(gem_spec).build
55
+ verbose(true) {
56
+ mv gem_file, "../#{gem_file}"
57
+ }
58
+ end
59
+ }
60
+ end
61
+
62
+ file package_dir_path => bones_files do
63
+ mkdir_p package_dir rescue nil
64
+
65
+ gem_spec.files = (gem_spec.files +
66
+ bones_files.map {|fn| File.join('tasks', File.basename(fn))}).sort
67
+
68
+ bones_files.each do |fn|
69
+ base_fn = File.join('tasks', File.basename(fn))
70
+ f = File.join(package_dir_path, base_fn)
71
+ fdir = File.dirname(f)
72
+ mkdir_p(fdir) if !File.exist?(fdir)
73
+ if File.directory?(fn)
74
+ mkdir_p(f)
75
+ else
76
+ raise "file name conflict for '#{base_fn}' (conflicts with '#{fn}')" if test(?e, f)
77
+ safe_ln(fn, f)
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ def gem_file
84
+ if @gem_spec.platform == Gem::Platform::RUBY
85
+ "#{package_name}.gem"
86
+ else
87
+ "#{package_name}-#{@gem_spec.platform}.gem"
88
+ end
89
+ end
90
+ end # class GemPackageTask
91
+ end # module Bones
92
+
93
+ namespace :gem do
94
+
95
+ PROJ.gem._spec = Gem::Specification.new do |s|
96
+ s.name = PROJ.name
97
+ s.version = PROJ.version
98
+ s.summary = PROJ.summary
99
+ s.authors = Array(PROJ.authors)
100
+ s.email = PROJ.email
101
+ s.homepage = Array(PROJ.url).first
102
+ s.rubyforge_project = PROJ.rubyforge.name
103
+
104
+ s.description = PROJ.description
105
+
106
+ PROJ.gem.dependencies.each do |dep|
107
+ s.add_dependency(*dep)
108
+ end
109
+
110
+ PROJ.gem.development_dependencies.each do |dep|
111
+ s.add_development_dependency(*dep)
112
+ end
113
+
114
+ s.files = PROJ.gem.files
115
+ s.executables = PROJ.gem.executables.map {|fn| File.basename(fn)}
116
+ s.extensions = PROJ.gem.files.grep %r/extconf\.rb$/
117
+
118
+ s.bindir = 'bin'
119
+ dirs = Dir["{#{PROJ.libs.join(',')}}"]
120
+ s.require_paths = dirs unless dirs.empty?
121
+
122
+ incl = Regexp.new(PROJ.rdoc.include.join('|'))
123
+ excl = PROJ.rdoc.exclude.dup.concat %w[\.rb$ ^(\.\/|\/)?ext]
124
+ excl = Regexp.new(excl.join('|'))
125
+ rdoc_files = PROJ.gem.files.find_all do |fn|
126
+ case fn
127
+ when excl; false
128
+ when incl; true
129
+ else false end
130
+ end
131
+ s.rdoc_options = PROJ.rdoc.opts + ['--main', PROJ.rdoc.main]
132
+ s.extra_rdoc_files = rdoc_files
133
+ s.has_rdoc = true
134
+
135
+ if test ?f, PROJ.test.file
136
+ s.test_file = PROJ.test.file
137
+ else
138
+ s.test_files = PROJ.test.files.to_a
139
+ end
140
+
141
+ # Do any extra stuff the user wants
142
+ PROJ.gem.extras.each do |msg, val|
143
+ case val
144
+ when Proc
145
+ val.call(s.send(msg))
146
+ else
147
+ s.send "#{msg}=", val
148
+ end
149
+ end
150
+ end # Gem::Specification.new
151
+
152
+ Bones::GemPackageTask.new(PROJ.gem._spec) do |pkg|
153
+ pkg.need_tar = PROJ.gem.need_tar
154
+ pkg.need_zip = PROJ.gem.need_zip
155
+ end
156
+
157
+ desc 'Show information about the gem'
158
+ task :debug => 'gem:prereqs' do
159
+ puts PROJ.gem._spec.to_ruby
160
+ end
161
+
162
+ desc 'Write the gemspec '
163
+ task :spec => 'gem:prereqs' do
164
+ File.open("#{PROJ.name}.gemspec", 'w') do |f|
165
+ f.write PROJ.gem._spec.to_ruby
166
+ end
167
+ end
168
+
169
+ desc 'Install the gem'
170
+ task :install => [:clobber, 'gem:package'] do
171
+ sh "#{SUDO} #{GEM} install --local pkg/#{PROJ.gem._spec.full_name}"
172
+
173
+ # use this version of the command for rubygems > 1.0.0
174
+ #sh "#{SUDO} #{GEM} install --no-update-sources pkg/#{PROJ.gem._spec.full_name}"
175
+ end
176
+
177
+ desc 'Uninstall the gem'
178
+ task :uninstall do
179
+ installed_list = Gem.source_index.find_name(PROJ.name)
180
+ if installed_list and installed_list.collect { |s| s.version.to_s}.include?(PROJ.version) then
181
+ sh "#{SUDO} #{GEM} uninstall --version '#{PROJ.version}' --ignore-dependencies --executables #{PROJ.name}"
182
+ end
183
+ end
184
+
185
+ desc 'Reinstall the gem'
186
+ task :reinstall => [:uninstall, :install]
187
+
188
+ desc 'Cleanup the gem'
189
+ task :cleanup do
190
+ sh "#{SUDO} #{GEM} cleanup #{PROJ.gem._spec.name}"
191
+ end
192
+ end # namespace :gem
193
+
194
+
195
+ desc 'Alias to gem:package'
196
+ task :gem => 'gem:package'
197
+
198
+ task :clobber => 'gem:clobber_package'
199
+ remove_desc_for_task 'gem:clobber_package'
200
+
201
+ # EOF