bit-struct 0.13.1

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 (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