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 +4 -4
- data/.gitignore +2 -1
- data/LICENSE +22 -0
- data/README.md +104 -83
- data/lib/mork/grid.rb +23 -30
- data/lib/mork/grid_const.rb +4 -4
- data/lib/mork/mimage.rb +10 -0
- data/lib/mork/sheet_omr.rb +0 -3
- data/lib/mork/version.rb +1 -1
- data/mork.gemspec +4 -5
- data/spec/mork/grid_omr_spec.rb +1 -1
- data/spec/mork/grid_spec.rb +1 -1
- data/spec/mork/sheet_omr_spec.rb +2 -2
- data/spec/mork/sheet_pdf_spec.rb +1 -1
- data/spec/samples/grid160.yml +3 -3
- data/spec/samples/layout.yml +51 -0
- data/spec/samples/sheet.jpg +0 -0
- metadata +11 -51
- data/cucu.jpg +0 -0
- data/spec/samples/code_sample.pdf +0 -85
- data/spec/samples/code_sample.png +0 -0
- data/spec/samples/code_zero.pdf +0 -79
- data/spec/samples/content01.yml +0 -0
- data/spec/samples/grid01.yml +0 -57
- data/spec/samples/grid02.yml +0 -57
- data/spec/samples/grid_omr_01.yml +0 -28
- data/spec/samples/sample04.jpg +0 -0
- data/spec/samples/sample_color.pdf +0 -0
- data/spec/samples/sheet666.pdf +0 -12566
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cb22bdfc594a05367dee16e6d9f214523d7c111c
|
4
|
+
data.tar.gz: 2bcafa2a1c6f0af97cb8da71bb586c10c607d817
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 39db655371def69bc1d6c3db65bb1f6fece0c14fd347fda7621714415775859823eaafff2d87e5da8513d4a994017b548b8fc625313f8b01ad3fb7ceee87777c
|
7
|
+
data.tar.gz: d727fdde4bacbd0b5ed86f59afe3382441a76f3eec11dc1bcae5b11d8a866f04f807c1458c6c1edbac96029fa84406117ae0f4e6a6ad259e55c4c60cca586b71
|
data/.gitignore
CHANGED
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/
|
7
|
-
2. capturing the responses provided on the [printed sheet](/spec/samples/
|
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
|
14
|
-
-
|
15
|
-
- after collecting the responses, a filled-out form
|
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
|
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
|
-
-
|
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
|
-
|
26
|
-
------------------------
|
24
|
+
## Getting started
|
27
25
|
|
28
|
-
To create a small ruby project
|
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
|
-
|
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
|
-
|
51
|
+
### content
|
43
52
|
|
44
|
-
|
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
|
-
|
68
|
-
|
69
|
-
bundle exec ruby mork_test.rb
|
73
|
+
These are the key-value pairs that the `content` hash should contain:
|
70
74
|
|
71
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
85
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
149
|
+
## Scoring response sheets with `SheetOMR`
|
111
150
|
|
112
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
127
|
-
s.
|
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
|
-
|
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 '
|
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
|
-
|
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
|
-
|
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?('
|
15
|
-
@params.merge! symbolize YAML.load_file('
|
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, :
|
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
|
95
|
-
def barcode_height() @params[:barcode][:height].to_f
|
96
|
-
def barcode_width() @params[:barcode][:width].to_f
|
97
|
-
def cell_width() @params[:items][:cell_width].to_f
|
98
|
-
def cell_height() @params[:items][:cell_height].to_f
|
99
|
-
def cell_spacing() @params[:items][:x_spacing].to_f
|
100
|
-
def item_spacing() @params[:items][:y_spacing].to_f
|
101
|
-
def column_width() @params[:items][:column_width].to_f
|
102
|
-
def
|
103
|
-
def
|
104
|
-
def
|
105
|
-
def
|
106
|
-
def
|
107
|
-
def
|
108
|
-
def
|
109
|
-
def
|
110
|
-
def
|
111
|
-
def
|
112
|
-
def
|
113
|
-
def
|
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
|
data/lib/mork/grid_const.rb
CHANGED
@@ -7,12 +7,12 @@ module Mork
|
|
7
7
|
width: 210,
|
8
8
|
height: 297
|
9
9
|
}, # page end
|
10
|
-
|
10
|
+
reg_marks: {
|
11
11
|
margin: 10,
|
12
12
|
radius: 2.5,
|
13
13
|
search: 10,
|
14
14
|
offset: 2
|
15
|
-
}, #
|
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
|
-
|
51
|
-
|
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
|
data/lib/mork/sheet_omr.rb
CHANGED
@@ -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
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
|
13
|
-
s.description = %q{
|
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 -- {
|
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
|
|