bio-gem 1.2.1 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -3,7 +3,7 @@ source "http://rubygems.org"
3
3
  # Example:
4
4
  # gem "activesupport", ">= 2.3.5"
5
5
  gem "bundler", "~> 1.0.18"
6
- gem "jeweler", "~> 1.6.4"
6
+ gem "jeweler", ">= 1.7.0"
7
7
  gem "rdoc"
8
8
 
9
9
 
@@ -12,7 +12,6 @@ gem "rdoc"
12
12
  group :development do
13
13
  gem "shoulda", ">= 0"
14
14
  gem "bundler", "~> 1.0.18"
15
- gem "jeweler", "~> 1.6.4"
16
- gem "rcov", ">= 0"
15
+ gem "jeweler", ">= 1.7.0"
17
16
  gem "rdoc"
18
17
  end
@@ -2,13 +2,13 @@ GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
4
  git (1.2.5)
5
- jeweler (1.6.4)
5
+ jeweler (1.7.0)
6
6
  bundler (~> 1.0)
7
7
  git (>= 1.2.5)
8
8
  rake
9
+ rdoc
9
10
  json (1.6.4)
10
11
  rake (0.9.2.2)
11
- rcov (0.9.11)
12
12
  rdoc (3.12)
13
13
  json (~> 1.4)
14
14
  shoulda (2.11.3)
@@ -18,7 +18,6 @@ PLATFORMS
18
18
 
19
19
  DEPENDENCIES
20
20
  bundler (~> 1.0.18)
21
- jeweler (~> 1.6.4)
22
- rcov
21
+ jeweler (>= 1.7.0)
23
22
  rdoc
24
23
  shoulda
@@ -1,4 +1,4 @@
1
- Copyright (c) 2010 Raoul J.P. Bonnal
1
+ Copyright (c) 2010-2012 Raoul J.P. Bonnal
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -21,11 +21,15 @@ versioning, releasing it to github.com and/or rubygems.org and
21
21
  packaging. Bundler is used used for setting up a predefined developing
22
22
  environment.
23
23
 
24
- Also Biogem makes use of webservices. E.g.
24
+ Also Biogem makes use of webservices. Currently
25
25
 
26
- * GitHub.com and RubyGems.org
27
- are two different services and you need to create different accounts for them
28
- if you already use GitHub.com you are set for using Biogem
26
+ * GitHub.com
27
+ is used for maintaining the source tree, tracking changes and
28
+ issues. Create a github account if you don't have one.
29
+ * RubyGems.org
30
+ publishes your software for other people to install and use
31
+ * biogems.info
32
+ tracks all biogems, so people can find them
29
33
 
30
34
  == Installation
31
35
 
@@ -45,8 +49,12 @@ Also Biogem makes use of webservices. E.g.
45
49
  $ git config --global github.token "TOKEN ASSIGNED BY GITHUB"
46
50
 
47
51
  Note: another Ruby version management system used in BioRuby community is https://github.com/sstephenson/rbenv but for now we can not provide support for it.
52
+
48
53
  ==== IMPORTANT NOTE
49
- Rubygems will not let you install Biogem in an environment with a Ruby interpreter older than 1.9.X
54
+
55
+ Rubygems will not let you install Biogem in an environment with a Ruby
56
+ interpreter older than 1.9.X. Biogem can create gems for Ruby 1.8.7 -
57
+ but you need a recent version of Ruby and tools to run Biogem itself.
50
58
 
51
59
  === Download
52
60
 
@@ -95,6 +103,7 @@ Note: the above list of dependencies is just an example and it may vary from you
95
103
 
96
104
  During the installation you may note how Rubygems install the documentation for you, for each library installed.
97
105
  Is possible to access to all the documentations and API installed simply typing in the command line:
106
+
98
107
  $ gem server
99
108
  Server started at http://0.0.0.0:8808
100
109
  Server started at http://[::ffff:0.0.0.0]:8808
@@ -107,10 +116,12 @@ Note: the above link must be update with your current version of Biogem
107
116
  == Biogem Tutorial HowTo Develop a plugins
108
117
 
109
118
  Please follow the guide reported in tutorial https://github.com/helios/bioruby-gem/blob/master/Tutorial.rdoc, which is the most up to date version.
110
- You'll find out how to create:
119
+ You'll find out how to create
120
+
111
121
  * a simple plugin
