mork 0.0.12 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f6930d8ee718dadb56c51c8f4ab776a489b017ac
4
- data.tar.gz: 8cbaef664dc24c91748e4f4cfb61724a7c38e2ef
3
+ metadata.gz: cb22bdfc594a05367dee16e6d9f214523d7c111c
4
+ data.tar.gz: 2bcafa2a1c6f0af97cb8da71bb586c10c607d817
5
5
  SHA512:
6
- metadata.gz: 3ae5c320ba47ce34331bcf0d5bbff6e8dc7a2fdc359de092843f54bff6bbf545430ccf8f294ac4e79ec9c13217980f8319079a5ba11d7b8670ddae49f62e9109
7
- data.tar.gz: 76c6f22dced2dc12e41534d51066a1c9e8c07b1cd3c0fbb5fcc7f63d12b04dcb7d034bb01549732e643879531615e0bdfb3d7853002d9245a3e8d892f2505be1
6
+ metadata.gz: 39db655371def69bc1d6c3db65bb1f6fece0c14fd347fda7621714415775859823eaafff2d87e5da8513d4a994017b548b8fc625313f8b01ad3fb7ceee87777c
7
+ data.tar.gz: d727fdde4bacbd0b5ed86f59afe3382441a76f3eec11dc1bcae5b11d8a866f04f807c1458c6c1edbac96029fa84406117ae0f4e6a6ad259e55c4c60cca586b71
data/.gitignore CHANGED
@@ -7,4 +7,5 @@ tmp/*
7
7
  .rspec
8
8
  .yardoc
9
9
  .ruby-version
10
- .ruby-gemset
10
+ .ruby-gemset
11
+ .rspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Giuseppe
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
data/README.md CHANGED
@@ -1,31 +1,29 @@
1
- Mork
2
- ====
1
+ # Mork
3
2
 
4
3
  A ruby [optical mark recognition](http://en.wikipedia.org/wiki/Optical_mark_recognition) (OMR) library aimed at accomplishing two tasks in the context of paper-based, multiple-choice tests and surveys:
5
4
 
6
- 1. generating [response sheets](/spec/samples/sample01.pdf) in PDF format
7
- 2. capturing the responses provided on the [printed sheet](/spec/samples/sample01.jpg) by a human with a pen or a pencil.
5
+ 1. generating [response sheets](/spec/samples/sheet.jpg) in PDF format
6
+ 2. capturing the responses provided on the [printed sheet](/spec/samples/sample_gray.jpg) by a human with a pen or a pencil.
7
+
8
+ ## Assumptions and limitations
8
9
 
9
- Assumptions and limitations
10
- ---------------------------
11
10
  Mork is a low-level library, and very much work in progress. It is not, and will likely never be a complete OMR solution. While suggestions and contributions are more than welcome, for the time being several assumptions and restrictions to what the library is capable of apply.
12
11
 
13
- - the PDF files generated by Mork [such as this one](/spec/samples/sample01.pdf) are intended to be printed on regular printer paper
14
- - all items must fit within the allocated response area of a single sheet
15
- - after collecting the responses, a filled-out form can be acquired as a bitmap image by a normal optical scanner or camera (i.e., no specialized equipment is necessary)
12
+ - the PDF files generated by Mork are intended to be printed on regular printer paper
13
+ - the entire response sheet must fit into a single page
14
+ - after collecting the responses, a filled-out form should be acquired as a JPEG, PNG, or PDF image by a normal optical scanner or camera (i.e., no specialized equipment is necessary)
16
15
  - the response sheet contains the following items:
17
16
  - registration marks at each page corner
18
17
  - a bar code along the bottom margin to uniquely identify the sheet
19
18
  - a header area to print arbitrary information
20
19
  - a response area containing a list of numbered items (questions)
21
- - each item contains an arbitrary number of choices, each marked with a capital letter (A, B, C, ...). In order to maximize contrast, assuming that responses will be given using a black or blue pen, choice cells are printed in red
20
+ - each item contains an arbitrary number of choice “cells”, each marked with a capital letter (A, B, C, ...)
22
21
  - the far right side of the response area is reserved for a column of calibration cells that must remain blank
23
- - with some restrictions, the number of columns in the response area, the numer of items, the number of choices per item, the size and shape of the choice cells can be set by the user
22
+ - it is entirely up to the user to provide parameters that produce the desired response sheet layout; in particular, making sure that the header elements and choice cells fit in the available space, as Mork does not provide any type of "sanity" check at this time.
24
23
 
25
- Creating response sheets
26
- ------------------------
24
+ ## Getting started
27
25
 
28
- To create a small ruby project for testing purposes, cd into a directory of choice, then execute the following shell commands:
26
+ To create a small ruby project that uses Mork, `cd` into a directory of choice, then execute the following shell commands:
29
27
 
30
28
  ```
31
29
  mkdir mork_test
@@ -37,11 +35,22 @@ echo "include Mork" >> mork_test.rb
37
35
  bundle install
38
36
  ```
39
37
 
40
- Creating response sheets is done through the `Mork::SheetPDF` class.
38
+ Edit the file `mork_test.rb` with the code snippets below, then execute the following shell command to see the result:
39
+
40
+ bundle exec ruby mork_test.rb
41
+
42
+ ## Generating response sheets with `SheetPDF`
43
+
44
+ Response sheets are created through the `Mork::SheetPDF` class. Two pieces of information must be provided to the class constructor to produce a meaningful object:
45
+
46
+ - **content**: what to place on the sheet, such as how many response items and choices, what to write in the header, the number to print as a barcode
47
+ - **layout**: sizes, margins, spacing, fonts, etc., of each of the printed elements
48
+
49
+ Let’s look at each argument in turn.
41
50
 
42
- [...work in progress...]
51
+ ### content
43
52
 
44
- For example, add the following code to `mork_test.rb`:
53
+ The `content` argument should be a hash like the following:
45
54
 
46
55
  ```ruby
47
56
  content = {
@@ -59,97 +68,109 @@ content = {
59
68
  signature: 'Signature'
60
69
  }
61
70
  }
62
- s = SheetPDF.new content
63
- s.save 'sheet.pdf'
64
- system 'open sheet.pdf' # this works in OSX
65
71
  ```
66
72
 
67
- In the shell, execute the following and inspect the output PDF file
68
-
69
- bundle exec ruby mork_test.rb
73
+ These are the key-value pairs that the `content` hash should contain:
70
74
 
71
- The “content” hash provides SheetPDF with the information necessary to create a meaningful response sheet. These are the key-value pairs that the hash should contain:
75
+ - **barcode**: an integer number, the sheet's unique identifier
76
+ - **choices**: an array of integers, specifiying the number of items in the test (the length of the array) and the number of choices available for each item (the array values)
77
+ - **header**: a (sub)hash of key-value pairs defining the content of named header elements; in each pair, the key is the name of one header element, while the value is the rendered content; the actually available elements are defined in the `layout` (see below)
72
78
 
73
- - `barcode`: an integer number, the sheet's unique identifier
74
- - `choices`: an array of integers, specifiying the number of items in the test (the length of the array) and the number of choices available for each item (the array values)
75
- - `header`: a hash of key-value pairs defining the content of named header elements; in each pair, the key is the name of one header element, while the value is the rendered content; the actually available elements are defined in the Grid object (see below)
79
+ ### layout
76
80
 
77
- It's easy to see that by iterating over a series of `content` hashes you can produce any number of sheets, all based on the same layout but each containing unique information (notably the barcode, but also names, dates, etc.)
81
+ The layout argument is also defined as a hash, but because of its length and since the layout often stays identical across many response sheets, it is usually more convenient to write the information in a YAML file and pass its path/filename to the `SheetPDF` constructor instead. Here is the YAML version of a standard layout hash. Please note that the parameters with an (*) in the comment have no effect on PDF production, but are relevant to OMR scan (see further below).
78
82
 
79
- But where is the layout itself defined? In the above example, creating the SheetPDF with a single initialization parameter (the `content` hash) caused a default boilerplate layout to be invoked. In real life, however, you will want to have full control of the layout. This is accomplished by passing a `Mork::Grid` object as a second argument in the SheetPDF constructor call.
83
+ ```yaml
84
+ page_size: # all measurements in mm
85
+ width: 210 # width of the paper sheet
86
+ height: 297 # height of the paper sheet
87
+ reg_marks:
88
+ margin: 10 # distance from each page border to registration mark center
89
+ radius: 2.5 # registration mark radius
90
+ search: 12 # initial size of the registration mark search area (*)
91
+ offset: 2 # distance between the search area and each page border (*)
92
+ header:
93
+ name: # ‘name’ is just a label; you can add arbitrary header elements
94
+ top: 5 # margin relative to registration frame top side
95
+ left: 7.5 # margin relative to registration frame left side
96
+ width: 170 # text will be fitted to this width
97
+ size: 14 # font size
98
+ title:
99
+ top: 15
100
+ left: 7.5
101
+ width: 180
102
+ size: 12
103
+ code:
104
+ top: 5
105
+ left: 165
106
+ width: 20
107
+ size: 14
108
+ signature:
109
+ top: 30
110
+ left: 7.5
111
+ width: 120
112
+ height: 15
113
+ size: 7
114
+ box: true # header element will be enclosed in a box
115
+ items:
116
+ top: 55.5 # response area margin, relative to reg frame
117
+ left: 10.5 # response area margin, relative to reg frame
118
+ rows: 30 # number of items per column
119
+ columns: 4 # number of columns
120
+ column_width: 44 #
121
+ x_spacing: 7 # horizontal distance between ajacent cell centers
122
+ y_spacing: 7 # vertical distance between ajacent cell centers
123
+ cell_width: 6 # width of each choice and calibration cell
124
+ cell_height: 5 # height of each choice and calibration cell
125
+ max_cells: 5 # maximum number of choices per item
126
+ font_size: 9 # size of both the item number and choice cell letter
127
+ number_width: 8 #
128
+ number_margin: 2 # margin between
129
+ barcode:
130
+ bits: 40 # the maximum sheet identifier is 2 to the power or bits
131
+ left: 15 # distance between registration frame side and the first barcode bit
132
+ width: 3 # width of each barcode bit
133
+ height: 2.5 # height of each barcode bit from the registration frame bottom side
134
+ spacing: 4 # horizontal distance between adjacent barcode bit centers
135
+ ```
80
136
 
81
- The Grid is a layout descriptor, it tells the SheetPDF object in detail where to render what on the sheet. To get a rough idea of the information managed by a Grid, try this:
137
+ Assuming that the above text is written in a file named `layout.yml`, here's how to create a `SheetPDF` object and write the PDF file to disk:
82
138
 
83
139
  ```ruby
84
- g = Grid.new
85
- g.show
140
+ s = SheetPDF.new content, 'layout.yml'
141
+ s.write 'sheet.pdf'
142
+ system 'open sheet.pdf' # this works in OSX
86
143
  ```
87
144
 
88
- The YAML-formatted output you see is the full list of parameters that describe the default Grid.
145
+ It's easy to see that by iterating over a series of `content` hashes you can produce any number of sheets, all based on the same layout but each containing unique information (notably the barcode, but also names, dates, etc.)
89
146
 
90
- ```yaml
91
- ---
92
- :page_size:
93
- :width: 210
94
- :height: 297
95
- :regmarks:
96
- :margin: 10
97
- :radius: 2.5
98
- :search: 10
99
- :offset: 2
100
- :header:
101
- :name:
102
- :top: 5
103
- :left: 7.5
104
- :width: 170
105
- :size: 14
106
-
107
- ...more...
108
- ```
147
+ If the `layout` argument is omitted, Mork will search for a file named `layout.yml` and load it. If such file cannot be found, Mork will fall back to a default, boilerplate layout (incidentally, this is the layout shown above).
109
148
 
110
- Thus, if you replace the call to SheetPDF with the following:
149
+ ## Scoring response sheets with `SheetOMR`
111
150
 
112
- ```ruby
113
- s = SheetPDF.new content, Grid.new
114
- ```
151
+ Assuming that a person has filled out a response sheet by darkening with a pen the selected choices, and that sheet has been acquired as an image file, response scoring is performed by the `Mork::SheetOMR` class. Again, two pieces of information must be provided to the class constructor:
115
152
 
116
- ...you get exactly the same result as before. In order to actually customize the layout, the Grid object must be constructed according to your own specifications. One way to initialize a custom Grid is to send the constructor a YAML path/file name. Copy the file `grid01.yml` from the `spec/samples` directory to your working directory. Edit some values, save, and execute:
153
+ - **image**: the path/filename of the bitmap image (currently accepts JPG, JPEG, PNG, PDF extensions; a resolution of 150-200 dpi is usually more than sufficient to obtain accurate readings)
154
+ - **layout**: same as for the SheetPDF class
117
155
 
118
- ```ruby
119
- s = SheetPDF.new content, Grid.new('grid01.yml')
120
- s.save 'sheet.pdf'
121
- ```
122
-
123
- Although this will work as well:
156
+ The following code shows how to create and analyze a SheetOMR based on a bitmap file named `image.jpg`:
124
157
 
125
158
  ```ruby
126
- s = SheetPDF.new content, 'grid01.yml'
127
- s.save 'sheet.pdf'
159
+ # instantiating the object
160
+ s = SheetOMR.new 'image.jpg', 'layout.yml'
161
+ # detecting darkened choice cells for the 100 items
162
+ chosen = s.mark_array 100
128
163
  ```
129
164
 
130
- Please note that currently there are no sanity checks on Grid parameters. The user is entirely responsible for providing values that actually produce the desired layout.
131
-
132
- Scoring response sheets
133
- -----------------------
134
-
135
- Copy the file `sample01.jpg` from `spec/samples` to your working directory, along with a fresh copy of `grid01.yml` and run the following:
165
+ If all goes well, the `chosen` array will contain 100 sub-arrays, each containing the list of darkened choices for that item, where the first cell is indicated by a 0, the second by a 1, etc. It is also possible to show the scoring graphically:
136
166
 
137
167
  ```ruby
138
- s = SheetOMR.new 'sample01.jpg', 'grid01.yml'
168
+ s = SheetOMR.new 'image.jpg', 'layout.yml'
139
169
  s.highlight
140
170
  s.write 'highlights.jpg'
141
171
  system 'open highlights.jpg' # OSX only
142
172
  ```
143
173
 
144
- Print out the PDF file you produced, and fill in a few response cells with a black pen. Be sure to also fill in the calibration ‘T’ cell. Now scan the sheet and save the image as a JPEG file (e.g. `img01.jpg`). A resolution of 150-200 dpi should be sufficient. Place the JPEG file in your working directory and run the following:
145
-
146
- License
147
- -------
148
-
149
- Copyright (c) 2014 Giuseppe Bertini
150
-
151
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
152
-
153
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
174
+ #### Wait, why Mork?
154
175
 
155
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
176
+ Because I used to have a crush on Mindy
data/lib/mork/grid.rb CHANGED
@@ -11,8 +11,8 @@ module Mork
11
11
  @params = DGRID
12
12
  case options
13
13
  when NilClass
14
- if File.exists?('config/grid.yml')
15
- @params.merge! symbolize YAML.load_file('config/grid.yml')
14
+ if File.exists?('layout.yml')
15
+ @params.merge! symbolize YAML.load_file('layout.yml')
16
16
  end
17
17
  when Hash
18
18
  @params.merge! symbolize options
@@ -25,7 +25,7 @@ module Mork
25
25
 
26
26
  # Puts out the Grid parameters in YAML format; the entire hash is displayed
27
27
  # if no arguments are given; you can specify what to show by passing one of:
28
- # :page_size, :regmarks, :header, :items, :barcode, :control
28
+ # :page_size, :reg_marks, :header, :items, :barcode, :control
29
29
  def show(subset=nil)
30
30
  out = subset ? @params[subset] : @params
31
31
  puts out.to_yaml
@@ -78,12 +78,6 @@ module Mork
78
78
  # ===========
79
79
  # = barcode =
80
80
  # ===========
81
-
82
- # def barcode_bit_area(i)
83
- # raise "Invalid barcode bit" if i >= barcode_bits
84
- # cal_cell_x i+1
85
- # end
86
-
87
81
  def barcode_bit_x(i)
88
82
  @params[:barcode][:left] + @params[:barcode][:spacing] * i
89
83
  end
@@ -91,26 +85,25 @@ module Mork
91
85
  # ===============================
92
86
  # = Simple parameter extraction =
93
87
  # ===============================
94
- def barcode_y() reg_frame_height - barcode_height end
95
- def barcode_height() @params[:barcode][:height].to_f end
96
- def barcode_width() @params[:barcode][:width].to_f end
97
- def cell_width() @params[:items][:cell_width].to_f end
98
- def cell_height() @params[:items][:cell_height].to_f end
99
- def cell_spacing() @params[:items][:x_spacing].to_f end
100
- def item_spacing() @params[:items][:y_spacing].to_f end
101
- def column_width() @params[:items][:column_width].to_f end
102
- def row_spacing() @params[:items][:y_spacing].to_f end
103
- def first_x() @params[:items][:first_x].to_f end
104
- def first_y() @params[:items][:first_y].to_f end
105
- def rows() @params[:items][:rows] end
106
- def columns() @params[:items][:columns] end
107
- def reg_search() @params[:regmarks][:search].to_f end
108
- def reg_off() @params[:regmarks][:offset].to_f end
109
- def reg_frame_width() page_width - reg_margin * 2 end
110
- def reg_frame_height() page_height - reg_margin * 2 end
111
- def page_width() @params[:page_size][:width].to_f end
112
- def page_height() @params[:page_size][:height].to_f end
113
- def reg_margin() @params[:regmarks][:margin].to_f end
114
- def reg_radius() @params[:regmarks][:radius].to_f end
88
+ def barcode_y() reg_frame_height - barcode_height end
89
+ def barcode_height() @params[:barcode][:height].to_f end
90
+ def barcode_width() @params[:barcode][:width].to_f end
91
+ def cell_width() @params[:items][:cell_width].to_f end
92
+ def cell_height() @params[:items][:cell_height].to_f end
93
+ def cell_spacing() @params[:items][:x_spacing].to_f end
94
+ def item_spacing() @params[:items][:y_spacing].to_f end
95
+ def column_width() @params[:items][:column_width].to_f end
96
+ def first_x() @params[:items][:left].to_f end
97
+ def first_y() @params[:items][:top].to_f end
98
+ def rows() @params[:items][:rows] end
99
+ def columns() @params[:items][:columns] end
100
+ def reg_search() @params[:reg_marks][:search].to_f end
101
+ def reg_off() @params[:reg_marks][:offset].to_f end
102
+ def reg_frame_width() page_width - reg_margin * 2 end
103
+ def reg_frame_height() page_height - reg_margin * 2 end
104
+ def page_width() @params[:page_size][:width].to_f end
105
+ def page_height() @params[:page_size][:height].to_f end
106
+ def reg_margin() @params[:reg_marks][:margin].to_f end
107
+ def reg_radius() @params[:reg_marks][:radius].to_f end
115
108
  end
116
109
  end
@@ -7,12 +7,12 @@ module Mork
7
7
  width: 210,
8
8
  height: 297
9
9
  }, # page end
10
- regmarks: {
10
+ reg_marks: {
11
11
  margin: 10,
12
12
  radius: 2.5,
13
13
  search: 10,
14
14
  offset: 2
15
- }, # regmarks end
15
+ }, # reg_marks end
16
16
  header: {
17
17
  name: {
18
18
  top: 5,
@@ -47,8 +47,8 @@ module Mork
47
47
  rows: 30,
48
48
  # from the top-left registration mark
49
49
  # to the center of the first choice cell
50
- first_x: 10.5,
51
- first_y: 55.5,
50
+ left: 10.5,
51
+ top: 55.5,
52
52
  # between choices
53
53
  x_spacing: 7,
54
54
  # between rows
data/lib/mork/mimage.rb CHANGED
@@ -65,6 +65,16 @@ module Mork
65
65
  end
66
66
  end
67
67
 
68
+ def cross_cells!(cells)
69
+ cells = [cells] if cells.is_a? Hash
70
+ cells.each do |c|
71
+ out = Magick::Draw.new
72
+ out.stroke 'yellow'
73
+ out.stroke_width 3
74
+ out.line
75
+ end
76
+ end
77
+
68
78
  def join!(p)
69
79
  poly = Magick::Draw.new
70
80
  poly.fill_opacity 0
@@ -98,9 +98,6 @@ module Mork
98
98
  @crop.highlight_cells! @grom.calibration_cell_areas
99
99
  @crop.highlight_rect! [@grom.ink_black_area, @grom.paper_white_area]
100
100
  @crop.highlight_rect! @grom.barcode_bit_areas
101
- # @grom.barcode_bits.times do |bit|
102
- # @crop.highlight_rect! @grom.barcode_bit_area bit
103
- # end
104
101
  end
105
102
 
106
103
  def highlight_marked
data/lib/mork/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Mork
2
- VERSION = "0.0.12"
2
+ VERSION = "0.1.0"
3
3
  end
data/mork.gemspec CHANGED
@@ -8,13 +8,12 @@ Gem::Specification.new do |s|
8
8
  s.licenses = ['MIT']
9
9
  s.authors = ["Giuseppe Bertini"]
10
10
  s.email = ["giuseppe.bertini@gmail.com"]
11
- s.homepage = ""
12
- s.summary = %q{Optical mark recognition of multiple-choice response sheets}
13
- s.description = %q{sorry, no docs until v.0.1.0}
14
- s.rubyforge_project = "mork"
11
+ s.homepage = 'https://github.com/giuseb/mork'
12
+ s.summary = %q{Optical mark recognition of multiple-choice tests and surveys}
13
+ s.description = %q{Producing response sheets as PDF files and automatically scoring manually filled-out sheets}
15
14
 
16
15
  s.files = `git ls-files`.split("\n")
17
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.test_files = `git ls-files -- {spec}/*`.split("\n")
18
17
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
18
  s.require_paths = ["lib"]
20
19