youandme 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.
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem 'getopt', "~> 1.4.1"
4
+ gem 'rpeg-multimarkdown', '~> 0.1.1', :require => 'multimarkdown'
5
+ gem 'libxslt-ruby', '~> 1.0.8 '
6
+
7
+ group :development do
8
+ gem "shoulda", ">= 0"
9
+ gem "bundler", "~> 1.0.0"
10
+ gem "jeweler", "~> 1.6.4"
11
+ gem "rcov", ">= 0"
12
+ end
@@ -0,0 +1,28 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ getopt (1.4.1)
5
+ git (1.2.5)
6
+ jeweler (1.6.4)
7
+ bundler (~> 1.0)
8
+ git (>= 1.2.5)
9
+ rake
10
+ libxml-ruby (2.2.2)
11
+ libxslt-ruby (1.0.8)
12
+ libxml-ruby (>= 2.2.2)
13
+ rake (0.9.2.2)
14
+ rcov (0.9.11)
15
+ rpeg-multimarkdown (0.1.1)
16
+ shoulda (2.11.3)
17
+
18
+ PLATFORMS
19
+ ruby
20
+
21
+ DEPENDENCIES
22
+ bundler (~> 1.0.0)
23
+ getopt (~> 1.4.1)
24
+ jeweler (~> 1.6.4)
25
+ libxslt-ruby (~> 1.0.8)
26
+ rcov
27
+ rpeg-multimarkdown (~> 0.1.1)
28
+ shoulda
@@ -0,0 +1,13 @@
1
+ Copyright 2011 Preston Lee
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
@@ -0,0 +1,23 @@
1
+ # youandme
2
+
3
+ An unofficial Ruby library and command-line application ("youandme") for quickly parsing 23andme raw data files into a plain Ruby structures for quick processing and analysis.
4
+
5
+ ## Installation ##
6
+
7
+ gem install youandme
8
+
9
+ ## Command-Line Usage
10
+
11
+ The primary command-line script is "youandme", which generates a simple side-by-side comparison report for two given 23andme raw data files. To generate the reports, grab a few raw 23andme data files (from 23andme.com, SNPedia etc.), and compare them like so:
12
+
13
+ bin/youandme --directory <output_directory> --left <23andme_data_file.txt> --right <23andme_data_file.txt>
14
+
15
+ For "full" files, this will take a LONG time to run. (As in, probably more than 24 hours.) I recommend breaking down the data files into chromosome-size chunks, and running each comparison through this script individually.
16
+
17
+ ## Authors ##
18
+
19
+ Preston Lee
20
+
21
+ ## Copyright
22
+
23
+ Copyright (c) 2011 Preston Lee. See LICENSE.txt for further details.
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "youandme"
18
+ gem.homepage = "http://github.com/preston/youandme"
19
+ gem.license = "Apache 2.0"
20
+ gem.summary = %Q{Data comparison and analysis tools for 23andme raw data files.}
21
+ gem.description = %Q{An unofficial ruby library for quickly parsing 23andme raw data files into a plain Ruby structures for quick processing and analysis.}
22
+ gem.email = "conmotto@gmail.com"
23
+ gem.authors = ["Preston Lee"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+
35
+ require 'rcov/rcovtask'
36
+ Rcov::RcovTask.new do |test|
37
+ test.libs << 'test'
38
+ test.pattern = 'test/**/test_*.rb'
39
+ test.verbose = true
40
+ test.rcov_opts << '--exclude "gems/*"'
41
+ end
42
+
43
+ task :default => :test
44
+
45
+ require 'rdoc/task'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "youandme #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.0
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # An script to compare two 23andme SNP data files.
4
+ #
5
+ # Author: Preston Lee
6
+ # License: Apache 2
7
+
8
+ # Runtime libraries:
9
+ require 'erb'
10
+
11
+ # 3rd-party libraries:
12
+ require 'getopt/long'
13
+ require 'multimarkdown'
14
+
15
+ # Our libraries:
16
+ current_dir = File.dirname(File.expand_path(__FILE__))
17
+ gem_dir = File.join(current_dir, '..')
18
+ lib_path = File.join(gem_dir, 'lib')
19
+ $LOAD_PATH.unshift lib_path
20
+ require 'youandme'
21
+
22
+
23
+ def print_help_and_exit
24
+ puts "Usage:"
25
+ puts "\t#{$0} --directory <output_directory> --left <23andme_data_file.txt> --right <23andme_data_file.txt>"
26
+ puts "\t#{$0} -d <output_directory> -l <23andme_data_file.txt> -r <23andme_data_file.txt>"
27
+ exit(1)
28
+ end
29
+
30
+
31
+ begin
32
+ opt = Getopt::Long.getopts(
33
+ ["--left", "-l", Getopt::REQUIRED],
34
+ ["--right", "-r", Getopt::REQUIRED],
35
+ ["--directory", "-d", Getopt::REQUIRED],
36
+ ["--help", "-h", Getopt::BOOLEAN]
37
+ )
38
+ rescue
39
+ print_help_and_exit
40
+ end
41
+
42
+
43
+
44
+ if(opt['help'])
45
+ print_help_and_exit
46
+ end
47
+
48
+ puts "Checking data file existyness..."
49
+ loader = YouAndMe::RawDataFileLoader.new
50
+ left_file = opt['left']
51
+ right_file = opt['right']
52
+ unless(loader.check_file(left_file) and loader.check_file(right_file))
53
+ puts "Please specify valid data files!"
54
+ print_help_and_exit
55
+ end
56
+
57
+ puts "Parsing data files... (may take a while)"
58
+ max_rows = 1000
59
+ left = loader.load_file(left_file, max_rows).sort{|a,b| a[:rsid] <=> b[:rsid]}
60
+ puts "\tLoaded #{left.length} SNPs from #{left_file}"
61
+ # y left[0..4]
62
+ right = loader.load_file(right_file, max_rows).sort{|a,b| a[:rsid] <=> b[:rsid]}
63
+ puts "\tLoaded #{right.length} SNPs from #{right_file}"
64
+ processor = YouAndMe::DataProcessor.new(left, right)
65
+ processor.process(true)
66
+
67
+
68
+ puts "Writing reports..."
69
+ processor.to_multimarkdown(left_file, right_file)
70
+ path = File.expand_path("#{opt['directory']}")
71
+ processor.write_multimarkdown(path)
72
+ processor.write_latex(path)
73
+ processor.write_html(path)
74
+
75
+
76
+ puts "Done!"
Binary file
@@ -0,0 +1,2 @@
1
+ require 'youandme/raw_data_file_loader'
2
+ require 'youandme/data_processor'
@@ -0,0 +1,116 @@
1
+ require 'xml'
2
+ require 'libxslt'
3
+ require 'fileutils'
4
+
5
+
6
+ module YouAndMe
7
+
8
+ class DataProcessor
9
+
10
+ attr_accessor :left
11
+ attr_accessor :right
12
+ attr_accessor :rsid_same
13
+ attr_accessor :rsid_diff
14
+ attr_accessor :both_rsid
15
+
16
+ attr_accessor :multimarkdown_text
17
+
18
+
19
+ def initialize(left, right)
20
+ @left = left
21
+ @right = right
22
+ # @rsid_same = nil
23
+ # @rsid_diff = nil
24
+ # @both_rsid = nil
25
+ # process
26
+ end
27
+
28
+ def write_multimarkdown(path)
29
+ file_path = File.join(path, "report.md")
30
+ puts "\tMultiMarkdown #{file_path}..."
31
+ report = File.open(file_path, 'w')
32
+ report.write @multimarkdown_text
33
+ report.close
34
+ end
35
+
36
+ def write_latex(path)
37
+ file_path = File.join(path, "report.ltx")
38
+ puts "\tLaTeX #{file_path}..."
39
+ report = File.open(file_path, 'w')
40
+ mmd = MultiMarkdown.new(@multimarkdown_text)
41
+ report.write mmd.to_latex
42
+ report.close
43
+ end
44
+
45
+ def write_html(path)
46
+ # Write the default file first.
47
+ file_path = File.join(path, "report.html")
48
+ puts "\tHTML #{file_path}..."
49
+ report = File.open(file_path, 'w')
50
+ mmd = MultiMarkdown.new(@multimarkdown_text, :smart, :filter_html)
51
+ report.write mmd.to_html
52
+ report.close
53
+
54
+ # Load the XSL Transform.
55
+ stylesheet_doc = XML::Document.file(File.join(File.dirname(__FILE__), 'xhtml-toc.xslt'))
56
+ stylesheet = LibXSLT::XSLT::Stylesheet.new(stylesheet_doc)
57
+
58
+ # Apply it and re-write the document.
59
+ old_html = XML::Document.file(file_path)
60
+ new_html = stylesheet.apply(old_html)
61
+ report = File.open(file_path, 'w')
62
+ report.write new_html
63
+ report.close
64
+
65
+ # Copy the CSS file into place.
66
+ css_src = File.join(File.dirname(__FILE__), 'report.css')
67
+ css_dest = File.join(path, 'report.css')
68
+ FileUtils.copy(css_src, css_dest)
69
+ end
70
+
71
+ def to_multimarkdown(left_file, right_file)
72
+ @left_file = left_file
73
+ @right_file = right_file
74
+ dir = File.dirname(File.expand_path(__FILE__))
75
+ template_file = File.join(dir, 'report.md.erb')
76
+ template = ERB.new(File.read(template_file))
77
+ @multimarkdown_text = template.result(binding)
78
+ end
79
+
80
+ def process(status = false)
81
+ puts "Creating indexes..." if status
82
+ puts "\tIndexing left data..." if status
83
+ @left_rsid = @left.collect do |n| n[:rsid] end
84
+ @left_chromosome = @left.collect do |n| n[:chromosome] end
85
+ @left_position = @left.collect do |n| n[:position] end
86
+ @left_genotype = @left.collect do |n| n[:genotype] end
87
+
88
+ puts "\tIndexing right data..." if status
89
+ @right_rsid = @right.collect do |n| n[:rsid] end
90
+ @right_chromosome = @right.collect do |n| n[:chromosome] end
91
+ @right_position = @right.collect do |n| n[:position] end
92
+ @right_genotype = @right.collect do |n| n[:genotype] end
93
+
94
+ puts "Computing stuff..." if status
95
+ puts "\tDetecting basic commonalities..." if status
96
+ @both_rsid = @left_rsid & @right_rsid
97
+ both_position = @left_position & @right_position
98
+
99
+ puts "\tFinding dissimilar genotypes..." if status
100
+ @rsid_same = []
101
+ @rsid_diff = []
102
+ @both_rsid.each do |rsid|
103
+ l = left[@left_rsid.index(rsid)]
104
+ r = right[@right_rsid.index(rsid)]
105
+ if l[:genotype] == r[:genotype]
106
+ @rsid_same << [l, r]
107
+ else
108
+ @rsid_diff << [l, r]
109
+ end
110
+ end
111
+
112
+ end
113
+
114
+ end
115
+
116
+ end
@@ -0,0 +1,48 @@
1
+ # Author: Preston Lee
2
+
3
+ module YouAndMe
4
+
5
+ # Tool for loading raw data files from 23andme into native Ruby structures
6
+ class RawDataFileLoader
7
+
8
+ # Returns Markdown-formatted URLs for the given SNP hash.
9
+ def markdown_links(snp)
10
+ "[dbSNP](http://www.ncbi.nlm.nih.gov/SNP/snp_ref.cgi?rs=#{snp[:rsid]}) [SNPedia](http://www.snpedia.com/index.php/#{snp[:rsid]})"
11
+ end
12
+
13
+ # Returns true if and only if the given file exists and is readable.
14
+ def check_file(file_name)
15
+ valid = false
16
+ if(file_name != nil && File.file?(file_name) && File.readable?(file_name))
17
+ valid = true
18
+ end
19
+ valid
20
+ end
21
+
22
+ # Reads the given raw 23andme data file, parses the data, and shoves it into a native Ruby data structure.
23
+ # The returned data is an +Array+ full of +Hash+es, where each hash has key/value pairs for the columns in the data file.
24
+ def load_file(file_name, max = 0)
25
+ snps = []
26
+ # Manually spliting seems to be faster than the built-in CSV parser for
27
+ rows = File.read(file_name).split("\n")
28
+ rows.each do |n|
29
+ row = n.chomp.split("\t")
30
+ # CSV.foreach(file_name, :col_sep => "\t") do |row|
31
+ # Skip if the the line is a comment
32
+ next if row[0][0] == '#'
33
+ break if max > 0 && snps.length >= max
34
+ snp = {
35
+ :rsid => row[0],
36
+ :chromosome => row[1],
37
+ :position => row[2],
38
+ :genotype => row[3]
39
+ }
40
+ # y snp
41
+ snps << snp
42
+ end
43
+ snps
44
+ end
45
+
46
+ end
47
+
48
+ end
@@ -0,0 +1,235 @@
1
+
2
+
3
+ body blockquote {
4
+ margin-top: .75em;
5
+ line-height: 1.5;
6
+ margin-bottom: .75em;
7
+ }
8
+ html {
9
+ background: #f8f8f8;
10
+ }
11
+ html body {
12
+ background: #fff;
13
+ margin: 1em auto 1em auto;
14
+ padding: 40px 100px;
15
+ line-height: 1.8;
16
+ width: 1000px;
17
+ text-align: justify;
18
+ font: 1.2em/2em "Century Gothic","Trebuchet MS",Arial,Helvetica,sans-serif;
19
+ font-size: 18px;
20
+ color: #444;
21
+ }
22
+
23
+ .legalnotice {
24
+ font-size: small;
25
+ font-variant: small-caps;
26
+ }
27
+
28
+ body div {
29
+ margin: 0;
30
+ }
31
+
32
+ dl {
33
+ margin: .8em 0;
34
+ line-height: 1.2;
35
+ }
36
+
37
+ body form {
38
+ margin: .6em 0;
39
+ }
40
+
41
+ h1, h2, h4, h5, h6,
42
+ div.example p b,
43
+ .question,
44
+ div.table p b,
45
+ div.procedure p b {
46
+ color: #005599;
47
+ font: bold 1.2em/2em "Century Gothic","Trebuchet MS",Arial,Helvetica,sans-serif;
48
+ margin: 20px 0;
49
+ }
50
+
51
+ h1 {
52
+ border-bottom: 1px solid black;
53
+ }
54
+
55
+
56
+
57
+
58
+ body hr {
59
+ margin: .6em;
60
+ border-width: 0 0 1px 0;
61
+ border-style: solid;
62
+ border-color: #cecece;
63
+ }
64
+
65
+ body img.navheader {
66
+ margin: 0 0 0 -4%;
67
+ }
68
+
69
+ ol {
70
+ margin: 0 0 0 5%;
71
+ line-height: 1.2;
72
+ }
73
+
74
+ body pre {
75
+ margin: .75em 0;
76
+ line-height: 1.0;
77
+ font-family: monospace;
78
+ }
79
+
80
+ body td, body th {
81
+ line-height: 1.2;
82
+ }
83
+
84
+ ul, body dir, body menu {
85
+ margin: 0 0 0 5%;
86
+ line-height: 1.2;
87
+ }
88
+
89
+ html {
90
+ margin: 0;
91
+ padding: 0;
92
+ }
93
+
94
+ body p b.application {
95
+ color: #000000;
96
+ }
97
+
98
+ .FILENAME {
99
+ color: #007a00;
100
+ }
101
+
102
+ .GUIMENU, .GUIMENUITEM, .GUISUBMENU,
103
+ .GUILABEL, .INTERFACE,
104
+ .SHORTCUT, .SHORTCUT .KEYCAP {
105
+ font-weight: bold;
106
+ }
107
+
108
+ .GUIBUTTON {
109
+ background-color: #CFCFCF;
110
+ padding: 2px;
111
+ }
112
+
113
+ .ACCEL {
114
+ background-color: #F0F0F0;
115
+ text-decoration: underline;
116
+ }
117
+
118
+ .SCREEN {
119
+ padding: 1ex;
120
+ }
121
+
122
+ .PROGRAMLISTING {
123
+ padding: 1ex;
124
+ background-color: #eee;
125
+ border: 1px solid #ccc;
126
+ }
127
+
128
+ @media screen {/* hide from IE3 */
129
+ a[href]:hover {
130
+ background: #ffa
131
+ }
132
+
133
+ }
134
+
135
+ BLOCKQUOTE.NOTE {
136
+ color: #222;
137
+ background: #eee;
138
+ border: 1px solid #ccc;
139
+ padding: 0.4em 0.4em;
140
+ width: 85%;
141
+ }
142
+
143
+ BLOCKQUOTE.TIP {
144
+ color: #004F00;
145
+ background: #d8ecd6;
146
+ border: 1px solid green;
147
+ padding: 0.2em 2em;
148
+ width: 85%;
149
+ }
150
+
151
+ BLOCKQUOTE.IMPORTANT {
152
+ font-style: italic;
153
+ border: 1px solid #a00;
154
+ border-left: 12px solid #c00;
155
+ padding: 0.1em 1em;
156
+ }
157
+
158
+ BLOCKQUOTE.WARNING {
159
+ color: #9F1313;
160
+ background: #f8e8e8;
161
+ border: 1px solid #e59595;
162
+ padding: 0.2em 2em;
163
+ width: 85%;
164
+ }
165
+
166
+ .EXAMPLE {
167
+ background: #fefde6;
168
+ border: 1px solid #f1bb16;
169
+ margin: 1em 0;
170
+ padding: 0.2em 2em;
171
+ width: 90%;
172
+ }
173
+
174
+
175
+ table {
176
+ width: 90%;
177
+ border-top: 1px solid #e5eff8;
178
+ border-right: 1px solid #e5eff8;
179
+ margin: 1em auto;
180
+ border-collapse: collapse;
181
+ }
182
+ caption {
183
+ color: #9ba9b4;
184
+ font-size: .94em;
185
+ letter-spacing: .1em;
186
+ margin: 1em 0 0 0;
187
+ padding: 0;
188
+ caption-side: top;
189
+ text-align: center;
190
+ }
191
+ tr.odd td {
192
+ background: #f7fbff
193
+ }
194
+ tr.odd .column1 {
195
+ background: #f4f9fe;
196
+ }
197
+ .column1 {
198
+ background: #f9fcfe;
199
+ }
200
+ td {
201
+ color: #678197;
202
+ border-bottom: 1px solid #e5eff8;
203
+ border-left: 1px solid #e5eff8;
204
+ padding: .3em 1em;
205
+ text-align: center;
206
+ }
207
+ th {
208
+ font-weight: normal;
209
+ color: #678197;
210
+ text-align: left;
211
+ border-bottom: 1px solid #e5eff8;
212
+ border-left: 1px solid #e5eff8;
213
+ padding: .3em 1em;
214
+ }
215
+ thead th {
216
+ background: #f4f9fe;
217
+ text-align: center;
218
+ font: bold 1.2em/2em "Century Gothic","Trebuchet MS",Arial,Helvetica,sans-serif;
219
+ color: #66a3d3
220
+ }
221
+ tfoot th {
222
+ text-align: center;
223
+ background: #f4f9fe;
224
+ }
225
+ tfoot th strong {
226
+ font: bold 1.2em "Century Gothic","Trebuchet MS",Arial,Helvetica,sans-serif;
227
+ margin: .5em .5em .5em 0;
228
+ color: #66a3d3;
229
+ }
230
+ tfoot th em {
231
+ color: #f03b58;
232
+ font-weight: bold;
233
+ font-size: 1.1em;
234
+ font-style: normal;
235
+ }
@@ -0,0 +1,37 @@
1
+ Title: SNV Comparison Report
2
+ Subtitle: A side-by-side comparison
3
+ Format: complete
4
+ CSS: report.css
5
+
6
+ # SNV Comparison Report
7
+
8
+ <% loader = YouAndMe::RawDataFileLoader.new %>
9
+
10
+ - Left file: <%= @left_file %>
11
+ - Right file: <%= @right_file %>
12
+ - SNPs sequenced in both profiles: <%= @both_rsid.length %> (<%= 100.0 * @both_rsid.length / @left.length %>% of left and <%= 100.0 * @both_rsid.length / @right.length %>% of right.)
13
+ - Same genotype when SNV in both profiles: <%= @rsid_same.length %> (<%= "%.3f" % (100.0 * @rsid_same.length / @left.length) %>% of left and <%= "%.3f" % (100.0 * @rsid_same.length / @right.length) %>% of right.))
14
+ - Differing genotypes when SNV in both profiles: <%= @rsid_diff.length %> (<%= "%.3f" % (100.0 * @rsid_diff.length / @left.length) %>% of left and <%= "%.3f" % (100.0 * @rsid_diff.length / @right.length) %>% of right.))
15
+ - Generated <%= Time.now.strftime("%m/%d/%Y at %I:%M%p") %>.
16
+
17
+ ## Same Genotype
18
+
19
+ The following <%= @rsid_same.length %> SNVs are the *same* in both profiles. Click the links in the last column for access to scientific literature.
20
+
21
+ [Same Genotype]
22
+ | rsID | Genotype | Reference Position | Links ||
23
+ -------- |
24
+ <% @rsid_same.each do |n| %><%= n[0][:rsid] %> | <%= n[0][:genotype] %> | <%= n[0][:position] %> |<%= loader.markdown_links(n[0]) %>
25
+ <% end %>
26
+
27
+
28
+ ## Different Genotype
29
+
30
+ The follow <%= @rsid_diff.length %> SNVs *differ* between the profiles. Click the links in the last column for access to scientific literature.
31
+
32
+ [Same Genotype]
33
+ | rsID | Left Genotype | Right Genotype | Reference Position | Links ||
34
+ -------- |
35
+ <% @rsid_diff.each do |n| %><%= n[0][:rsid] %> | <%= n[0][:genotype] %> | <%= n[1][:genotype] %> | <%= n[0][:position] %> | <%= loader.markdown_links(n[0]) %>
36
+ <% end %>
37
+
@@ -0,0 +1,134 @@
1
+ <?xml version='1.0' encoding='utf-8'?>
2
+
3
+ <!-- XHTML-to-XHTML converter by Fletcher Penney
4
+ specifically designed for use with MultiMarkdown created XHTML
5
+
6
+ Adds a Table of Contents to the top of the XHTML document,
7
+ and adds linkbacks from h1 and h2's.
8
+
9
+ Also, an example of the sorts of things that can be done to customize
10
+ the XHTML output of MultiMarkdown.
11
+
12
+ MultiMarkdown Version 2.0.b6
13
+
14
+ $Id: xhtml-toc.xslt 499 2008-03-23 13:03:19Z fletcher $
15
+
16
+ TODO: If a section has no children, a "<ol></ol>" is generated, which is invalid
17
+ -->
18
+
19
+ <!--
20
+ # Copyright (C) 2007-2008 Fletcher T. Penney <fletcher@fletcherpenney.net>
21
+ #
22
+ # This program is free software; you can redistribute it and/or modify
23
+ # it under the terms of the GNU General Public License as published by
24
+ # the Free Software Foundation; either version 2 of the License, or
25
+ # (at your option) any later version.
26
+ #
27
+ # This program is distributed in the hope that it will be useful,
28
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
29
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30
+ # GNU General Public License for more details.
31
+ #
32
+ # You should have received a copy of the GNU General Public License
33
+ # along with this program; if not, write to the
34
+ # Free Software Foundation, Inc.
35
+ # 59 Temple Place, Suite 330
36
+ # Boston, MA 02111-1307 USA
37
+ -->
38
+
39
+
40
+ <xsl:stylesheet
41
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
42
+ xmlns:xhtml="http://www.w3.org/1999/xhtml"
43
+ xmlns="http://www.w3.org/1999/xhtml"
44
+ exclude-result-prefixes="xhtml xsl"
45
+ version="1.0">
46
+
47
+ <xsl:variable name="newline">
48
+ <xsl:text>
49
+ </xsl:text>
50
+ </xsl:variable>
51
+
52
+ <xsl:output method='xml' version="1.0" encoding='utf-8' doctype-public="-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN" doctype-system="http://www.w3.org/TR/MathML2/dtd/xhtml-math11-f.dtd" indent="no"/>
53
+
54
+ <!-- the identity template, based on http://www.xmlplease.com/xhtmlxhtml -->
55
+ <xsl:template match="@*|node()">
56
+ <xsl:copy>
57
+ <xsl:apply-templates select="@*|node()"/>
58
+ </xsl:copy>
59
+ </xsl:template>
60
+
61
+ <!-- adjust the body to add a ToC -->
62
+ <!-- TODO: Will need to move this to just before first <h1> to allow for introductory comments -->
63
+ <xsl:template match="xhtml:body">
64
+ <xsl:copy>
65
+ <xsl:value-of select="$newline"/>
66
+ <h1>Table of Contents</h1>
67
+ <xsl:value-of select="$newline"/>
68
+ <ol>
69
+ <xsl:apply-templates select="xhtml:h1" mode="ToC"/>
70
+ <xsl:value-of select="$newline"/>
71
+ </ol>
72
+ <xsl:apply-templates select="@*|node()"/>
73
+ </xsl:copy>
74
+ </xsl:template>
75
+
76
+
77
+ <!-- create ToC entry -->
78
+ <xsl:template match="xhtml:h1" mode="ToC">
79
+ <xsl:value-of select="$newline"/>
80
+ <xsl:variable name="link">
81
+ <xsl:value-of select="@id"/>
82
+ </xsl:variable>
83
+ <xsl:variable name="myId">
84
+ <xsl:value-of select="generate-id(.)"/>
85
+ </xsl:variable>
86
+ <li>
87
+ <a id="ToC-{$link}" href="#{$link}">
88
+ <xsl:apply-templates select="node()"/>
89
+ </a>
90
+ <xsl:if test="following::xhtml:h2[1][preceding::xhtml:h1[1]]">
91
+ <xsl:value-of select="$newline"/>
92
+ <ol>
93
+ <xsl:apply-templates select="following::xhtml:h2[preceding::xhtml:h1[1][generate-id() = $myId]]" mode="ToC"/>
94
+ <xsl:value-of select="$newline"/>
95
+ </ol>
96
+ <xsl:value-of select="$newline"/>
97
+ </xsl:if>
98
+ </li>
99
+ </xsl:template>
100
+
101
+ <xsl:template match="xhtml:h2" mode="ToC">
102
+ <xsl:value-of select="$newline"/>
103
+ <xsl:variable name="link">
104
+ <xsl:value-of select="@id"/>
105
+ </xsl:variable>
106
+ <li>
107
+ <a id="ToC-{$link}" href="#{$link}">
108
+ <xsl:apply-templates select="node()"/>
109
+ </a>
110
+ </li>
111
+ </xsl:template>
112
+
113
+ <!-- h1 and h2's should point back to the ToC for easy navigation -->
114
+ <xsl:template match="xhtml:h1">
115
+ <xsl:variable name="link">
116
+ <xsl:value-of select="@id"/>
117
+ </xsl:variable>
118
+ <xsl:copy>
119
+ <xsl:apply-templates select="@*|node()"/>
120
+ <a href="#ToC-{$link}">&#160;&#8617;</a>
121
+ </xsl:copy>
122
+ </xsl:template>
123
+
124
+ <xsl:template match="xhtml:h2">
125
+ <xsl:variable name="link">
126
+ <xsl:value-of select="@id"/>
127
+ </xsl:variable>
128
+ <xsl:copy>
129
+ <xsl:apply-templates select="@*|node()"/>
130
+ <a href="#ToC-{$link}">&#160;&#8617;</a>
131
+ </xsl:copy>
132
+ </xsl:template>
133
+
134
+ </xsl:stylesheet>
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+ require 'shoulda'
12
+
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ require 'youandme'
16
+
17
+ class Test::Unit::TestCase
18
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestYouandme < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,146 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: youandme
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Preston Lee
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-11-04 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: getopt
16
+ requirement: &70244552095660 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 1.4.1
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70244552095660
25
+ - !ruby/object:Gem::Dependency
26
+ name: rpeg-multimarkdown
27
+ requirement: &70244552094940 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 0.1.1
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70244552094940
36
+ - !ruby/object:Gem::Dependency
37
+ name: libxslt-ruby
38
+ requirement: &70244552094060 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 1.0.8
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *70244552094060
47
+ - !ruby/object:Gem::Dependency
48
+ name: shoulda
49
+ requirement: &70244552093220 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70244552093220
58
+ - !ruby/object:Gem::Dependency
59
+ name: bundler
60
+ requirement: &70244552091740 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ~>
64
+ - !ruby/object:Gem::Version
65
+ version: 1.0.0
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70244552091740
69
+ - !ruby/object:Gem::Dependency
70
+ name: jeweler
71
+ requirement: &70244552090860 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ version: 1.6.4
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *70244552090860
80
+ - !ruby/object:Gem::Dependency
81
+ name: rcov
82
+ requirement: &70244552090000 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: *70244552090000
91
+ description: An unofficial ruby library for quickly parsing 23andme raw data files
92
+ into a plain Ruby structures for quick processing and analysis.
93
+ email: conmotto@gmail.com
94
+ executables:
95
+ - youandme
96
+ extensions: []
97
+ extra_rdoc_files:
98
+ - LICENSE.txt
99
+ - README.md
100
+ files:
101
+ - .document
102
+ - Gemfile
103
+ - Gemfile.lock
104
+ - LICENSE.txt
105
+ - README.md
106
+ - Rakefile
107
+ - VERSION
108
+ - bin/youandme
109
+ - lib/.DS_Store
110
+ - lib/youandme.rb
111
+ - lib/youandme/data_processor.rb
112
+ - lib/youandme/raw_data_file_loader.rb
113
+ - lib/youandme/report.css
114
+ - lib/youandme/report.md.erb
115
+ - lib/youandme/xhtml-toc.xslt
116
+ - test/helper.rb
117
+ - test/test_youandme.rb
118
+ homepage: http://github.com/preston/youandme
119
+ licenses:
120
+ - Apache 2.0
121
+ post_install_message:
122
+ rdoc_options: []
123
+ require_paths:
124
+ - lib
125
+ required_ruby_version: !ruby/object:Gem::Requirement
126
+ none: false
127
+ requirements:
128
+ - - ! '>='
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ segments:
132
+ - 0
133
+ hash: -3067078396370175135
134
+ required_rubygems_version: !ruby/object:Gem::Requirement
135
+ none: false
136
+ requirements:
137
+ - - ! '>='
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ requirements: []
141
+ rubyforge_project:
142
+ rubygems_version: 1.8.11
143
+ signing_key:
144
+ specification_version: 3
145
+ summary: Data comparison and analysis tools for 23andme raw data files.
146
+ test_files: []