112
122
  * embed a database
113
123
  * create a Biogem Engine to embed your gem into a Ruby on Rails web application
124
+
114
125
  and much more
115
126
 
116
127
 
@@ -121,11 +132,13 @@ and much more
121
132
  == Contributing to Biogem
122
133
 
123
134
  The source code repositories for Biogem and http://biogems.info
124
- website are on github.
135
+ website are on github
136
+
125
137
  * https://github.com/helios/bioruby-gem
126
138
  * https://github.com/pjotrp/biogems.info
127
- If you want to contribute, feel free! Clone the
128
- project!
139
+
140
+ Use Biogem for all purposes DRY. If you want to contribute, feel free! Clone the
141
+ project! Submit! Send us a pull request!
129
142
 
130
143
  == BioRuby's Wiki Official Documentation
131
144
 
@@ -171,9 +184,13 @@ e.g. biogem the-perfect-gem
171
184
  --rdoc use rdoc for documentation
172
185
  -h, --help display this help and exit
173
186
 
187
+ Recent versions of Biogem may have more options. For a full list run
188
+
189
+ bundle exec rake -T
190
+
174
191
  == Copyright
175
192
 
176
- Copyright (c) 2010, 2011 Raoul J.P. Bonnal. See LICENSE.txt for
193
+ Copyright (c) 2010-2012 Raoul J.P. Bonnal. See LICENSE.txt for
177
194
  further details.
178
195
 
179
196
 
data/Rakefile CHANGED
@@ -15,11 +15,11 @@ Jeweler::Tasks.new do |gem|
15
15
  gem.name = "bio-gem"
16
16
  gem.homepage = "http://github.com/helios/bioruby-gem"
17
17
  gem.license = "MIT"
18
- gem.summary = %Q{BioGem helps Bioinformaticians start developing plugins/modules for BioRuby creating a scaffold and a gem package}
19
- gem.description = %Q{BioGem is a scaffold generator for those Bioinformaticans who want to start coding an application or a library for using/extending BioRuby core library and sharing it through rubygems.org .
20
- The basic idea is to simplify and promote a modular approach to the BioRuby package.}
18
+ gem.summary = %Q{Biogem is a software generator for Ruby in bioinformatics}
19
+ gem.description = %Q{Biogem is a software generator for those bioinformaticans who want to start coding an application or a library for using/extending BioRuby core library and sharing it through rubygems.org .
20
+ The basic idea is to simplify and promote a modular approach to bioinformatics software development}
21
21
  gem.email = "ilpuccio.febo@gmail.com"
22
- gem.authors = ["Raoul J.P. Bonnal"]
22
+ gem.authors = ["Raoul J.P. Bonnal", "Pjotr Prins"]
23
23
  # Include your dependencies below. Runtime dependencies are required when using your gem,
24
24
  # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
25
25
  #gem.version='0.0.1'
@@ -46,12 +46,14 @@ Rake::TestTask.new(:test) do |test|
46
46
  test.verbose = true
47
47
  end
48
48
 
49
- require 'rcov/rcovtask'
50
- Rcov::RcovTask.new do |test|
51
- test.libs << 'test'
52
- test.pattern = 'test/**/test_*.rb'
53
- test.verbose = true
54
- end
49
+ # No proper rcov support in 1.9
50
+ #
51
+ # require 'rcov/rcovtask'
52
+ # Rcov::RcovTask.new do |test|
53
+ # test.libs << 'test'
54
+ # test.pattern = 'test/**/test_*.rb'
55
+ # test.verbose = true
56
+ # end
55
57
 
56
58
  task :default => :test
57
59
 
@@ -41,7 +41,7 @@ In case you are not connected to internet the following message will appear:
41
41
 
42
42
  Note the name of the plugin is important. Plugins are published as Ruby gems on http://rubygems.org/. All plugins that start with the name bio dash (bio-) are automatically listed on the Biogem website http://biogems.info/ !
43
43
 
44
- The first step is to open Rakefile and modify the gem.summary and gem.description.
44
+ The first step is to open the Rakefile and modify the gem.summary and gem.description.
45
45
 
46
46
  gem.summary = %Q{TODO: one-line summary of your gem}
47
47
  gem.description = %Q{TODO: longer description of your gem}
