resumetools 0.2.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,307 @@
1
+ # coding: utf-8
2
+
3
+ #--
4
+ # Copyright (c) 2009 Virgil Dimaguila
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person
7
+ # obtaining a copy of this software and associated documentation
8
+ # files (the "Software"), to deal in the Software without
9
+ # restriction, including without limitation the rights to use,
10
+ # copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the
12
+ # Software is furnished to do so, subject to the following
13
+ # conditions:
14
+ #
15
+ # The above copyright notice and this permission notice shall be
16
+ # included in all copies or substantial portions of the Software.
17
+ #
18
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20
+ # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22
+ # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23
+ # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25
+ # OTHER DEALINGS IN THE SOFTWARE.
26
+ #++
27
+
28
+ module ResumeTools
29
+
30
+ # = Resume
31
+ # Represents a single resume document
32
+ class Resume
33
+
34
+ # The full name of the subject of this resume
35
+ attr_accessor :full_name
36
+
37
+ # The subject's URL
38
+ attr_accessor :url
39
+
40
+ # The subject's e-mail address
41
+ attr_accessor :email
42
+
43
+ # The subject's telephone number
44
+ attr_accessor :telephone
45
+
46
+ # First line of the address
47
+ attr_accessor :address1
48
+
49
+ # Second line of the address
50
+ attr_accessor :address2
51
+
52
+ # The resume's sections
53
+ attr_reader :sections
54
+
55
+ # Creates a +Resume+ and passes it to the given block. Returns the created +Resume+.
56
+ def self.build(opts={}, &block)
57
+ resume = self.new(opts)
58
+ block.call(resume)
59
+ resume
60
+ end
61
+
62
+ # Creates a new +Resume+ with the given properties
63
+ def initialize(props={})
64
+ @full_name = props[:full_name] || ""
65
+ @url = props[:url] || ""
66
+ @email = props[:email] || ""
67
+ @telephone = props[:telephone] || ""
68
+ @address1 = props[:address1] || ""
69
+ @address2 = props[:address2] || ""
70
+ @sections = Array.new
71
+ end
72
+
73
+ # Add section
74
+ def add_section(section)
75
+ self.sections << section
76
+ self
77
+ end
78
+
79
+ # Create new section and add to sections
80
+ def create_section(props={}, &block)
81
+ section = Section.new(props)
82
+ block.call(section) if block
83
+ self.add_section(section)
84
+ self
85
+ end
86
+
87
+ #
88
+ def has_url?
89
+ !self.url.blank?
90
+ end
91
+
92
+ #
93
+ def has_email?
94
+ !self.email.blank?
95
+ end
96
+
97
+ #
98
+ def has_telephone?
99
+ !self.telephone.blank?
100
+ end
101
+
102
+ #
103
+ def has_address1?
104
+ !self.address1.blank?
105
+ end
106
+
107
+ #
108
+ def has_address2?
109
+ !self.address2.blank?
110
+ end
111
+
112
+ #
113
+ def has_sections?
114
+ !self.sections.empty?
115
+ end
116
+
117
+ # Returns an array of lines that has the contact info
118
+ def header_lines
119
+ elements = []
120
+ [:address1, :address2, :telephone, :email, :url].each do |element|
121
+ elements << self.send(element) unless self.send(element).blank?
122
+ end
123
+ lines = []
124
+ elements.each_slice(2) { |pair| lines << pair.join(" • ") }
125
+ lines
126
+ end
127
+
128
+ end #class Resume
129
+
130
+
131
+ # = Section
132
+ # Represents a section in the resume
133
+ class Section
134
+ # Section title
135
+ attr_accessor :title
136
+
137
+ # Section paragraph
138
+ attr_accessor :para
139
+
140
+ # List of periods
141
+ attr_reader :periods
142
+
143
+ # List of items
144
+ attr_reader :items
145
+
146
+ #
147
+ def initialize(props={})
148
+ @title = props[:title] || ""
149
+ @para = props[:para] || ""
150
+ @items = Array.new
151
+ @periods = Array.new
152
+ end
153
+
154
+ #
155
+ def has_paragraph?
156
+ !self.para.blank?
157
+ end
158
+
159
+ def has_para?
160
+ self.has_paragraph?
161
+ end
162
+
163
+ #
164
+ def has_items?
165
+ !self.items.empty?
166
+ end
167
+
168
+ #
169
+ def has_periods?
170
+ !self.periods.empty?
171
+ end
172
+
173
+ #
174
+ def has_title?
175
+ !self.title.blank?
176
+
177
+ end
178
+
179
+ # Creates a period and adds it to the list
180
+ def create_period(props={}, &block)
181
+ period = Period.new(props)
182
+ block.call(period) if block
183
+ self.add_period(period)
184
+ self
185
+ end
186
+
187
+ # Adds a period
188
+ def add_period(period)
189
+ self.periods << period
190
+ end
191
+
192
+ # Ads an item
193
+ def add_item(item)
194
+ self.items << item
195
+ end
196
+
197
+ # Creates an item and adds it to the list
198
+ def create_item(props={}, &block)
199
+ item = Item.new(props)
200
+ block.call(item) if block
201
+ self.add_item(item)
202
+ self
203
+ end
204
+ end
205
+
206
+
207
+ # = Period
208
+ # Represents a period in the section
209
+ class Period
210
+ # Period title
211
+ attr_accessor :title
212
+
213
+ # Period location
214
+ attr_accessor :location
215
+
216
+ # Period organization
217
+ attr_accessor :organization
218
+
219
+ # Period start date
220
+ attr_accessor :dtstart
221
+
222
+ # Period end date
223
+ attr_accessor :dtend
224
+
225
+ # List of items
226
+ attr_reader :items
227
+
228
+ #
229
+ def initialize(props={})
230
+ @title = props[:title] || ""
231
+ @location = props[:location] || ""
232
+ @organization = props[:organization] || ""
233
+ @dtstart = props[:dtstart] || nil
234
+ @dtend = props[:dtend] || nil
235
+ @items = Array.new
236
+ end
237
+
238
+ #
239
+ def has_title?
240
+ !self.title.blank?
241
+ end
242
+
243
+ def has_location?
244
+ !self.location.blank?
245
+ end
246
+
247
+ def has_organization?
248
+ !self.organization.blank?
249
+ end
250
+
251
+ def has_dtstart?
252
+ !self.dtstart.blank?
253
+ end
254
+
255
+ def has_dtend?
256
+ !self.dtend.blank?
257
+ end
258
+
259
+ def has_items?
260
+ !self.items.empty?
261
+ end
262
+
263
+ # Adds an item
264
+ def add_item(item)
265
+ self.items << item
266
+ end
267
+
268
+ # Creates an item and adds it to the list
269
+ def create_item(props={}, &block)
270
+ item = Item.new(props)
271
+ block.call(item) if block
272
+ self.add_item(item)
273
+ item
274
+ end
275
+
276
+ # The period details in a single line
277
+ def line
278
+ elements = []
279
+ elements << self.organization if self.has_organization?
280
+ elements << self.location if self.has_location?
281
+ if self.has_dtstart? && self.has_dtend?
282
+ date = " (#{self.dtstart} - #{self.dtend})"
283
+ elsif self.has_dtstart? || self.has_dtend?
284
+ value = self.has_dtstart? ? self.dtstart : self.dtend
285
+ date = " (#{value})"
286
+ else
287
+ date = ''
288
+ end
289
+ elements.join(", ").concat("#{date}")
290
+ end
291
+ end
292
+
293
+
294
+ # = Item
295
+ # Represents an item in a period or section. Items are usually
296
+ # bulleted items that are listed in order
297
+ class Item
298
+ # The item text
299
+ attr_accessor :text
300
+
301
+ #
302
+ def initialize(props={})
303
+ @text = props[:text] || ""
304
+ end
305
+ end
306
+
307
+ end
@@ -0,0 +1,107 @@
1
+ #--
2
+ # Copyright (c) 2009 Virgil Dimaguila
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person
5
+ # obtaining a copy of this software and associated documentation
6
+ # files (the "Software"), to deal in the Software without
7
+ # restriction, including without limitation the rights to use,
8
+ # copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the
10
+ # Software is furnished to do so, subject to the following
11
+ # conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
+ # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
+ # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
+ # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
+ # OTHER DEALINGS IN THE SOFTWARE.
24
+ #++
25
+
26
+ module ResumeTools
27
+ module TextReader
28
+ class ParseException < Exception
29
+ end
30
+
31
+ module ClassMethods
32
+ require 'treetop'
33
+
34
+ Treetop.load File.join(File.dirname(__FILE__), '..', 'grammars', 'resume.treetop')
35
+
36
+ # Builds a new Resume instance from text
37
+ def from_text(text)
38
+ parser = ::ResumeParser.new
39
+ result = parser.parse(text)
40
+
41
+ if result.nil?
42
+ raise ParseException.new(parser.failure_reason)
43
+ end
44
+
45
+ resume = ResumeTools::Resume.new
46
+ current_section = nil
47
+ current_period = nil
48
+
49
+ result.elements.each do |element|
50
+ case element.data_type
51
+ when :item
52
+ item = ::ResumeTools::Item.new(:text => element.value)
53
+ if current_period
54
+ current_period.add_item(item)
55
+ elsif current_section
56
+ current_section.add_item(item)
57
+ end
58
+ when :period
59
+ current_period = ::ResumeTools::Period.new(:title => element.value)
60
+ current_section.add_period(current_period) if current_section
61
+ when :section
62
+ current_period = nil # Reset period
63
+ current_section = ::ResumeTools::Section.new(:title => element.value)
64
+ resume.add_section(current_section)
65
+ when :period_location
66
+ current_period.location = element.value if current_period
67
+ when :period_organization
68
+ current_period.organization = element.value if current_period
69
+ when :period_dates
70
+ if current_period
71
+ dates = element.value.split("to", 2).map { |d| d.strip }
72
+ if dates.length == 1
73
+ current_period.dtend = dates[0]
74
+ current_period.dtstart = nil
75
+ elsif dates.length == 2
76
+ current_period.dtstart = dates[0]
77
+ current_period.dtend = dates[1]
78
+ end
79
+ end
80
+ when :paragraph
81
+ current_section.para = element.value if current_section
82
+ when :contact_name
83
+ resume.full_name = element.value
84
+ when :contact_telephone
85
+ resume.telephone = element.value
86
+ when :contact_email
87
+ resume.email = element.value
88
+ when :contact_address
89
+ if resume.address1.blank?
90
+ resume.address1 = element.value
91
+ elsif resume.address2.blank?
92
+ resume.address2 = element.value
93
+ end
94
+ when :contact_url
95
+ resume.url = element.value
96
+ end
97
+ end
98
+
99
+ resume
100
+ end
101
+ end
102
+ end
103
+
104
+ class << Resume
105
+ include TextReader::ClassMethods
106
+ end
107
+ end
@@ -0,0 +1,36 @@
1
+ #--
2
+ # Resume Tools, Copyright (c) 2009 Virgil Dimaguila
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person
5
+ # obtaining a copy of this software and associated documentation
6
+ # files (the "Software"), to deal in the Software without
7
+ # restriction, including without limitation the rights to use,
8
+ # copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the
10
+ # Software is furnished to do so, subject to the following
11
+ # conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
+ # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
+ # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
+ # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
+ # OTHER DEALINGS IN THE SOFTWARE.
24
+ #++
25
+
26
+ unless defined? ResumeTools::VERSION
27
+ module ResumeTools
28
+ module VERSION
29
+ MAJOR = 0
30
+ MINOR = 2
31
+ TINY = 7
32
+ BITSY = 0
33
+ STRING = [MAJOR, MINOR, TINY, BITSY].join('.')
34
+ end
35
+ end
36
+ end