juicer 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 (71) hide show
  1. data/History.txt +10 -0
  2. data/Manifest.txt +58 -0
  3. data/Rakefile +44 -0
  4. data/Readme.rdoc +143 -0
  5. data/bin/juicer +8 -0
  6. data/lib/juicer.rb +70 -0
  7. data/lib/juicer/binary.rb +173 -0
  8. data/lib/juicer/cache_buster.rb +45 -0
  9. data/lib/juicer/chainable.rb +106 -0
  10. data/lib/juicer/cli.rb +56 -0
  11. data/lib/juicer/command/install.rb +59 -0
  12. data/lib/juicer/command/list.rb +50 -0
  13. data/lib/juicer/command/merge.rb +185 -0
  14. data/lib/juicer/command/util.rb +32 -0
  15. data/lib/juicer/command/verify.rb +60 -0
  16. data/lib/juicer/core.rb +59 -0
  17. data/lib/juicer/css_cache_buster.rb +99 -0
  18. data/lib/juicer/install/base.rb +186 -0
  19. data/lib/juicer/install/jslint_installer.rb +51 -0
  20. data/lib/juicer/install/rhino_installer.rb +52 -0
  21. data/lib/juicer/install/yui_compressor_installer.rb +66 -0
  22. data/lib/juicer/jslint.rb +90 -0
  23. data/lib/juicer/merger/base.rb +74 -0
  24. data/lib/juicer/merger/css_dependency_resolver.rb +25 -0
  25. data/lib/juicer/merger/dependency_resolver.rb +82 -0
  26. data/lib/juicer/merger/javascript_dependency_resolver.rb +21 -0
  27. data/lib/juicer/merger/javascript_merger.rb +30 -0
  28. data/lib/juicer/merger/stylesheet_merger.rb +112 -0
  29. data/lib/juicer/minifyer/yui_compressor.rb +129 -0
  30. data/tasks/ann.rake +80 -0
  31. data/tasks/bones.rake +20 -0
  32. data/tasks/gem.rake +201 -0
  33. data/tasks/git.rake +40 -0
  34. data/tasks/notes.rake +27 -0
  35. data/tasks/post_load.rake +34 -0
  36. data/tasks/rdoc.rake +50 -0
  37. data/tasks/rubyforge.rake +55 -0
  38. data/tasks/setup.rb +300 -0
  39. data/tasks/spec.rake +54 -0
  40. data/tasks/svn.rake +47 -0
  41. data/tasks/test.rake +40 -0
  42. data/tasks/test/setup.rake +35 -0
  43. data/test/bin/jslint.js +474 -0
  44. data/test/bin/rhino1_7R1.zip +0 -0
  45. data/test/bin/rhino1_7R2-RC1.zip +0 -0
  46. data/test/bin/yuicompressor +238 -0
  47. data/test/bin/yuicompressor-2.3.5.zip +0 -0
  48. data/test/bin/yuicompressor-2.4.2.zip +0 -0
  49. data/test/juicer/command/test_install.rb +53 -0
  50. data/test/juicer/command/test_list.rb +69 -0
  51. data/test/juicer/command/test_merge.rb +155 -0
  52. data/test/juicer/command/test_util.rb +54 -0
  53. data/test/juicer/command/test_verify.rb +33 -0
  54. data/test/juicer/install/test_installer_base.rb +195 -0
  55. data/test/juicer/install/test_jslint_installer.rb +54 -0
  56. data/test/juicer/install/test_rhino_installer.rb +57 -0
  57. data/test/juicer/install/test_yui_compressor_installer.rb +56 -0
  58. data/test/juicer/merger/test_base.rb +122 -0
  59. data/test/juicer/merger/test_css_dependency_resolver.rb +36 -0
  60. data/test/juicer/merger/test_javascript_dependency_resolver.rb +39 -0
  61. data/test/juicer/merger/test_javascript_merger.rb +74 -0
  62. data/test/juicer/merger/test_stylesheet_merger.rb +178 -0
  63. data/test/juicer/minifyer/test_yui_compressor.rb +159 -0
  64. data/test/juicer/test_cache_buster.rb +58 -0
  65. data/test/juicer/test_chainable.rb +94 -0
  66. data/test/juicer/test_core.rb +47 -0
  67. data/test/juicer/test_css_cache_buster.rb +72 -0
  68. data/test/juicer/test_jslint.rb +33 -0
  69. data/test/test_helper.rb +146 -0
  70. data/test/test_juicer.rb +4 -0
  71. metadata +194 -0