@@ -402,11 +402,11 @@ Biogem, like other frameworks, offers a bunch of predefined and common operation
402
402
 
403
403
  $ rake -T
404
404
 
405
- but because we are in a "development environment" is strongly suggested to use a very similar command
405
+ but because we are in a "development environment" we suggest to use
406
406
 
407
407
  $ bundle exec rake -T
408
408
 
409
- which guarantees that all the called programs/tasks will be executed inside the current development environment (bound to specific libraries versions). Follows the list of all available tasks for Biogem
409
+ which guarantees that all the called programs/tasks will be executed inside the current development environment (bound to specific libraries versions). rake -T displays the list of tasks
410
410
 
411
411
  rake build # Build gem into pkg/
412
412
  rake clobber_rcov # Remove rcov products for rcov
@@ -443,7 +443,6 @@ which guarantees that all the called programs/tasks will be executed inside the
443
443
  rake version:bump:patch # Bump the patch version by 1
444
444
  rake version:write # Writes out an explicit version.
445
445
 
446
-
447
446
  == Advanced Developers
448
447
 
449
448
  * Remember to modify .gitignore to exclude unwanted files.
@@ -463,5 +462,5 @@ which guarantees that all the called programs/tasks will be executed inside the
463
462
 
464
463
  == Copyright
465
464
 
466
- Copyright (c) 2010 Raoul J.P. Bonnal, Toshiaki Katayama, and Pjotr Prins. See LICENSE.txt for further details.
465
+ Copyright (c) 2010-2012 Raoul J.P. Bonnal, Toshiaki Katayama, and Pjotr Prins. See LICENSE.txt for further details.
467
466
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.2.1
1
+ 1.2.2
data/bin/biogem CHANGED
@@ -16,8 +16,16 @@ if (application_exit[:exit]==0)
16
16
  pwd = FileUtils.pwd
17
17
  FileUtils.cd "bioruby-#{application_exit[:options][:project_name]}"
18
18
  ARGV.clear << "install"
19
+
19
20
  Bundler::CLI.start
20
21
  #TODO: call rake directly not from shell
22
+ # print "Note: if rake gives an error try running biogem from an installed gem\n"
23
+ print "\trake version:write\n"
21
24
  sh "rake version:write"
25
+ print "\trake gemspec\n"
22
26
  sh "rake gemspec"
23
- end
27
+ print "Done!\n"
28
+ else
29
+ $stderr.print "\nERROR: Biogem failed!\n"
30
+ end
31
+
@@ -5,12 +5,12 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "bio-gem"
8
- s.version = "1.2.1"
8
+ s.version = "1.2.2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Raoul J.P. Bonnal"]
12
- s.date = "2012-01-05"
13
- s.description = "BioGem is a scaffold generator for those Bioinformaticans who want to start coding an application or a library for using/extending BioRuby core library and sharing it through rubygems.org .\n The basic idea is to simplify and promote a modular approach to the BioRuby package."
11
+ s.authors = ["Raoul J.P. Bonnal", "Pjotr Prins"]
12
+ s.date = "2012-02-16"
13
+ s.description = "Biogem is a software generator for those bioinformaticans who want to start coding an application or a library for using/extending BioRuby core library and sharing it through rubygems.org .\n The basic idea is to simplify and promote a modular approach to bioinformatics software development"
14
14
  s.email = "ilpuccio.febo@gmail.com"
15
15
  s.executables = ["biogem"]
