ydocx 1.0.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.
data/History.txt ADDED
@@ -0,0 +1,6 @@
1
+ === 1.0.0 / 01.05.2012
2
+
3
+ * 1 major enhancement
4
+
5
+ * Birthday!
6
+
data/Manifest.txt ADDED
@@ -0,0 +1,12 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ bin/docx2html
6
+ lib/docx2html/bin/docx2html
7
+ lib/docx2html/lib/docx2html.rb
8
+ lib/docx2html/lib/docx2html/builder.rb
9
+ lib/docx2html/lib/docx2html/document.rb
10
+ lib/docx2html/lib/docx2html/html_methods.rb
11
+ lib/docx2html/lib/docx2html/parser.rb
12
+ lib/fachinfo.rb
data/README.txt ADDED
@@ -0,0 +1,21 @@
1
+ == ydocx - © ywesee GmbH
2
+
3
+ * https://github.com/zdavatz/ydocx
4
+ * Parsing docx files with Ruby and output them as HTML.
5
+
6
+ == Supports
7
+
8
+ * Tables
9
+ * Uppercase letters, numbers
10
+ * Lowercase letters, numbers
11
+ * Umlaute
12
+ * bold, italic, underline
13
+
14
+ == Using the great libraries
15
+
16
+ * nokogiri
17
+ * htmlentities
18
+
19
+ == License GPLv2.1
20
+
21
+ * http://www.gnu.org/licenses/lgpl-2.1.html
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+
6
+ # Hoe.plugin :compiler
7
+ # Hoe.plugin :gem_prelude_sucks
8
+ # Hoe.plugin :inline
9
+ # Hoe.plugin :minitest
10
+ # Hoe.plugin :racc
11
+ # Hoe.plugin :rubyforge
12
+
13
+ Hoe.spec 'ydocx' do
14
+
15
+ developer('Yasuhiro Asaka, Zeno R.R. Davatz', 'yasaka@ywesee.com, zdavatz@ywesee.com')
16
+
17
+ end
data/bin/docx2html ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ # coding: utf-8
3
+
4
+ require 'pathname'
5
+
6
+ VERSION = "1.0.0"
7
+
8
+ root = Pathname.new(__FILE__).realpath.parent.parent
9
+ %w(
10
+ lib/docx2html/lib
11
+ lib
12
+ ).each do |lib|
13
+ $:.unshift root.join(lib) if $0 == __FILE__
14
+ end
15
+ require 'docx2html'
16
+
17
+ if file = ARGV.first
18
+ unless File.exist?(file)
19
+ exit
20
+ else
21
+ # TODO args handling
22
+ if true
23
+ require 'fachinfo'
24
+ end
25
+ Docx2html::Document.open(file).to_html file, :style => true
26
+ end
27
+ end
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ # coding: utf-8
3
+
4
+ require 'pathname'
5
+
6
+ root = Pathname.new(__FILE__).realpath.parent.parent
7
+ $:.unshift root.join('lib/docx2html') if $0 == __FILE__
8
+ require 'docx2html'
9
+
10
+ if file = ARGV.first
11
+ unless File.exist?(file)
12
+ exit
13
+ else
14
+ Docx2html::Document.open(file).to_html file, :style => true
15
+ end
16
+ end
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ require 'nokogiri'
5
+ require 'docx2html/html_methods'
6
+
7
+ module Docx2html
8
+ class Builder
9
+ include HtmlMethods
10
+ attr_accessor :body, :indecies, :style, :title
11
+ def initialize(body)
12
+ @body = body
13
+ @container = {}
14
+ @indecies = []
15
+ @style = false
16
+ @title = ''
17
+ init
18
+ if block_given?
19
+ yield self
20
+ end
21
+ end
22
+ def init
23
+ end
24
+ def build
25
+ if @container.has_key?(:content)
26
+ @container[:content] = @body
27
+ @body = [@container]
28
+ end
29
+ if before_content = build_before_content
30
+ @body.unshift before_content
31
+ end
32
+ if after_content = build_after_content
33
+ @body.push after_content
34
+ end
35
+ body = ''
36
+ @body.each do |e|
37
+ body << build_tag(e[:tag], e[:content], e[:attributes])
38
+ end
39
+ builder = Nokogiri::HTML::Builder.new do |doc|
40
+ doc.html {
41
+ doc.head {
42
+ doc.meta :charset => 'utf-8'
43
+ doc.title @title
44
+ doc.style { doc << style } if @style
45
+ }
46
+ doc.body { doc << body }
47
+ }
48
+ end
49
+ builder.to_html.gsub(/\n/, '')
50
+ end
51
+ private
52
+ def build_after_content
53
+ nil
54
+ end
55
+ def build_before_content
56
+ nil
57
+ end
58
+ def build_tag(tag, content, attributes)
59
+ return '' if content.empty?
60
+ _content = ''
61
+ if content.is_a? Array
62
+ content.each do |c|
63
+ next if c.nil? or c.empty?
64
+ if c.is_a? Hash
65
+ _content << build_tag(c[:tag], c[:content], c[:attributes])
66
+ elsif c.is_a? String
67
+ _content << c.chomp.to_s
68
+ end
69
+ end
70
+ elsif content.is_a? Hash
71
+ _content = build_tag(content[:tag], content[:content], content[:attributes])
72
+ elsif content.is_a? String
73
+ _content = content
74
+ end
75
+ _tag = tag.to_s
76
+ _attributes = ''
77
+ unless attributes.empty?
78
+ attributes.each_pair do |k, v|
79
+ _attributes << " #{k.to_s}=#{v.to_s}"
80
+ end
81
+ end
82
+ "<#{_tag}#{_attributes}>#{_content}</#{_tag}>"
83
+ end
84
+ def style
85
+ style = <<-CSS
86
+ table, tr, td {
87
+ border-collapse: collapse;
88
+ border: 1px solid gray;
89
+ }
90
+ table {
91
+ margin: 5px 0 5px 0;
92
+ }
93
+ td {
94
+ padding: 5px 10px;
95
+ }
96
+ CSS
97
+ style.gsub(/\s\s+|\n/, ' ')
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ require 'pathname'
5
+ require 'zip/zip'
6
+ require 'docx2html/parser'
7
+ require 'docx2html/builder'
8
+
9
+ module Docx2html
10
+ class Document
11
+ attr_reader :contents
12
+ def self.open(file)
13
+ self.new(file)
14
+ end
15
+ def initialize(file)
16
+ @contents = nil
17
+ @indecies = nil
18
+ read(file)
19
+ end
20
+ def to_html(file='', options={})
21
+ html = ''
22
+ Builder.new(@contents) do |builder|
23
+ builder.title = @path
24
+ builder.style = options[:style]
25
+ if @indecies
26
+ builder.indecies = @indecies
27
+ end
28
+ html = builder.build
29
+ end
30
+ unless file.empty?
31
+ path = Pathname.new(file).realpath.sub_ext('.html')
32
+ File.open(path, 'w:utf-8') do |f|
33
+ f.puts html
34
+ end
35
+ else
36
+ html
37
+ end
38
+ end
39
+ private
40
+ def read(file)
41
+ @path = File.expand_path(file)
42
+ @zip = Zip::ZipFile.open(@path)
43
+ stream = @zip.find_entry('word/document.xml').get_input_stream
44
+ Parser.new(stream) do |parser|
45
+ @contents = parser.parse
46
+ @indecies = parser.indecies
47
+ end
48
+ @zip.close
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ module Docx2html
5
+ module HtmlMethods
6
+ def tag(tag, content = [], attributes = {})
7
+ tag_hash = {
8
+ :tag => tag,
9
+ :content => content,
10
+ :attributes => attributes
11
+ }
12
+ tag_hash
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,213 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ require 'nokogiri'
5
+ require 'htmlentities'
6
+ require 'docx2html/html_methods'
7
+
8
+ module Docx2html
9
+ class Parser
10
+ include HtmlMethods
11
+ attr_accessor :indecies, :result
12
+ def initialize(stream)
13
+ @xml = Nokogiri::XML.parse(stream)
14
+ @coder = HTMLEntities.new
15
+ @indecies = []
16
+ @result = []
17
+ init
18
+ if block_given?
19
+ yield self
20
+ end
21
+ end
22
+ def init
23
+ end
24
+ def parse
25
+ @xml.xpath('//w:document//w:body').children.map do |node|
26
+ case node.node_name
27
+ when 'text'
28
+ @result << parse_paragraph(node)
29
+ when 'tbl'
30
+ @result << parse_table(node)
31
+ when 'image'
32
+ # pending
33
+ when 'p'
34
+ @result << parse_paragraph(node)
35
+ else
36
+ # skip
37
+ end
38
+ end
39
+ @result
40
+ end
41
+ private
42
+ def apply_fonts(rpr, text)
43
+ symbol = false
44
+ unless rpr.xpath('w:rFonts').empty?
45
+ rpr.xpath('w:rFonts').each do |font|
46
+ if font.values.include? 'Symbol'
47
+ symbol = true
48
+ end
49
+ break if symbol
50
+ end
51
+ end
52
+ if symbol
53
+ _text = ''
54
+ text.unpack('U*').each do |char|
55
+ _text << optional_replace(char.to_s(16))
56
+ end
57
+ text = _text
58
+ end
59
+ text
60
+ end
61
+ def apply_align(rpr, text)
62
+ unless rpr.xpath('w:vertAlign').empty?
63
+ script = rpr.xpath('w:vertAlign').first['val'].to_sym
64
+ if script == :subscript
65
+ text = tag(:sub, text)
66
+ elsif script == :superscript
67
+ text = tag(:sup, text)
68
+ end
69
+ end
70
+ text
71
+ end
72
+ def parse_as_block(r, text)
73
+ nil # default no block element
74
+ end
75
+ def optional_escape(text)
76
+ return text = '&nbsp;' if text.empty?
77
+ text.force_encoding('utf-8')
78
+ # NOTE
79
+ # :named only for escape at Builder
80
+ text = @coder.encode(text, :named)
81
+ text
82
+ end
83
+ def optional_replace(code)
84
+ code = '0x' + code
85
+ # NOTE
86
+ # replace with rsemble html character ref
87
+ # Symbol Font to HTML Character named ref
88
+ case code
89
+ when '0xf020' # '61472'
90
+ ""
91
+ when '0xf025' # '61477'
92
+ "%"
93
+ when '0xf02b' # '61482'
94
+ "*"
95
+ when '0xf02b' # '61483'
96
+ "+"
97
+ when '0xf02d' # '61485'
98
+ "-"
99
+ when '0xf02f' # '61487'
100
+ "/"
101
+ when '0xf03c' # '61500'
102
+ "&lt;"
103
+ when '0xf03d' # '61501'
104
+ "="
105
+ when '0xf03e' # '61502'
106
+ "&gt;"
107
+ when '0xf040' # '61504'
108
+ "&cong;"
109
+ when '0xf068' # '61544'
110
+ "&eta;"
111
+ when '0xf071' # '61553'
112
+ "&theta;"
113
+ when '0xf06d' # '61549'
114
+ "&mu;"
115
+ when '0xf0a3' # '61603'
116
+ "&le;"
117
+ when '0xf0ab' # '61611'
118
+ "&harr;"
119
+ when '0xf0ac' # '61612'
120
+ "&larr;"
121
+ when '0xf0ad' # '61613'
122
+ "&uarr;"
123
+ when '0xf0ae' # '61614'
124
+ "&rarr;"
125
+ when '0xf0ad' # '61615'
126
+ "&darr;"
127
+ when '0xf0b1' # '61617'
128
+ "&plusmn;"
129
+ when '0xf0b2' # '61618'
130
+ "&Prime;"
131
+ when '0xf0b3' # '61619'
132
+ "&ge;"
133
+ when '0xf0b4' # '61620'
134
+ "&times;"
135
+ when '0xf0b7' # '61623'
136
+ "&sdot;"
137
+ else
138
+ #p "code : " + ("&#%s;" % code)
139
+ #p "hex : " + code.hex.to_s
140
+ #p "char : " + @coder.decode("&#%s;" % code)
141
+ #@coder.decode("&#%s;" % code.hex.to_s)
142
+ end
143
+ end
144
+ def parse_image
145
+ # pending
146
+ end
147
+ def parse_paragraph(node)
148
+ paragraph = tag :p
149
+ node.xpath('w:r').each do |r|
150
+ unless r.xpath('w:t').empty?
151
+ paragraph[:content] << parse_text(r)
152
+ else
153
+ unless r.xpath('w:tab').empty?
154
+ if paragraph[:content].last != '&nbsp;' # as a space
155
+ paragraph[:content] << optional_escape('')
156
+ end
157
+ end
158
+ unless r.xpath('w:sym').empty?
159
+ code = r.xpath('w:sym').first['char'].downcase # w:char
160
+ paragraph[:content] << optional_replace(code)
161
+ end
162
+ end
163
+ end
164
+ paragraph
165
+ end
166
+ def parse_table(node)
167
+ table = tag :table
168
+ node.xpath('w:tr').each do |tr|
169
+ cells = tag :tr
170
+ tr.xpath('w:tc').each do |tc|
171
+ attributes = {}
172
+ tc.xpath('w:tcPr').each do |tcpr|
173
+ if span = tcpr.xpath('w:gridSpan') and !span.empty?
174
+ attributes[:colspan] = span.first['val'] # w:val
175
+ end
176
+ end
177
+ cell = tag :td, [], attributes
178
+ tc.xpath('w:p').each do |p|
179
+ cell[:content] << parse_paragraph(p)
180
+ end
181
+ cells[:content] << cell
182
+ end
183
+ table[:content] << cells
184
+ end
185
+ table
186
+ end
187
+ def parse_text(r)
188
+ text = r.xpath('w:t').map(&:text).join('')
189
+ text = optional_escape(text)
190
+ if rpr = r.xpath('w:rPr')
191
+ text = apply_fonts(rpr, text)
192
+ if block = parse_as_block(r, text)
193
+ block
194
+ else
195
+ # inline tag
196
+ text = apply_align(rpr, text)
197
+ unless rpr.xpath('w:u').empty?
198
+ text = tag(:span, text, {:style => "text-decoration:underline;"})
199
+ end
200
+ unless rpr.xpath('w:i').empty?
201
+ text = tag(:em, text)
202
+ end
203
+ unless rpr.xpath('w:b').empty?
204
+ text = tag(:strong, text)
205
+ end
206
+ text
207
+ end
208
+ else
209
+ text
210
+ end
211
+ end
212
+ end
213
+ end
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ require 'docx2html/document'
5
+
6
+ module Docx2html
7
+ end
data/lib/fachinfo.rb ADDED
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ require 'cgi'
5
+
6
+ module Docx2html
7
+ class Parser
8
+ private
9
+ def parse_as_block(r, text)
10
+ if r.parent.previous.nil?
11
+ # first line is package name
12
+ return tag(:h2, text)
13
+ end
14
+ text = text.strip
15
+ # TODO
16
+ # Franzoesisch
17
+ chapters = {
18
+ 'Dos./Anw.' => /^Dosierung\s*\/\s*Anwendung/u, # 5
19
+ 'Eigensch.' => /^Eigenschaften\s*\/\s*Wirkungen($|\s*\(\s*(ATC\-Code|Wirkungsmechanismus|Pharmakodyamik|Klinische\s+Wirksamkeit)\s*\)\s*$)|^Propri.t.s/iu, # 13
20
+ 'Galen.Form' => /^Galenische\s+Form\s+und\s+Wirkstoffmenge\s+pro\s+Einheit$|^Forme\s*gal.nique/iu, # 3
21
+ 'Ind./Anw.mögl.' => /^Indikationen(\s+|\s*\/\s*)Anwendungsm&ouml;glichkeiten$|^Indications/u, # 4
22
+ 'Interakt.' => /^Interaktionen$|^Interactions/u, # 8
23
+ 'Kontraind.' => /^Kontraindikationen($|\s*\(\s*absolute\s+Kontraindikationen\s*\)$)/u, # 6
24
+ 'Name' => /^Name\s+des\s+Pr&auml;parates$/, # 1
25
+ 'Packungen' => /^Packungen($|\s*\(\s*mit\s+Angabe\s+der\s+Abgabekategorie\s*\)$)/u, # 18
26
+ 'Präklin.' => /^Pr&auml;klinische\s+Daten$/u, # 15
27
+ 'Pharm.kinetik' => /^Pharmakokinetik($|\s*\((Absorption,\s*Distribution,\s*Metabolisms,\s*Elimination\s|Kinetik\s+spezieller\s+Patientengruppen)*\)$)|^Pharmacocin.tique?/iu, # 14
28
+ 'Sonstige H.' => /^Sonstige\s*Hinweise($|\s*\(\s*(Inkompatibilit&auml;ten|Beeinflussung\s*diagnostischer\s*Methoden|Haltbarkeit|Besondere\s*Lagerungshinweise|Hinweise\s+f&uuml;r\s+die\s+Handhabung)\s*\)$)|^Remarques/u, # 16
29
+ 'Schwangerschaft' => /^Schwangerschaft(,\s*|\s*\/\s*)Stillzeit$/u, # 9
30
+ 'Stand d. Info.' => /^Stand\s+der\s+Information$|^Mise\s+.\s+jour$/iu, # 20
31
+ 'Unerw.Wirkungen' => /^Unerw&uuml;nschte\s+Wirkungen$/u, # 11
32
+ 'Überdos.' => /^&Uuml;berdosierung$|^Surdosage$/u, # 12
33
+ 'Warn.hinw.' => /^Warnhinweise\s+und\s+Vorsichtsmassnahmen($|\s*\/\s*(relative\s+Kontraindikationen|Warnhinweise\s*und\s*Vorsichtsmassnahmen)$)/u, # 7
34
+ 'Fahrtücht.' => /^Wirkung\s+auf\s+die\s+Fahrt&uuml;chtigkeit\s+und\s+auf\s+das\s+Bedienen\s+von\s+Maschinen$/u, # 10
35
+ 'Swissmedic-Nr.' => /^Zulassungsnummer($|\s*\(\s*Swissmedic\s*\)$)/u, # 17
36
+ 'Reg.Inhaber' => /^Zulassungsinhaberin($|\s*\(\s*Firma\s+und\s+Sitz\s+gem&auml;ss\s*Handelsregisterauszug\s*\))/u, # 19
37
+ 'Zusammens.' => /^Zusammensetzung($|\s*\/\s*(Wirkstoffe|Hilsstoffe)$)/u, # 2
38
+ }.each_pair do |chapter, regexp|
39
+ if text =~ regexp
40
+ next unless r.next.nil? # without line break
41
+ id = CGI.escape(text.gsub(/&(.)uml;/, '\1').gsub(/\s*\/\s*|\/|\s+/, '_').downcase)
42
+ @indecies << {:text => chapter, :id => id}
43
+ return tag(:h3, text, {:id => id})
44
+ end
45
+ end
46
+ nil
47
+ end
48
+ end
49
+ class Builder
50
+ def init
51
+ @container = tag(:div, [], {:id => 'container'})
52
+ end
53
+ private
54
+ def build_after_content
55
+ link = tag(:a, 'Top', {:href => ''})
56
+ tag(:div, link, {:id => 'footer'})
57
+ end
58
+ def build_before_content
59
+ if @indecies
60
+ indices = []
61
+ @indecies.each do |index|
62
+ indices << tag(:li, tag(:a, index[:text], {:href => "#" + index[:id]}))
63
+ end
64
+ tag(:div, tag(:ul, indices), {:id => 'indecies'})
65
+ end
66
+ end
67
+ def style
68
+ style = <<-CSS
69
+ table, tr, td {
70
+ border-collapse: collapse;
71
+ border: 1px solid gray;
72
+ }
73
+ table {
74
+ margin: 5px 0 5px 0;
75
+ }
76
+ td {
77
+ padding: 5px 10px;
78
+ }
79
+ body {
80
+ position: relative;
81
+ padding: 0 0 20px 0;
82
+ margin: 0px;
83
+ width: 100%;
84
+ height: auto;
85
+ }
86
+ div#indecies {
87
+ position: relative;
88
+ padding: 0px;
89
+ float: left;
90
+ width: 200px;
91
+ }
92
+ div#indecies ul {
93
+ margin: 0;
94
+ padding: 0 0 0 25px;
95
+ }
96
+ div#container {
97
+ position: relative;
98
+ padding: 0px;
99
+ float: top left;
100
+ margin-left: 200px;
101
+ }
102
+ div#footer {
103
+ position: relative;
104
+ float: bottom right;
105
+ text-align: right;
106
+ padding-right: 25px;
107
+ }
108
+ CSS
109
+ style.gsub(/\s\s+|\n/, ' ')
110
+ end
111
+ end
112
+ end
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ydocx
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Yasuhiro Asaka, Zeno R.R. Davatz
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-05-01 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rdoc
16
+ requirement: &21539280 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '3.10'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *21539280
25
+ - !ruby/object:Gem::Dependency
26
+ name: hoe
27
+ requirement: &21538860 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: '2.13'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *21538860
36
+ description: ''
37
+ email:
38
+ - yasaka@ywesee.com, zdavatz@ywesee.com
39
+ executables:
40
+ - docx2html
41
+ extensions: []
42
+ extra_rdoc_files:
43
+ - History.txt
44
+ - Manifest.txt
45
+ - README.txt
46
+ files:
47
+ - History.txt
48
+ - Manifest.txt
49
+ - README.txt
50
+ - Rakefile
51
+ - bin/docx2html
52
+ - lib/docx2html/bin/docx2html
53
+ - lib/docx2html/lib/docx2html.rb
54
+ - lib/docx2html/lib/docx2html/builder.rb
55
+ - lib/docx2html/lib/docx2html/document.rb
56
+ - lib/docx2html/lib/docx2html/html_methods.rb
57
+ - lib/docx2html/lib/docx2html/parser.rb
58
+ - lib/fachinfo.rb
59
+ homepage: https://github.com/zdavatz/ydocx
60
+ licenses: []
61
+ post_install_message:
62
+ rdoc_options:
63
+ - --main
64
+ - README.txt
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ! '>='
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ requirements: []
80
+ rubyforge_project: ydocx
81
+ rubygems_version: 1.8.15
82
+ signing_key:
83
+ specification_version: 3
84
+ summary: ''
85
+ test_files: []