@@ -0,0 +1,10 @@
1
+ == 0.2.0 / 2009-xx-xx
2
+
3
+ * Refactored the minifyers execute method from compress to save
4
+ * Refactored Juicer::Merger::FileMerger -> Juicer::Merger::Base
5
+ * Refactored the mergers and minifyers to be chainable commands.
6
+ * Added Chainable module
7
+
8
+ == 0.1.0 / 2008-12-17
9
+
10
+ * Dug up old project and set it up with Mr Bones
@@ -0,0 +1,58 @@
1
+ History.txt
2
+ Manifest.txt
3
+ Rakefile
4
+ Readme.rdoc
5
+ bin/juicer
6
+ lib/juicer.rb
7
+ lib/juicer/binary.rb
8
+ lib/juicer/cache_buster.rb
9
+ lib/juicer/chainable.rb
10
+ lib/juicer/cli.rb
11
+ lib/juicer/command/install.rb
12
+ lib/juicer/command/list.rb
13
+ lib/juicer/command/merge.rb
14
+ lib/juicer/command/util.rb
15
+ lib/juicer/command/verify.rb
16
+ lib/juicer/core.rb
17
+ lib/juicer/css_cache_buster.rb
18
+ lib/juicer/install/base.rb
19
+ lib/juicer/install/jslint_installer.rb
20
+ lib/juicer/install/rhino_installer.rb
21
+ lib/juicer/install/yui_compressor_installer.rb
22
+ lib/juicer/jslint.rb
23
+ lib/juicer/merger/base.rb
24
+ lib/juicer/merger/css_dependency_resolver.rb
25
+ lib/juicer/merger/dependency_resolver.rb
26
+ lib/juicer/merger/javascript_dependency_resolver.rb
27
+ lib/juicer/merger/javascript_merger.rb
28
+ lib/juicer/merger/stylesheet_merger.rb
29
+ lib/juicer/minifyer/yui_compressor.rb
30
+ tasks/test/setup.rake
31
+ test/bin/jslint.js
32
+ test/bin/rhino1_7R1.zip
33
+ test/bin/rhino1_7R2-RC1.zip
34
+ test/bin/yuicompressor
35
+ test/bin/yuicompressor-2.3.5.zip
36
+ test/bin/yuicompressor-2.4.2.zip
37
+ test/juicer/command/test_install.rb
38
+ test/juicer/command/test_list.rb
39
+ test/juicer/command/test_merge.rb
40
+ test/juicer/command/test_util.rb
41
+ test/juicer/command/test_verify.rb
42
+ test/juicer/install/test_installer_base.rb
43
+ test/juicer/install/test_jslint_installer.rb
44
+ test/juicer/install/test_rhino_installer.rb
45
+ test/juicer/install/test_yui_compressor_installer.rb
46
+ test/juicer/merger/test_base.rb
47
+ test/juicer/merger/test_css_dependency_resolver.rb
48
+ test/juicer/merger/test_javascript_dependency_resolver.rb
49
+ test/juicer/merger/test_javascript_merger.rb
50
+ test/juicer/merger/test_stylesheet_merger.rb
51
+ test/juicer/minifyer/test_yui_compressor.rb
52
+ test/juicer/test_cache_buster.rb
53
+ test/juicer/test_chainable.rb
54
+ test/juicer/test_core.rb
55
+ test/juicer/test_css_cache_buster.rb
56
+ test/juicer/test_jslint.rb
57
+ test/test_helper.rb
58
+ test/test_juicer.rb
@@ -0,0 +1,44 @@
1
+ # Look in the tasks/setup.rb file for the various options that can be
2
+ # configured in this Rakefile. The .rake files in the tasks directory
3
+ # are where the options are used.
4
+
5
+ begin
6
+ require 'bones'
7
+ load 'tasks/test/setup.rake'
8
+ Bones.setup
9
+ rescue LoadError
10
+ load 'tasks/setup.rb'
11
+ end
12
+
13
+ ensure_in_path 'lib'
14
+ require 'juicer'
15
+
16
+ task :default => 'test:run'
17
+
18
+ PROJ.name = 'juicer'
19
+ PROJ.authors = 'Christian Johansen'
20
+ PROJ.email = 'christian@cjohansen.no'
21
+ PROJ.url = 'http://www.cjohansen.no/en/projects/juicer'
22
+ PROJ.version = Juicer::VERSION
23
+ PROJ.rubyforge.name = 'juicer'
24
+ PROJ.readme_file = 'Readme.rdoc'
25
+ PROJ.exclude = %w(tmp$ bak$ ~$ CVS \.svn ^pkg ^doc \.git ^rcov ^test\/data gemspec ^test\/bin$)
26
+ PROJ.rdoc.remote_dir = 'juicer'
27
+
28
+ PROJ.spec.opts << '--color'
29
+
30
+ PROJ.gem.extras[:post_install_message] = <<-MSG
31
+ Juicer does not ship with third party libraries. You probably want to install
32
+ Yui Compressor and JsLint now:
33
+
34
+ juicer install yui_compressor
35
+ juicer install jslint
36
+
37
+ Happy juicing!
38
+ MSG
39
+
40
+ CLOBBER.include "test/data"
41
+
42
+ depend_on 'cmdparse'
43
+ depend_on 'hpricot'
44
+ depend_on 'rubyzip'
@@ -0,0 +1,143 @@
1
+ = Juicer
2
+ Official URL: http://github.com/cjohansen/juicer/tree/master
3
+ Christian Johansen (http://www.cjohansen.no)
4
+
5
+ == DESCRIPTION:
6
+
7
+ Juicer is a command line tool that helps you ship frontend code for production.
8
+
9
+ High level overview; Juicer can
10
+
11
+ * figure out which files depend on each other and merge them together, reducing
12
+ the number of http requests per page view, thus improving performance
13
+ * use YUI Compressor to compress code, thus improving performance
14
+ * verify that your JavaScript is safe to minify/compress by running JsLint on it
15
+ * cycle asset hosts in CSS files
16
+ * add "cache busters" to URLs in CSS files
17
+ * recalculate relative URLs in CSS files, as well as convert them to absolute
18
+ (or convert absolute URLs to relative URLs)
19
+
20
+ == FEATURES:
21
+
22
+ === Merging and minifying
23
+
24
+ Juicer can read @import statements in CSS files and use them to combine all your
25
+ stylesheets into a single file. This file may be minified using the YUI
26
+ Compressor. Eventually it will support other minifying tools too.
27
+
28
+ Juicer can treat your JavaScript files much the same way too, parsing a comment
29
+ switch @depend, as this example shows:
30
+
31
+ /**
32
+ * My script file
33
+ *
34
+ * @depend jquery-1.2.0.js
35
+ */
36
+ var myNS = {
37
+ myObject = {}
38
+ };
39
+
40
+ Running <tt>juicer merge</tt> on this file will result in a minified file
41
+ <tt>filename.min.js</tt> containing the file jquery-1.2.0.js (located in the
42
+ same directory) and the code above.
43
+
44
+ You can use @import (CSS files) and @depend (JavaScript) recursively, effectively
45
+ creating a dependency chain for Juicer to climb and merge.
46
+
47
+ === Paths
48
+
49
+ When merging CSS files, you may want to merge CSS files in different directories.
50
+ You may also want the resulting CSS file to end up in another directory as well.
51
+ Juicer automatically recalculates referenced URLs to reflect this change.
52
+
53
+ Absolute URLs are not changed by default, but if you provide juicer merge with
54
+ --document-root [DIR] and --relative-urls then absolute URLs are converted to
55
+ URLs relative to output directory. You can also use --absolute-urls to convert
56
+ all URLs to absolute ones.
57
+
58
+ === Cache busters
59
+
60
+ Juicer supports so-called cache busters. A cache buster is a pattern in a path
61
+ whose only purpose is to "trick" browsers to redownload a file when it has
62
+ changed in cases where a far future expires header is used.
63
+
64
+ There are two types of cache busters; soft ones add a parameter to the URL, like
65
+ so: http://assets/images/1.png?cb1234567890, ie the letters "cb" (as in cache
66
+ buster) and then the timestamp of the files mtime.
67
+
68
+ Unfortunately, the popular web proxy Squid shipped for some time with a default
69
+ configuration which would not treat a URL as a "new" URL if the only thing changed
70
+ was the GET parameters. For this reason Juicer provides hard cache busters.
71
+
72
+ Hard cache busters result in URLs such as http://assets/images/1-cb1234567890.png,
73
+ ie URLs that require either renaming of files, or (more conveniently) a web
74
+ server configuration that will forward URLs to the right files anyway.
75
+
76
+ == PLANNED FEATURES:
77
+
78
+ Juicer 0.2.0 is the first usable release. Work will continue from here. Improving
79
+ documentation and APIs is one concern, but there are also new features planned:
80
+
81
+ * Support more minifiers, JsMin (Ruby port), Packer and possibly others
82
+ * Add support for CssTidy to compress CSS files
83
+ * juicer build, a command that can build several files in one swoop using a
84
+ configuration file
85
+ * juicer doc, a command that produces documentation using YUI Doc or JsDoc
86
+
87
+ If you have any ideas, feature requests, want to contribute or whatever, fork
88
+ the project on github, or get in touch through christian (at) cjohansen.no.
89
+
90
+ == SYNOPSIS:
91
+
92
+ juicer merge myfile.css
93
+ -> Produces myfile.min.css which may contain several CSS files, minified
94
+
95
+ juicer merge myfile.js
96
+ -> Produces myfile.min.js, minified and combined
97
+
98
+ juicer help
99
+
100
+ == REQUIREMENTS:
101
+
102
+ In order to use YUI Compressor and JsMin (requires Rhino) you need Java
103
+ installed and the java executable available on your path.
104
+
105
+ == INSTALL:
106
+
107
+ $ gem install juicer
108
+ $ juicer install yui_compressor
109
+
110
+ You need Java installed and available on your PATH. During gem installation,
111
+ Juicer will download and install YUI Compressor, JsLint and Rhino for you.
112
+
113
+ == For developers
114
+
115
+ Before running tests you should run
116
+ rake test:setup
117
+
118
+ which brings in third party libraries (ie, requires a working network connection)
119
+
120
+ == LICENSE:
121
+
122
+ (The MIT License)
123
+
124
+ Copyright (c) 2008-2009 Christian Johansen
125
+
126
+ Permission is hereby granted, free of charge, to any person obtaining
127
+ a copy of this software and associated documentation files (the
128
+ 'Software'), to deal in the Software without restriction, including
129
+ without limitation the rights to use, copy, modify, merge, publish,
130
+ distribute, sublicense, and/or sell copies of the Software, and to
131
+ permit persons to whom the Software is furnished to do so, subject to
132
+ the following conditions:
133
+
134
+ The above copyright notice and this permission notice shall be
135
+ included in all copies or substantial portions of the Software.
136
+
137
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
138
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
139
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
140
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
141
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
142
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
143
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ require "rubygems"
3
+ dir = File.dirname(File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__)
4
+ base = File.expand_path(File.join(dir, %w[.. lib juicer]))
5
+ require base
6
+ require File.join(base, "cli")
7
+
8
+ Juicer::Cli.run(ARGV)
@@ -0,0 +1,70 @@
1
+ require "logger"
2
+
3
+ module Juicer
4
+
5
+ # :stopdoc:
6
+ VERSION = '0.2.0'
7
+ LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
8
+ PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
9
+ LOGGER = Logger.new(STDOUT)
10
+ @@home = nil
11
+ # :startdoc:
12
+
13
+ # Returns the version string for the library.
14
+ #
15
+ def self.version
16
+ VERSION
17
+ end
18
+
19
+ # Returns the installation directory for Juicer
20
+ #
21
+ def self.home
22
+ return @@home if @@home
23
+ return ENV['JUICER_HOME'] if ENV['JUICER_HOME']
24
+ return File.join(ENV['HOME'], ".juicer") if ENV['HOME']
25
+ return File.join(ENV['APPDATA'], "juicer") if ENV['APPDATA']
26
+ return File.join(ENV['HOMEDRIVE'], ENV['HOMEPATH'], "juicer") if ENV['HOMEDRIVE'] && ENV['HOMEPATH']
27
+ return File.join(ENV['USERPROFILE'], "juicer") if ENV['USERPROFILE']
28
+ return File.join(ENV['Personal'], "juicer") if ENV['Personal']
29
+ end
30
+
31
+ # Set home directory
32
+ #
33
+ def self.home=(home)
34
+ @@home = home
35
+ end
36
+
37
+ # Returns the library path for the module. If any arguments are given,
38
+ # they will be joined to the end of the libray path using
39
+ # <tt>File.join</tt>.
40
+ #
41
+ def self.libpath( *args )
42
+ args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
43
+ end
44
+
45
+ # Returns the lpath for the module. If any arguments are given,
46
+ # they will be joined to the end of the path using
47
+ # <tt>File.join</tt>.
48
+ #
49
+ def self.path( *args )
50
+ args.empty? ? PATH : ::File.join(PATH, args.flatten)
51
+ end
52
+
53
+ # Utility method used to require all files ending in .rb that lie in the
54
+ # directory below this file that has the same name as the filename passed
55
+ # in. Optionally, a specific _directory_ name can be passed in such that
56
+ # the _filename_ does not have to be equivalent to the directory.
57
+ #
58
+ def self.require_all_libs_relative_to( fname, dir = nil )
59
+ dir ||= ::File.basename(fname, '.*')
60
+ search_me = ::File.expand_path(::File.join(::File.dirname(fname), dir, '**', '*.rb'))
61
+
62
+ Dir.glob(search_me).sort.each { |rb| require rb }
63
+ end
64
+
65
+ end
66
+
67
+ Juicer.require_all_libs_relative_to(__FILE__)
68
+
69
+ class FileNotFoundError < Exception
70
+ end
@@ -0,0 +1,173 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "chainable"))
2
+
3
+ module Juicer
4
+
5
+ # Defines an abstract implementation of a binary that needs to be "shelled
6
+ # out" to be run. Provides a starting point when wrapping and API around a
7
+ # shell binary.
8
+ #
9
+ # The module requires the including class to define the default_options
10
+ # method. It should return a hash of options where options are keys and
11
+ # default values are the values. Only options defined in this hash will be
12
+ # allowed to set on the binary.
13
+ #
14
+ module Binary
15
+
16
+ # Initialize binary with options
17
+ # options = Hash of options, optional
18
+ #
19
+ def initialize(binary, options = {})
20
+ @options = self.respond_to?(:defualt_options) ? default_options.merge(options) : options
21
+ @opt_set = false
22
+ @command = nil
23
+ @binary = binary
24
+ @path = []
25
+ end
26
+
27
+ def path
28
+ @path
29
+ end
30
+
31
+ # Run command
32
+ #
33
+ def execute(params = nil)
34
+ #puts "#{self.command} #{params}"
35
+ cmd = IO.popen("#{self.command} #{params}", "r")
36
+ results = cmd.gets(nil)
37
+ cmd.close
38
+ results
39
+ end
40
+
41
+ # Return the value of a given option
42
+ # opt = The option to return value for
43
+ #
44
+ def get_opt(opt)
45
+ @options[opt] || nil
46
+ end
47
+
48
+ # Return options as a cli arguments string. Optionally accepts a list of
49
+ # options to exclude from the generated string
50
+ #
51
+ def options(*excludes)
52
+ excludes = excludes.flatten.collect { |exc| exc.to_sym }
53
+ @options.inject("") do |str, opt|
54
+ if opt[1].nil? || excludes.include?(opt[0].to_sym)
55
+ str
56
+ else
57
+ val = opt[1] == true ? '' : opt[1]
58
+ option = opt[0].to_s
59
+ option = (option.length == 1 ? "-" : "--") + option.gsub('_', '-')
60
+ "#{str} #{option} #{val}".strip
61
+ end
62
+ end
63
+ end
64
+
65
+ # Set an option. Important: you can only set options that are predefined by the
66
+ # implementing class
67
+ # opt = The option to set
68
+ # value = The value of the option
69
+ #
70
+ def set_opt(opt, value)
71
+ opt = opt.to_sym
72
+ if @options.key?(opt)
73
+ @options[opt] = value
74
+ @opt_set = true
75
+ else
76
+ msg = "Illegal option '#{opt}', specify one of: #{@options.keys.join(', ')}"
77
+ raise ArgumentError.new(msg)
78
+ end
79
+ end
80
+
81
+ # Performs simple parsing of a string of parameters. All recognized
82
+ # parameters are set, non-existent arguments raise an ArgumentError
83
+ #
84
+ def set_opts(options)
85
+ options = options.split " "
86
+ option = nil
87
+ regex = /^--?([^=]*)(=(.*))?/
88
+
89
+ while word = options.shift
90
+ if word =~ regex
91
+ if option
92
+ set_opt option, true
93
+ end
94
+
95
+ if $3
96
+ set_opt $1, $3
97
+ else
98
+ option = $1
99
+ end
100
+ else
101
+ set_opt option, word
102
+ option = nil
103
+ end
104
+ end
105
+ end
106
+
107
+ # Constructs the command to use
108
+ #
109
+ def command
110
+ return @command if !@opt_set && @command
111
+ @opt_set = false
112
+ @command = "#{@binary} #{options}"
113
+ end
114
+
115
+ # Locate the binary to execute. The binary is searched for in the
116
+ # following places:
117
+ #
118
+ # 1) The paths specified through my_binary.path << "/usr/bin"
119
+ # 2) The path specified by the given environment variable
120
+ # 3) Current working directory
121
+ #
122
+ # The name of the binary may be a glob pattern, resulting in +locate+
123
+ # returning an array of matches. This is useful in cases where the path
124
+ # is expected to store several versions oof a binary in the same directory,
125
+ # like /usr/bin/ruby /usr/bin/ruby1.8 /usr/bin/ruby1.9
126
+ #
127
+ # +locate+ always returns an array, or nil if no binaries where found.
128
+ # The result is always all files matching the given pattern in *one* of
129
+ # the specified paths - ie the first path where the pattern matches
130
+ # something.
131
+ #
132
+ def locate(bin_glob, env = nil)
133
+ path << ENV[env] if env && ENV.key?(env) && File.exist?(ENV[env])
134
+
135
+ (path << Dir.pwd).each do |path|
136
+ files = Dir.glob(File.expand_path(File.join(path, bin_glob)))
137
+ return files unless files.empty?
138
+ end
139
+
140
+ nil
141
+ end
142
+
143
+ # Allows for options to be set and read directly on the object as though they were
144
+ # standard attributes. compressor.verbose translates to
145
+ # compressor.get_opt('verbose') and compressor.verbose = true to
146
+ # compressor.set_opt('verbose', true)
147
+ def method_missing(m, *args)
148
+ if @options.key?(m)
149
+ # Only hit method_missing once per option
150
+ self.class.send(:define_method, m) do # def verbose
151
+ get_opt(m) # get_opt(:verbose)
152
+ end # end
153
+
154
+ return get_opt(m)
155
+ end
156
+
157
+ return super unless m.to_s =~ /=$/
158
+
159
+ opt = m.to_s.sub(/=$/, "").to_sym
160
+
161
+ if @options.key?(opt)
162
+ # Only hit method_missing once per option
163
+ self.class.send(:define_method, m) do # def verbose=(val)
164
+ set_opt(opt, args[0]) # set_opt(:verbose, val)
165
+ end # end
166
+
167
+ return set_opt(opt, args[0])
168
+ end
169
+
170
+ super
171
+ end
172
+ end
173
+ end