16
16
  s.extra_rdoc_files = [
@@ -29,22 +29,31 @@ Gem::Specification.new do |s|
29
29
  "VERSION",
30
30
  "bin/biogem",
31
31
  "bio-gem.gemspec",
32
+ "doc/biogem-hacking.md",
32
33
  "lib/bio-gem.rb",
33
34
  "lib/bio-gem/application.rb",
35
+ "lib/bio-gem/generator/render.rb",
36
+ "lib/bio-gem/mod/biogem-rails.rb",
37
+ "lib/bio-gem/mod/biogem.rb",
34
38
  "lib/bio-gem/mod/jeweler.rb",
35
39
  "lib/bio-gem/mod/jeweler/github_mixin.rb",
36
40
  "lib/bio-gem/mod/jeweler/options.rb",
37
- "lib/bio-gem/templates/bin",
41
+ "lib/bio-gem/templates/README.rdoc",
42
+ "lib/bio-gem/templates/bin/bio-plugin",
38
43
  "lib/bio-gem/templates/database",
39
44
  "lib/bio-gem/templates/db_connection",
40
45
  "lib/bio-gem/templates/db_model",
41
46
  "lib/bio-gem/templates/engine",
47
+ "lib/bio-gem/templates/ffi/ext.c",
48
+ "lib/bio-gem/templates/ffi/ext.h",
42
49
  "lib/bio-gem/templates/foos_controller",
43
50
  "lib/bio-gem/templates/foos_view_example",
44
51
  "lib/bio-gem/templates/foos_view_index",
45
52
  "lib/bio-gem/templates/foos_view_new",
46
53
  "lib/bio-gem/templates/foos_view_show",
47
- "lib/bio-gem/templates/lib",
54
+ "lib/bio-gem/templates/gitignore",
55
+ "lib/bio-gem/templates/lib/bioruby-plugin.rb",
56
+ "lib/bio-gem/templates/lib/plugin.rb",
48
57
  "lib/bio-gem/templates/library",
49
58
  "lib/bio-gem/templates/migration",
50
59
  "lib/bio-gem/templates/rakefile",
@@ -59,38 +68,35 @@ Gem::Specification.new do |s|
59
68
  s.require_paths = ["lib"]
60
69
  s.required_ruby_version = Gem::Requirement.new("~> 1.9")
61
70
  s.rubygems_version = "1.8.10"
62
- s.summary = "BioGem helps Bioinformaticians start developing plugins/modules for BioRuby creating a scaffold and a gem package"
71
+ s.summary = "Biogem is a software generator for Ruby in bioinformatics"
63
72
 
64
73
  if s.respond_to? :specification_version then
65
74
  s.specification_version = 3
66
75
 
67
76
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
68
77
  s.add_runtime_dependency(%q<bundler>, ["~> 1.0.18"])
69
- s.add_runtime_dependency(%q<jeweler>, ["~> 1.6.4"])
78
+ s.add_runtime_dependency(%q<jeweler>, [">= 1.7.0"])
70
79
  s.add_runtime_dependency(%q<rdoc>, [">= 0"])
71
80
  s.add_development_dependency(%q<shoulda>, [">= 0"])
72
81
  s.add_development_dependency(%q<bundler>, ["~> 1.0.18"])
73
- s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
74
- s.add_development_dependency(%q<rcov>, [">= 0"])
82
+ s.add_development_dependency(%q<jeweler>, [">= 1.7.0"])
75
83
  s.add_development_dependency(%q<rdoc>, [">= 0"])
76
84
  else
77
85
  s.add_dependency(%q<bundler>, ["~> 1.0.18"])
78
- s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
86
+ s.add_dependency(%q<jeweler>, [">= 1.7.0"])
79
87
  s.add_dependency(%q<rdoc>, [">= 0"])
80
88
  s.add_dependency(%q<shoulda>, [">= 0"])
81
89
  s.add_dependency(%q<bundler>, ["~> 1.0.18"])
82
- s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
83
- s.add_dependency(%q<rcov>, [">= 0"])
90
+ s.add_dependency(%q<jeweler>, [">= 1.7.0"])
84
91
  s.add_dependency(%q<rdoc>, [">= 0"])
85
92
  end
86
93
  else
87
94
  s.add_dependency(%q<bundler>, ["~> 1.0.18"])
88
- s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
95
+ s.add_dependency(%q<jeweler>, [">= 1.7.0"])
89
96
  s.add_dependency(%q<rdoc>, [">= 0"])
90
97
  s.add_dependency(%q<shoulda>, [">= 0"])
91
98
  s.add_dependency(%q<bundler>, ["~> 1.0.18"])
92
- s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
93
- s.add_dependency(%q<rcov>, [">= 0"])
99
+ s.add_dependency(%q<jeweler>, [">= 1.7.0"])
94
100
  s.add_dependency(%q<rdoc>, [">= 0"])
95
101
  end
96
102
  end
@@ -0,0 +1,396 @@
1
+ # Hacking biogem
2
+
3
+ Biogem is a Ruby code generator for bioinformatics. It generates a plugin, in
4
+ the form of a gem, which is published automatically on both github and
5
+ rubygems.org.
6
+
7
+ In this document we discuss ways to modify Biogem, so you can generate your own
8
+ code, and avoid repetitious work. The design of the biogem code generator is based on
9
+ templates, and there are accessible ways to hack it, or even add your own templates.
10
+
11
+ This document is divided into two sections. In the first section we will create
12
+ a directory, generate a file through a template, and add a test through a
13
+ helper. In the second section we will modify some undesired behaviour in biogem
14
+ through meta-programming.
15
+
16
+ ## Check out the source
17
+
18
+
19
+ To change biogem, checkout the source tree to your local machine. E.g.
20
+
21
+ ```sh
22
+ git clone https://github.com/helios/bioruby-gem.git
23
+ cd bioruby-gem
24
+ bundle
25
+ ```
26
+
27
+ Make sure you are running a supported version of Ruby (check the README).
28
+ Now you can invoke biogem with
29
+
30
+ ```sh
31
+ bundle exec ./bin/biogem foo
32
+ ```
33
+
34
+ which will create the bioruby-foo plugin for testing. Every time you rerun biogem, make
35
+ sure to remove the bioruby-foo directory first
36
+
37
+ ```sh
38
+ rm -rf bioruby-foo
39
+ ```
40
+
41
+ Recommended biogem switches are --with-bin and --rspec
42
+
43
+ ```sh
44
+ bundle exec ./bin/biogem --with-bin --rspec foo
45
+ ```
46
+
47
+ Note that we are running biogem here within bundler. This may cause a rakefile
48
+ error after generating the plugin (nesting bundler is not a good idea). This can simply be fixed by running the rake by hand in the plugin directory after generation
49
+
50
+ ```sh
51
+ cd bioruby-foo
52
+ bundle
53
+ bundle exec rake version:write
54
+ bundle exec rake gemspec
55
+ ```
56
+
57
+ Alternatively, install an updated version of biogem, and run biogem without
58
+ bundler with
59
+
60
+ ```sh
61
+ bundle exec rake install
62
+ biogem --with-bin --rspec foo
63
+ ```
64
+
65
+ ## Invoking the Biogem code generator
66
+
67
+ In the file ./bin/biogem rake, jeweler and bundler support are loaded and
68
+ Bio::Gem::Generator::Application invoked, which generates the new directory and
69
+ files. After generating code biogem changes directory and runs some rake
70
+ commands in the newly generated plugin.
71
+
72
+ ## Add an CLI option to Biogem
73
+
74
+ In the first step we want to add a switch to the biogem command line. For our
75
+ purpose we will add --with-ffi, a switch which will create a template for a foreign
76
+ function interface. Switches are defined in [options.rb](https://github.com/helios/bioruby-gem/blob/master/lib/bio-gem/mod/jeweler/options.rb). We add
77
+ a switch with
78
+
79
+ ```ruby
80
+ o.on('--with-ffi', 'generate a foreign function interface (FFI)') do
81
+ self[:biogem_ffi] = true
82
+ end
83
+ ```
84
+
85
+ This switch will be available as *options[:biogem_ffi]* further on.
86
+
87
+ ## Create a directory
88
+
89
+ In the method *create_files* in Biogem [jeweler.rb](https://github.com/helios/bioruby-gem/blob/master/lib/bio-gem/mod/jeweler.rb) directories and files get
90
+ created. For example the plugin library file is generated with
91
+
92
+ ```ruby
93
+ # Fill lib/bio-plugin.rb with some default comments
94
+ output_template_in_target_generic 'lib', File.join(lib_dir, lib_filename)
95
+ ```
96
+
97
+ which also creates the directory. We explicitly add a directory to store C
98
+ source files and headers with
99
+
100
+ ```ruby
101
+ create_ffi_structure if options[:biogem_ffi]
102
+ ```
103
+
104
+ and
105
+
106
+ ```ruby
107
+ def create_ffi_structure
108
+ # create ./ext/src and ./ext/include for the .c and .h files
109
+ mkdir_in_target(ext_dir)
110
+ mkdir_in_target(File.join(ext_dir,"src"))
111
+ # create ./lib/ffi for the Ruby ffi
112
+ mkdir_in_target(File.join(lib_dir,"ffi"))
113
+ end
114
+ ```
115
+
116
+ ## Generate file from template
117
+
118
+ Templates are stored in lib/bio-gem/templates. We create a template for
119
+ our C extension named [ext.c](https://github.com/helios/bioruby-gem/tree/master/lib/bio-gem/templates/ffi/ext.c), e.g. the C function
120
+
121
+ ```ruby
122
+ int add_one(int number) {
123
+ return number + 1;
124
+ }
125
+ ```
126
+
127
+ which gets copied into the plugins ./ext/src directory with
128
+
129
+ ```ruby
130
+ output_template_in_target_generic File.join('ffi','ext.c'), File.join(src_dir, "ext.c" )
131
+ ```
132
+
133
+ Likewise, an include file ext.h gets copied, a Makefile, and the Ruby ffi file, which defines the bindings to ext.c.
134
+
135
+ (to be continued)
136
+
137
+ ## Modify a generated file with a helper
138
+
139
+ Similar to Ruby on Rails, we use erb to modify templates based on input parameters.
140
+ Erb is part of the Ruby [standard library](http://ruby-doc.org/stdlib-1.9.3/libdoc/erb/rdoc/ERB.html).
141
+ To use erb we create helper functions. A good example is the main library file that
142
+ gets included by everyone using your plugin using
143
+
144
+ ```ruby
145
+ require 'bio-myawesomeplugin'
146
+ ```
147
+
148
+ The generated file is in your module *lib* directory. The template for that file can be found [here](https://github.com/pjotrp/bioruby-gem/blob/master/lib/bio-gem/templates/lib/bioruby-plugin.rb).
149
+ Another example generates the
150
+ binary from a [template](https://github.com/pjotrp/bioruby-gem/blob/master/lib/bio-gem/templates/bin/bio-plugin), when generating with the --with-bin switch. It contains the line
151
+
152
+ ```ruby
153
+ require '<%= project_name %>'
154
+ ```
155
+
156
+ *project_name* is a helper, a method which is defined in *lib/bio-gem/mod/jeweler.rb* as
157
+
158
+ ```ruby
159
+ alias original_project_name project_name
160
+ def project_name
161
+ name = original_project_name
162
+ return 'bio-'+name if name !~ /^bio-/
163
+ name
164
+ end
165
+ ```
166
+
167
+ Here, original_project_name is the original method in jeweler. The main thing to note is that you
168
+ can easily create your own helpers - they are available in the erb based templates when they
169
+ exist in the Jeweler::Generator namespace.
170
+
171
+ ## Adapt the Rakefile
172
+
173
+ For our FFI (DRY) the Rakefile needs to be adapted to compile the C file(s) properly. For this
174
+ implementatin I am adding a working example of a C binding, similar to what we do for tests.
175
+
176
+ (to be continued)
177
+
178
+ # Hacking jeweler for Biogem
179
+
180
+ The following section discusses surgical changes to biogem.
181
+
182
+ ''Warning, the rest of this document is about Ruby meta-programming. It is not for the faint of
183
+ heart.''
184
+
185
+ Biogem builds on [Jeweler](https://github.com/technicalpickles/jeweler).
186
+
187
+ jeweler comes with a library for managing and releasing RubyGem projects, and
188
+ a scaffold generator for starting new RubyGem projects. Using typical Ruby
189
+ overrides of jeweler methods, also known as meta-programming, Biogem subverts
190
+ Jeweler for our bioinformatics needs (see jeweler::Generator.new example below).
191
+
192
+ ## Invoking the Biogem code generator
193
+
194
+ In the file ./bin/biogem rake, jeweler and bundler support are loaded and
195
+ Bio::Gem::Generator::Application invoked, which generates the new directory and
196
+ files. Thereafter biogem changes directory and runs some rake commands.
197
+
198
+ ## Inside Bio::Gem::Generator::Application
199
+
200
+ First Jeweler::Generator.run is run, so the basic scaffolding exists for Rake,
201
+ tests etc. Nothing special so far. Where it gets interesting is that biogem
202
+ overrides Jeweler classes in [./lib/bio-gem/mod/jeweler.rb](https://github.com/helios/bioruby-gem/blob/master/lib/bio-gem/mod/jeweler.rb). In this file, at runtime,
203
+ Jeweler::Generator.new is replaced with our own version, which calls the
204
+ original first, but continues to plug in information. Any time jeweler::Generator.new is called,
205
+ our edition is called. Even from within jeweler!
206
+
207
+ It is important to check out this file, as many overrides are defined here.
208
+ Also have a look at the *create_files* function. That is where directories and
209
+ files are generated from templates.
210
+
211
+ ## Biogem options
212
+
213
+ The application generator is programmed from biogem command line options. These
214
+ options are listed in [jeweler/options.rb](https://github.com/helios/bioruby-gem/blob/master/lib/bio-gem/mod/jeweler/options.rb).
215
+
216
+ ## Biogem templates
217
+
218
+ Biogem templates are listed in [./lib/bio-gem/templates](https://github.com/helios/bioruby-gem/tree/master/lib/bio-gem/templates). These templates use erb to tune content within.
219
+
220
+ Templates are by in the jeweler.rb override (described above). For example the Rakefile is
221
+ generated with
222
+
223
+ ```ruby
224
+ output_template_in_target 'Rakefile'
225
+ ```
226
+
227
+ it is all fairly straightforward.
228
+
229
+ ## Check out the jeweler source code
230
+
231
+ From the above you can see how we reprogram jeweler for our needs. To find new
232
+ ways of generating code, we strongly suggest to also check out the [jeweler
233
+ source code](https://github.com/technicalpickles/jeweler/tree/master/lib). The
234
+ jeweler code base is well thought out, and stable.
235
+
236
+ ## Changing jeweler behaviour
237
+
238
+ Just as an example we are going to override code generated by Jeweler. Jeweler generates
239
+ a dependency for rcov, a Ruby code coverage analyzer. We are going to remove this dependency,
240
+ without touching the Jeweler code base.
241
+
242
+ In the Jeweler source code tree rcov is used in two files:
243
+
244
+ ```ruby
245
+ grep -r rcov *
246
+ jeweler/generator.rb: development_dependencies << ["rcov", ">= 0"]
247
+ jeweler/templates/other_tasks.erb:RSpec::Core::RakeTask.new(:rcov) do |spec|
248
+ jeweler/templates/other_tasks.erb: spec.rcov = true
249
+ jeweler/templates/other_tasks.erb:Micronaut::RakeTask.new(:rcov) do |examples|
250
+ jeweler/templates/other_tasks.erb: examples.rcov_opts = '-Ilib -I<%= test_dir %>'
251
+ jeweler/templates/other_tasks.erb: examples.rcov = true
252
+ jeweler/templates/other_tasks.erb:require 'rcov/rcovtask'
253
+ jeweler/templates/other_tasks.erb: <%= test_task %>.rcov_opts << '--exclude "gems/*"'
254
+ ```
255
+
256
+ The first step is to remove the rcov entry from development_dependencies. This can be
257
+ done by adding a line in Biogems lib/bio-gem/mod/jeweler.rb. Change it to
258
+
259
+ ```ruby
260
+ class Jeweler
261
+ class Generator
262
+ alias original_initialize initialize
263
+ def initialize(options = {})
264
+ original_initialize(options)
265
+ development_dependencies << ["bio", ">= 1.4.2"]
266
+ development_dependencies.delete_if { |k,v| k == "rcov" }
267
+ (...)
268
+ ```
269
+
270
+ You can see here that BioRuby support is always added. The next step is to change
271
+ the behaviour of jeweler/templates/other_tasks.erb. The code to generate the
272
+ Rakefile lists is
273
+
274
+ ```ruby
275
+ <% case testing_framework %>
276
+ <% when :rspec %>
277
+ (...)
278
+ <% when :micronaut %>
279
+ (...)
280
+ <% else %>
281
+ require 'rcov/rcovtask'
282
+ Rcov::RcovTask.new do |<%= test_task %>|
283
+ (...)
284
+ end
285
+ <% end %>
286
+ ```
287
+
288
+ and, annoyingly, shows that rcov is always added by default (in the final
289
+ 'else'). We should communicate with the author of Jeweler to fix this. However, we
290
+ also have the option to override the Rakefile generator. The jeweler Rakefile
291
+ template has the form
292
+
293
+ ```ruby
294
+ require 'rubygems'
295
+ <%= render_template 'bundler_setup.erb' %>
296
+ require 'rake'
297
+ <%= render_template 'jeweler_tasks.erb' %>
298
+ <%= render_template 'other_tasks.erb' %>
299
+ ```
300
+
301
+ The two important functions in jeweler.rb are:
302
+
303
+ ```ruby
304
+ def render_template(source)
305
+ template_contents = File.read(File.join(template_dir, source))
306
+ template = ERB.new(template_contents, nil, '<>')
307
+ # squish extraneous whitespace from some of the conditionals
308
+ template.result(binding).gsub(/\n\n\n+/, "\n\n")
309
+ end
310
+
311
+ def output_template_in_target(source, destination = source)
312
+ final_destination = File.join(target_dir, destination)
313
+ template_result = render_template(source)
314
+ File.open(final_destination, 'w') {|file| file.write(template_result)}
315
+ $stdout.puts "\tcreate\t#{destination}"
316
+ end
317
+ ```
318
+
319
+ these find the templates and render them through ERB.
320
+
321
+ Naturally, Biogem has needed some overriding behaviour. In this case Biogems jeweler.rb
322
+ has
323
+
324
+ ```ruby
325
+ def output_template_in_target_generic_update(source, destination = source, template_dir = template_dir_biogem)
326
+ final_destination = File.join(target_dir, destination)
327
+ template_result = render_template_generic(source, template_dir)
328
+ File.open(final_destination, 'a') {|file| file.write(template_result)}
329
+ $stdout.puts "\tcreate\t#{destination}"
330
+ end
331
+ ```
332
+
333
+ and, in the case of the --with-db option, the Rakefile already gets modified by Biogem
334
+
335
+ ```ruby
336
+ output_template_in_target_generic 'rakefile', 'Rakefile', template_dir_biogem
337
+ ```
338
+
339
+ So, what would be the best route here, to change biogem behaviour? We have to rewrite
340
+ the Rakefile template to remove the rcov lines. We can
341
+ change the *render_template* to allow rewriting the template. Unfortunately there is no
342
+ existing hook for that in jeweler. So, let us inject a hook named *after_render_template*
343
+ to a *render_template* override. First we open the Jeweler::Generator class and move the method to biogem jeweler.rb, renaming the original method to original_render_template:
344
+
345
+ ```ruby
346
+ class Jeweler
347
+ class Generator
348
+ alias original_render_template render_template
349
+ def render_template(source)
350
+ buf = original_render_template(source)
351
+ # call hook (returns edited buf)
352
+ after_render_template(source,buf)
353
+ end
354
+
355
+ # new hook for removing stuff
356
+ def after_render_template(source,buf)
357
+ if source == 'other_tasks.erb'
358
+ # remove rcov related lines
359
+ buf.gsub!(/require 'rcov/rcovtask'/,'')
360
+ (...)
361
+ end
362
+ end
363
+ ```
364
+
365
+ you probably get the gist (the stuff you can do with Ruby meta-programming!).
366
+ The solution chosen overrides original jeweler behaviour without touching
367
+ jeweler itself. Naturally, if it can be handled in jeweler, it is strongly
368
+ preferred. With our solution a small change in jeweler may now break biogem
369
+ (in software engineering terms: the fix is brittle).
370
+
371
+ In fact, the jeweler author has responded that the default behaviour for rcov will change now. I.e.
372
+ our fix will go upstream.
373
+
374
+ Still, for stuff that will not go into jeweler, this is a way of changing
375
+ behaviour.
376
+
377
+ # DRY (Do not repeat yourself)
378
+
379
+ This document should help you preventing repeating yourself. Code generation
380
+ can be very useful. When you have something that is useful to yourself, or
381
+ others, and is bioinformatics related, add it to biogem. When it is more
382
+ generic, add it to jeweler. You may make a lot of people happy.
383
+
384
+ # More on meta-programming
385
+
386
+ Thanks to Ruby meta-programming we do not have to change jeweler. With another
387
+ computer language, we would have cloned jeweler and modified the source code
388
+ for our purposes. This would imply a fork of the code base - and the projects
389
+ would have diverged irrevocably. As it stands, we can build on the existing
390
+ jeweler project. Some 'brittleness' may get introduced, as explained above, but in
391
+ general we should normally be able to continue adapting our code base to that
392
+ of jeweler.
393
+
394
+ The Pragmatic programmers book on [Ruby metaprogramming](http://www.amazon.com/Metaprogramming-Ruby-Program-Like-Pros/dp/1934356476/ref=cm_cr_pr_product_top) is recommended reading.
395
+
396
+ Copyright (C) 2012 Pjotr Prins <pjotr.prins@thebird.nl>