akapen 0.0.1
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/.gitignore +17 -0
- data/.rspec +2 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +311 -0
- data/Rakefile +1 -0
- data/akapen.gemspec +27 -0
- data/bin/akapen +29 -0
- data/doc_image/akapen structure.png +0 -0
- data/lib/akapen/version.rb +3 -0
- data/lib/akapen_core.rb +156 -0
- data/lib/akapen_dsl.rb +78 -0
- data/spec/akapen_core_spec.rb +170 -0
- data/spec/akapen_dsl_spec.rb +81 -0
- data/spec/spec_helper.rb +8 -0
- metadata +121 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 tbpgr
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following 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 OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,311 @@
|
|
1
|
+
# Akapen
|
2
|
+
|
3
|
+
Akapen is grading & report generator.
|
4
|
+
|
5
|
+
## Summary
|
6
|
+
|
7
|
+
If you have some students, and you have to check student's test or some report constantly,
|
8
|
+
|
9
|
+
Akapen help your operation more easily.
|
10
|
+
|
11
|
+
you have to do is
|
12
|
+
|
13
|
+
* create test check script each question.
|
14
|
+
|
15
|
+
* create result report template
|
16
|
+
|
17
|
+
* create ok/ng message for each question.
|
18
|
+
|
19
|
+
after setting, Akapen check test & create report automatically.
|
20
|
+
|
21
|
+
## Installation
|
22
|
+
|
23
|
+
Add this line to your application's Gemfile:
|
24
|
+
|
25
|
+
gem 'akapen'
|
26
|
+
|
27
|
+
And then execute:
|
28
|
+
|
29
|
+
$ bundle
|
30
|
+
|
31
|
+
Or install it yourself as:
|
32
|
+
|
33
|
+
$ gem install akapen
|
34
|
+
|
35
|
+
## Structure
|
36
|
+
### Image
|
37
|
+
<img src="./doc_image/akapen structure.png" />
|
38
|
+
|
39
|
+
### akapen_checker.rb
|
40
|
+
this is test check script.
|
41
|
+
|
42
|
+
if you execute 'akapen init', you can get this files's template.
|
43
|
+
|
44
|
+
but you want to create empty new file, you can.
|
45
|
+
|
46
|
+
you must implement this class/methods.
|
47
|
+
|
48
|
+
each questions method must name 'qX', and must return true/false.
|
49
|
+
|
50
|
+
(※X = serial number from 1. for example q1, q2 ...)
|
51
|
+
|
52
|
+
you have to implement id method, to distinguish each submitter.
|
53
|
+
|
54
|
+
id is considered for multi student's tests or reports check.
|
55
|
+
|
56
|
+
sample
|
57
|
+
~~~ruby
|
58
|
+
# encoding: utf-8
|
59
|
+
class AkapenChecker
|
60
|
+
# implement your check logic.(return true / false)
|
61
|
+
def q1
|
62
|
+
# some check logic that returns true/false
|
63
|
+
# you can implement this logic by ruby.
|
64
|
+
# you can implement this logic by another language.
|
65
|
+
# if you use another language, you can get result following command
|
66
|
+
# let = `some command`
|
67
|
+
end
|
68
|
+
|
69
|
+
# implement your check logic.(return true / false)
|
70
|
+
def q2
|
71
|
+
# some check logic that returns true/false
|
72
|
+
end
|
73
|
+
|
74
|
+
# if you want create more questions, you can create q3,q4...
|
75
|
+
|
76
|
+
# return answer users id. this is used in result file name.
|
77
|
+
def id
|
78
|
+
# some id get logic that returns String id.
|
79
|
+
end
|
80
|
+
end
|
81
|
+
~~~
|
82
|
+
|
83
|
+
### Questiontemplate
|
84
|
+
write your report templete by ERB format.
|
85
|
+
|
86
|
+
if you execute 'akapen init', you can get this files's template.
|
87
|
+
|
88
|
+
but you want to create new empty file, you can.
|
89
|
+
|
90
|
+
if you use <%=q_results%>, you can get each test or report result messages.
|
91
|
+
|
92
|
+
other parameter can freely use.
|
93
|
+
|
94
|
+
parameter's contents must write in Questionparameter, and must git it same variable name.
|
95
|
+
|
96
|
+
sample
|
97
|
+
~~~erb
|
98
|
+
Title: <%=title%>
|
99
|
+
Summary: <%=summary%>
|
100
|
+
|
101
|
+
Results
|
102
|
+
<%=q_results%>
|
103
|
+
|
104
|
+
Thanks!!
|
105
|
+
~~~
|
106
|
+
|
107
|
+
### Questionparameter
|
108
|
+
write your report parameter for Questiontemplate.
|
109
|
+
|
110
|
+
if you execute 'akapen init', you can get this files's template.
|
111
|
+
|
112
|
+
but you want to create new empty file, you can.
|
113
|
+
|
114
|
+
you have to define each test result message q1_ok, q1_ng, q2_ok, q2_ng, q3....
|
115
|
+
|
116
|
+
sample
|
117
|
+
~~~ruby
|
118
|
+
title "some title"
|
119
|
+
summary "some summary"
|
120
|
+
|
121
|
+
q1_ok <<-EOS
|
122
|
+
question1: ok
|
123
|
+
EOS
|
124
|
+
q1_ng <<-EOS
|
125
|
+
question1: ng
|
126
|
+
EOS
|
127
|
+
|
128
|
+
q2_ok <<-EOS
|
129
|
+
question2: ok
|
130
|
+
EOS
|
131
|
+
q2_ng <<-EOS
|
132
|
+
question2: ng
|
133
|
+
EOS
|
134
|
+
~~~
|
135
|
+
|
136
|
+
## Usage
|
137
|
+
### akapen init
|
138
|
+
if you execute akapen init, you can get template files [akapen_checker.rb, Questiontemplate, Questionparameter]
|
139
|
+
~~~bash
|
140
|
+
akapen init
|
141
|
+
~~~
|
142
|
+
|
143
|
+
### akapen grade
|
144
|
+
before execute this command, you must create [akapen_checker.rb, Questiontemplate, Questionparameter].
|
145
|
+
|
146
|
+
[akapen_checker.rb, Questiontemplate, Questionparameter] can get by 'akapen init' command.
|
147
|
+
|
148
|
+
if you execute akapen grade, you can get grading result report 'akapen_result_id.txt' in current directory.
|
149
|
+
~~~bash
|
150
|
+
akapen grade
|
151
|
+
~~~
|
152
|
+
|
153
|
+
## Pragmatic Usage
|
154
|
+
### 1. Generate Template Files by akapen init
|
155
|
+
~~~bash
|
156
|
+
akapen init
|
157
|
+
~~~
|
158
|
+
|
159
|
+
after generate
|
160
|
+
~~~bash
|
161
|
+
akapen_checker.rb
|
162
|
+
Akapenparameter
|
163
|
+
Akapentemplate
|
164
|
+
~~~
|
165
|
+
|
166
|
+
* akapen_checker.rb
|
167
|
+
~~~ruby
|
168
|
+
# encoding: utf-8
|
169
|
+
class AkapenChecker
|
170
|
+
# implement your check logic.(return true / false)
|
171
|
+
def q1
|
172
|
+
true
|
173
|
+
end
|
174
|
+
|
175
|
+
# implement your check logic.(return true / false)
|
176
|
+
# def q2
|
177
|
+
# true
|
178
|
+
# end
|
179
|
+
|
180
|
+
# return answer users id. this is used in result file name.
|
181
|
+
def id
|
182
|
+
"some_id"
|
183
|
+
end
|
184
|
+
end
|
185
|
+
~~~
|
186
|
+
|
187
|
+
* Akapenparameter
|
188
|
+
~~~ruby
|
189
|
+
title "some title"
|
190
|
+
summary "some summary"
|
191
|
+
|
192
|
+
q1_ok <<-EOS
|
193
|
+
question1: ok
|
194
|
+
EOS
|
195
|
+
q1_ng <<-EOS
|
196
|
+
question1: ng
|
197
|
+
EOS
|
198
|
+
|
199
|
+
q2_ok <<-EOS
|
200
|
+
question2: ok
|
201
|
+
EOS
|
202
|
+
q2_ng <<-EOS
|
203
|
+
question2: ng
|
204
|
+
EOS
|
205
|
+
~~~
|
206
|
+
|
207
|
+
* Akapentemplate
|
208
|
+
~~~erb
|
209
|
+
# write your result report template by erb format.
|
210
|
+
|
211
|
+
# if you want to use each questions response,
|
212
|
+
# use <%=q_results%>.
|
213
|
+
|
214
|
+
# if you want to use some parameter, any word you can use.
|
215
|
+
# for example
|
216
|
+
# title: <%=title%>
|
217
|
+
# summary: <%=summary%>
|
218
|
+
~~~
|
219
|
+
|
220
|
+
### 2. Edit akapen_checker.rb
|
221
|
+
~~~ruby
|
222
|
+
# encoding: utf-8
|
223
|
+
class AkapenChecker
|
224
|
+
# implement your check logic.(return true / false)
|
225
|
+
def q1
|
226
|
+
# actually , you must implement boolean test check logic.
|
227
|
+
false
|
228
|
+
end
|
229
|
+
|
230
|
+
# implement your check logic.(return true / false)
|
231
|
+
def q2
|
232
|
+
# actually , you must implement boolean test check logic.
|
233
|
+
true
|
234
|
+
end
|
235
|
+
|
236
|
+
# return answer users id. this is used in result file name.
|
237
|
+
def id
|
238
|
+
# actually , you must get id information from some file.
|
239
|
+
"some_id"
|
240
|
+
end
|
241
|
+
end
|
242
|
+
~~~
|
243
|
+
|
244
|
+
### 3. Edit Akapentemplate
|
245
|
+
set your report template message.
|
246
|
+
~~~erb
|
247
|
+
Title: <%=title%>
|
248
|
+
Summary: <%=summary%>
|
249
|
+
|
250
|
+
Results
|
251
|
+
<%=q_results%>
|
252
|
+
|
253
|
+
Thanks!!
|
254
|
+
~~~
|
255
|
+
|
256
|
+
### 4. Edit Akapenparameter
|
257
|
+
set your variable messages for Akapentemplate.
|
258
|
+
|
259
|
+
~~~ruby
|
260
|
+
title "some title"
|
261
|
+
summary "some summary"
|
262
|
+
|
263
|
+
q1_ok <<-EOS
|
264
|
+
question1: ok
|
265
|
+
EOS
|
266
|
+
q1_ng <<-EOS
|
267
|
+
question1: ng
|
268
|
+
EOS
|
269
|
+
|
270
|
+
q2_ok <<-EOS
|
271
|
+
question2: ok
|
272
|
+
EOS
|
273
|
+
q2_ng <<-EOS
|
274
|
+
question2: ng
|
275
|
+
EOS
|
276
|
+
~~~
|
277
|
+
|
278
|
+
### 5. Execute akapen grade
|
279
|
+
~~~bash
|
280
|
+
akapen grade
|
281
|
+
~~~
|
282
|
+
|
283
|
+
### 6. check your report
|
284
|
+
~~~bash
|
285
|
+
$ tree
|
286
|
+
Akapenparameter
|
287
|
+
Akapentemplate
|
288
|
+
akapen_checker.rb
|
289
|
+
akapen_result_some_id.txt
|
290
|
+
|
291
|
+
$ cat akapen_result_some_id.txt
|
292
|
+
Title: some title
|
293
|
+
Summary: some summary
|
294
|
+
|
295
|
+
Results
|
296
|
+
question1: ng
|
297
|
+
question2: ok
|
298
|
+
|
299
|
+
Thanks!!
|
300
|
+
~~~
|
301
|
+
|
302
|
+
## History
|
303
|
+
* version 0.0.1 : first release.
|
304
|
+
|
305
|
+
## Contributing
|
306
|
+
|
307
|
+
1. Fork it
|
308
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
309
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
310
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
311
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/akapen.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'akapen/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "akapen"
|
8
|
+
spec.version = Akapen::VERSION
|
9
|
+
spec.authors = ["tbpgr"]
|
10
|
+
spec.email = ["tbpgr@tbpgr.jp"]
|
11
|
+
spec.description = %q{Akapen is grading & report generator}
|
12
|
+
spec.summary = %q{Akapen is grading & report generator}
|
13
|
+
spec.homepage = "https://github.com/tbpgr/akapen"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_runtime_dependency "thor", "~> 0.18.1"
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
spec.add_development_dependency "rspec", "~> 2.14.1"
|
26
|
+
spec.add_development_dependency "simplecov", "~> 0.8.2"
|
27
|
+
end
|
data/bin/akapen
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'akapen/version'
|
3
|
+
require 'akapen_core'
|
4
|
+
require "thor"
|
5
|
+
|
6
|
+
module Akapen
|
7
|
+
#= Akapen CLI
|
8
|
+
class CLI < Thor
|
9
|
+
class_option :help, :type => :boolean, :aliases => '-h', :desc => 'help message.'
|
10
|
+
class_option :version, :type => :boolean, :desc => 'version'
|
11
|
+
default_task :grade
|
12
|
+
|
13
|
+
desc "grade", "check & report"
|
14
|
+
def grade
|
15
|
+
Akapen::Core.new.grade
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "init", "generate templates [akapen_checker.rb, Akapentemplate, Akapenparameter]"
|
19
|
+
def init
|
20
|
+
Akapen::Core.new.init
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "version", "version"
|
24
|
+
def version
|
25
|
+
p Akapen::VERSION
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
Akapen::CLI.start
|
Binary file
|
data/lib/akapen_core.rb
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
require "akapen/version"
|
2
|
+
require "akapen_dsl"
|
3
|
+
require "erb"
|
4
|
+
|
5
|
+
module Akapen
|
6
|
+
#= Akapen::Core
|
7
|
+
class Core
|
8
|
+
#== result file name
|
9
|
+
AKAPEN_RESULT_FILE = "akapen_result_$id$.txt"
|
10
|
+
#== check script template file name
|
11
|
+
AKAPEN_CHECKER_FILE = "akapen_checker.rb"
|
12
|
+
#== check script template
|
13
|
+
AKAPEN_CHECKER_TEMPLATE =<<-EOS
|
14
|
+
# encoding: utf-8
|
15
|
+
class AkapenChecker
|
16
|
+
# implement your check logic.(return true / false)
|
17
|
+
def q1
|
18
|
+
true
|
19
|
+
end
|
20
|
+
|
21
|
+
# implement your check logic.(return true / false)
|
22
|
+
# def q2
|
23
|
+
# true
|
24
|
+
# end
|
25
|
+
|
26
|
+
# return answer users id. this is used in result file name.
|
27
|
+
def id
|
28
|
+
"some_id"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
EOS
|
32
|
+
|
33
|
+
#== report template file name
|
34
|
+
AKAPEN_TEMPLATE_FILE = "Akapentemplate"
|
35
|
+
#== report template template
|
36
|
+
AKAPEN_TEMPLATE_TEMPLATE =<<-EOS
|
37
|
+
# write your result report template by erb format.
|
38
|
+
|
39
|
+
# if you want to use each questions response,
|
40
|
+
# use <%=q_results%>.
|
41
|
+
|
42
|
+
# if you want to use some parameter, any word you can use.
|
43
|
+
# for example
|
44
|
+
# title: <%=title%>
|
45
|
+
# summary: <%=summary%>
|
46
|
+
EOS
|
47
|
+
|
48
|
+
#== report parameter template file name
|
49
|
+
AKAPEN_PARAMETER_FILE = "Akapenparameter"
|
50
|
+
#== report parameter template
|
51
|
+
AKAPEN_PARAMETER_TEMPLATE =<<-END
|
52
|
+
title "some title"
|
53
|
+
summary "some summary"
|
54
|
+
|
55
|
+
q1_ok <<-EOS
|
56
|
+
question1: ok
|
57
|
+
EOS
|
58
|
+
q1_ng <<-EOS
|
59
|
+
question1: ng
|
60
|
+
EOS
|
61
|
+
|
62
|
+
q2_ok <<-EOS
|
63
|
+
question2: ok
|
64
|
+
EOS
|
65
|
+
q2_ng <<-EOS
|
66
|
+
question2: ng
|
67
|
+
EOS
|
68
|
+
END
|
69
|
+
|
70
|
+
# init Akapen::Core
|
71
|
+
def init
|
72
|
+
File.open("./#{AKAPEN_CHECKER_FILE}", "w") {|f|f.puts AKAPEN_CHECKER_TEMPLATE}
|
73
|
+
File.open("./#{AKAPEN_TEMPLATE_FILE}", "w") {|f|f.puts AKAPEN_TEMPLATE_TEMPLATE}
|
74
|
+
File.open("./#{AKAPEN_PARAMETER_FILE}", "w") {|f|f.puts AKAPEN_PARAMETER_TEMPLATE}
|
75
|
+
end
|
76
|
+
|
77
|
+
# check test or report, and generate result report from Akapentemplate & Akapenparameter.
|
78
|
+
def grade
|
79
|
+
require "./akapen_checker"
|
80
|
+
template = read_template
|
81
|
+
parameters = read_parameters
|
82
|
+
dsl = Dsl.new
|
83
|
+
dsl.instance_eval parameters
|
84
|
+
|
85
|
+
test_results = get_test_results
|
86
|
+
id = get_id
|
87
|
+
q_results = get_q_results(dsl, test_results)
|
88
|
+
result = get_report(dsl, q_results, template)
|
89
|
+
File.open(get_output_filename(id), "w") {|f|f.puts result}
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
def read_template
|
94
|
+
unless File.exists? "./#{AKAPEN_TEMPLATE_FILE}"
|
95
|
+
raise AkapenTemplateNotExistsError.new("you must create #{AKAPEN_TEMPLATE_FILE}. create manually or execute 'akapen init' command")
|
96
|
+
end
|
97
|
+
|
98
|
+
File.read("./#{AKAPEN_TEMPLATE_FILE}")
|
99
|
+
end
|
100
|
+
|
101
|
+
def read_parameters
|
102
|
+
AKAPEN_PARAMETER_FILE
|
103
|
+
unless File.exists? "./#{AKAPEN_PARAMETER_FILE}"
|
104
|
+
raise AkapenTemplateNotExistsError.new("you must create #{AKAPEN_PARAMETER_FILE}. create manually or execute 'akapen init' command")
|
105
|
+
end
|
106
|
+
|
107
|
+
File.read("./#{AKAPEN_PARAMETER_FILE}")
|
108
|
+
end
|
109
|
+
|
110
|
+
def get_test_results
|
111
|
+
akapen_checker = AkapenChecker.new
|
112
|
+
test_results = []
|
113
|
+
AkapenChecker.instance_methods.grep(/^q(\d+)$/).sort.each do |m|
|
114
|
+
test_results << akapen_checker.method(m).call
|
115
|
+
end
|
116
|
+
test_results
|
117
|
+
end
|
118
|
+
|
119
|
+
def get_id
|
120
|
+
AkapenChecker.new.id
|
121
|
+
end
|
122
|
+
|
123
|
+
def get_q_results(dsl, test_results)
|
124
|
+
questions = dsl.questions
|
125
|
+
ret = []
|
126
|
+
|
127
|
+
test_results.each_with_index do |result, index|
|
128
|
+
if (result)
|
129
|
+
ret << questions[index].ok
|
130
|
+
else
|
131
|
+
ret << questions[index].ng
|
132
|
+
end
|
133
|
+
end
|
134
|
+
ret.join.chomp
|
135
|
+
end
|
136
|
+
|
137
|
+
def get_report(dsl, q_results, template)
|
138
|
+
dynamic_filed_names = Akapen::Dsl.get_dynamic_field_names
|
139
|
+
code = []
|
140
|
+
dynamic_filed_names.each do |field_name|
|
141
|
+
method_value = dsl.method("_#{field_name}").call
|
142
|
+
code << "#{field_name.to_s} = '#{method_value}'"
|
143
|
+
end
|
144
|
+
code << "erb = ERB.new(template)"
|
145
|
+
code << "erb.result(binding)"
|
146
|
+
eval code.join("\n"), binding
|
147
|
+
end
|
148
|
+
|
149
|
+
def get_output_filename(id)
|
150
|
+
AKAPEN_RESULT_FILE.gsub('$id$', id)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
class AkapenTemplateNotExistsError < StandardError;end
|
155
|
+
class AkapenParameterNotExistsError < StandardError;end
|
156
|
+
end
|
data/lib/akapen_dsl.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Akapen
|
4
|
+
#= Akapen::Dsl
|
5
|
+
class Dsl
|
6
|
+
#== questions information
|
7
|
+
attr_accessor :questions
|
8
|
+
|
9
|
+
class << self
|
10
|
+
#== get dynamic define field names.
|
11
|
+
def get_dynamic_field_names
|
12
|
+
Akapen::Dsl.instance_methods(false).delete_if {|e|e.match /(questions|method_missing)/}.delete_if {|e|e.match /^_.*$/}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
#== init Akapen::Dsl
|
17
|
+
def initialize
|
18
|
+
@questions = []
|
19
|
+
end
|
20
|
+
|
21
|
+
#== create dynamic define field or set question_ok or question_ng
|
22
|
+
#- if you call qX_ok, call set_question_ok
|
23
|
+
#- if you call qX_ng, call set_question_ng
|
24
|
+
#- others, you define field by called name & value.
|
25
|
+
def method_missing(method_name, *args, &block)
|
26
|
+
arg = args[0]
|
27
|
+
return if set_question_ok(method_name, arg)
|
28
|
+
return if set_question_ng(method_name, arg)
|
29
|
+
define_others(method_name, arg)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
def set_question_ok(method_name, ok_message)
|
34
|
+
return unless method_name.to_s.match /^q(\d+)_ok$/
|
35
|
+
|
36
|
+
ret = @questions.find {|qe|qe.no == $1}
|
37
|
+
if ret
|
38
|
+
ret.ok = ok_message
|
39
|
+
else
|
40
|
+
q = Question.new($1)
|
41
|
+
q.ok = ok_message
|
42
|
+
@questions << q
|
43
|
+
end
|
44
|
+
true
|
45
|
+
end
|
46
|
+
|
47
|
+
def set_question_ng(method_name, ng_message)
|
48
|
+
return unless method_name.to_s.match /^q(\d+)_ng$/
|
49
|
+
|
50
|
+
ret = @questions.find {|qe|qe.no == $1}
|
51
|
+
if ret
|
52
|
+
ret.ng = ng_message
|
53
|
+
else
|
54
|
+
q = Question.new($1)
|
55
|
+
q.ng = ng_message
|
56
|
+
@questions << q
|
57
|
+
end
|
58
|
+
true
|
59
|
+
end
|
60
|
+
|
61
|
+
def define_others(method_name, arg)
|
62
|
+
self.class.class_eval "attr_accessor :_#{method_name}"
|
63
|
+
self.class.class_eval <<-EOS
|
64
|
+
def #{method_name}(_#{method_name})
|
65
|
+
@_#{method_name} = _#{method_name}
|
66
|
+
end
|
67
|
+
EOS
|
68
|
+
self.method("#{method_name}").call(arg)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class Question
|
73
|
+
attr_accessor :no, :ok, :ng
|
74
|
+
def initialize(no)
|
75
|
+
@no = no
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,170 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "spec_helper"
|
3
|
+
require "akapen_core"
|
4
|
+
|
5
|
+
describe Akapen::Core do
|
6
|
+
|
7
|
+
context :init do
|
8
|
+
cases = [
|
9
|
+
{
|
10
|
+
case_no: 1,
|
11
|
+
case_title: "init",
|
12
|
+
expected_template: Akapen::Core::AKAPEN_TEMPLATE_TEMPLATE,
|
13
|
+
expected_parameter: Akapen::Core::AKAPEN_PARAMETER_TEMPLATE,
|
14
|
+
expected_checker: Akapen::Core::AKAPEN_CHECKER_TEMPLATE
|
15
|
+
},
|
16
|
+
]
|
17
|
+
|
18
|
+
cases.each do |c|
|
19
|
+
it "|case_no=#{c[:case_no]}|case_title=#{c[:case_title]}" do
|
20
|
+
begin
|
21
|
+
case_before c
|
22
|
+
|
23
|
+
# -- given --
|
24
|
+
akapen_core = Akapen::Core.new
|
25
|
+
|
26
|
+
# -- when --
|
27
|
+
akapen_core.init
|
28
|
+
|
29
|
+
# then
|
30
|
+
actual_template = File.open("#{Akapen::Core::AKAPEN_TEMPLATE_FILE}") {|f|f.read}
|
31
|
+
actual_parameter = File.open("#{Akapen::Core::AKAPEN_PARAMETER_FILE}") {|f|f.read}
|
32
|
+
actual_checker = File.open("#{Akapen::Core::AKAPEN_CHECKER_FILE}") {|f|f.read}
|
33
|
+
expect(actual_template).to eq(c[:expected_template])
|
34
|
+
expect(actual_parameter).to eq(c[:expected_parameter])
|
35
|
+
expect(actual_checker).to eq(c[:expected_checker])
|
36
|
+
ensure
|
37
|
+
case_after c
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def case_before(c)
|
43
|
+
# implement each case before
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
def case_after(c)
|
48
|
+
# implement each case after
|
49
|
+
File.delete(Akapen::Core::AKAPEN_TEMPLATE_FILE) if File.exists? Akapen::Core::AKAPEN_TEMPLATE_FILE
|
50
|
+
File.delete(Akapen::Core::AKAPEN_PARAMETER_FILE) if File.exists? Akapen::Core::AKAPEN_PARAMETER_FILE
|
51
|
+
File.delete(Akapen::Core::AKAPEN_CHECKER_FILE) if File.exists? Akapen::Core::AKAPEN_CHECKER_FILE
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context :grade do
|
57
|
+
AKAPEN_CHECKER_CASE1 =<<-EOS
|
58
|
+
class AkapenChecker
|
59
|
+
# implement your check logic.(return true / false)
|
60
|
+
def q1
|
61
|
+
true
|
62
|
+
end
|
63
|
+
|
64
|
+
# implement your check logic.(return true / false)
|
65
|
+
def q2
|
66
|
+
false
|
67
|
+
end
|
68
|
+
|
69
|
+
# return answer users id. this is used in result file name.
|
70
|
+
def id
|
71
|
+
"some_id"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
EOS
|
75
|
+
|
76
|
+
AKAPEN_TEMPLATE_CASE1 =<<-EOS
|
77
|
+
Title : <%=title%>
|
78
|
+
Summary : <%=summary%>
|
79
|
+
|
80
|
+
Your Answers
|
81
|
+
<%=q_results%>
|
82
|
+
|
83
|
+
Thank you for challenge!
|
84
|
+
EOS
|
85
|
+
|
86
|
+
AKAPEN_PARAMETER_CASE1 =<<-END
|
87
|
+
title "Some Title"
|
88
|
+
summary "Some Summary"
|
89
|
+
|
90
|
+
q1_ok <<-EOS
|
91
|
+
question1: ok
|
92
|
+
EOS
|
93
|
+
q1_ng <<-EOS
|
94
|
+
question1: ng
|
95
|
+
EOS
|
96
|
+
|
97
|
+
q2_ok <<-EOS
|
98
|
+
question2: ok
|
99
|
+
EOS
|
100
|
+
q2_ng <<-EOS
|
101
|
+
question2: ng
|
102
|
+
EOS
|
103
|
+
END
|
104
|
+
|
105
|
+
AKAPEN_RESULT_CASE1 =<<-EOS
|
106
|
+
Title : Some Title
|
107
|
+
Summary : Some Summary
|
108
|
+
|
109
|
+
Your Answers
|
110
|
+
question1: ok
|
111
|
+
question2: ng
|
112
|
+
|
113
|
+
Thank you for challenge!
|
114
|
+
EOS
|
115
|
+
|
116
|
+
cases = [
|
117
|
+
{
|
118
|
+
case_no: 1,
|
119
|
+
case_title: "case_title",
|
120
|
+
id: "some_id",
|
121
|
+
akapen_checker: AKAPEN_CHECKER_CASE1,
|
122
|
+
akapen_template: AKAPEN_TEMPLATE_CASE1,
|
123
|
+
akapen_parameter: AKAPEN_PARAMETER_CASE1,
|
124
|
+
expected: AKAPEN_RESULT_CASE1,
|
125
|
+
},
|
126
|
+
|
127
|
+
# Templateなしのケース
|
128
|
+
# Parameterなしのケース
|
129
|
+
]
|
130
|
+
|
131
|
+
cases.each do |c|
|
132
|
+
it "|case_no=#{c[:case_no]}|case_title=#{c[:case_title]}" do
|
133
|
+
begin
|
134
|
+
case_before c
|
135
|
+
|
136
|
+
# -- given --
|
137
|
+
akapen_core = Akapen::Core.new
|
138
|
+
|
139
|
+
# -- when --
|
140
|
+
akapen_core.grade
|
141
|
+
|
142
|
+
# -- then --
|
143
|
+
result_file = Akapen::Core::AKAPEN_RESULT_FILE.gsub('$id$', c[:id])
|
144
|
+
|
145
|
+
FileTest.exist?("./#{result_file}").should be_true
|
146
|
+
actual = File.read(result_file)
|
147
|
+
expect(actual).to eq(c[:expected])
|
148
|
+
ensure
|
149
|
+
case_after c
|
150
|
+
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def case_before(c)
|
155
|
+
# implement each case before
|
156
|
+
File.open("./#{Akapen::Core::AKAPEN_CHECKER_FILE}", "w") {|f|f.puts c[:akapen_checker]}
|
157
|
+
File.open("./#{Akapen::Core::AKAPEN_TEMPLATE_FILE}", "w") {|f|f.puts c[:akapen_template]}
|
158
|
+
File.open("./#{Akapen::Core::AKAPEN_PARAMETER_FILE}", "w") {|f|f.puts c[:akapen_parameter]}
|
159
|
+
end
|
160
|
+
|
161
|
+
def case_after(c)
|
162
|
+
# implement each case after
|
163
|
+
File.delete(Akapen::Core::AKAPEN_TEMPLATE_FILE) if File.exists? Akapen::Core::AKAPEN_TEMPLATE_FILE
|
164
|
+
File.delete(Akapen::Core::AKAPEN_PARAMETER_FILE) if File.exists? Akapen::Core::AKAPEN_PARAMETER_FILE
|
165
|
+
File.delete(Akapen::Core::AKAPEN_CHECKER_FILE) if File.exists? Akapen::Core::AKAPEN_CHECKER_FILE
|
166
|
+
File.delete(Akapen::Core::AKAPEN_RESULT_FILE.gsub('$id$', c[:id])) if File.exists? Akapen::Core::AKAPEN_RESULT_FILE.gsub('$id$', c[:id])
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "spec_helper"
|
3
|
+
require "akapen_dsl"
|
4
|
+
|
5
|
+
describe Akapen::Dsl do
|
6
|
+
context :method_missing do
|
7
|
+
cases = [
|
8
|
+
{
|
9
|
+
case_no: 1,
|
10
|
+
case_title: "single question",
|
11
|
+
q_method_names: ["q1_ok", "q1_ng"],
|
12
|
+
args: ["ok message", "ng message"],
|
13
|
+
expected_nos: ["1"],
|
14
|
+
expected_oks: ["ok message"],
|
15
|
+
expected_ngs: ["ng message"],
|
16
|
+
},
|
17
|
+
{
|
18
|
+
case_no: 2,
|
19
|
+
case_title: "multi question",
|
20
|
+
q_method_names: ["q1_ok", "q2_ok", "q1_ng", "q2_ng"],
|
21
|
+
args: ["ok message1", "ok message2", "ng message1", "ng message2"],
|
22
|
+
expected_nos: ["1", "2"],
|
23
|
+
expected_oks: ["ok message1", "ok message2"],
|
24
|
+
expected_ngs: ["ng message1", "ng message2"],
|
25
|
+
},
|
26
|
+
{
|
27
|
+
case_no: 3,
|
28
|
+
case_title: "other attributes",
|
29
|
+
other_method_names: ["title", "summary"],
|
30
|
+
args: ["this is title", "this is summary"],
|
31
|
+
expected_others: ["this is title", "this is summary"],
|
32
|
+
}
|
33
|
+
]
|
34
|
+
|
35
|
+
cases.each do |c|
|
36
|
+
it "|case_no=#{c[:case_no]}|case_title=#{c[:case_title]}" do
|
37
|
+
begin
|
38
|
+
case_before c
|
39
|
+
|
40
|
+
# -- given --
|
41
|
+
akapen_dsl = Akapen::Dsl.new
|
42
|
+
|
43
|
+
# -- when --
|
44
|
+
c[:q_method_names].each_with_index do |m, cnt|
|
45
|
+
eval "akapen_dsl.#{c[:q_method_names][cnt]} \"#{c[:args][cnt]}\"", binding
|
46
|
+
end if c[:q_method_names]
|
47
|
+
|
48
|
+
c[:other_method_names].each_with_index do |m, cnt|
|
49
|
+
eval "akapen_dsl.#{c[:other_method_names][cnt]} \"#{c[:args][cnt]}\"", binding
|
50
|
+
end if c[:other_method_names]
|
51
|
+
|
52
|
+
# -- then --
|
53
|
+
c[:expected_nos].each_with_index do |m, cnt|
|
54
|
+
actual = akapen_dsl.questions.find c[:expected_nos][cnt]
|
55
|
+
expect(akapen_dsl.questions[cnt].no).to eq(c[:expected_nos][cnt])
|
56
|
+
expect(akapen_dsl.questions[cnt].ok).to eq(c[:expected_oks][cnt])
|
57
|
+
expect(akapen_dsl.questions[cnt].ng).to eq(c[:expected_ngs][cnt])
|
58
|
+
end if c[:expected_nos]
|
59
|
+
|
60
|
+
c[:expected_others].each_with_index do |m, cnt|
|
61
|
+
actual = akapen_dsl.method("_#{c[:other_method_names][cnt]}").call
|
62
|
+
expect(actual).to eq(m)
|
63
|
+
end if c[:expected_others]
|
64
|
+
ensure
|
65
|
+
case_after c
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def case_before(c)
|
71
|
+
# implement each case before
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
def case_after(c)
|
76
|
+
# implement each case after
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: akapen
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- tbpgr
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-12-08 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: thor
|
16
|
+
requirement: &30132660 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.18.1
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *30132660
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: bundler
|
27
|
+
requirement: &30132168 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '1.3'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *30132168
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rake
|
38
|
+
requirement: &30131688 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *30131688
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rspec
|
49
|
+
requirement: &30131088 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.14.1
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *30131088
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: simplecov
|
60
|
+
requirement: &30130596 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ~>
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: 0.8.2
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *30130596
|
69
|
+
description: Akapen is grading & report generator
|
70
|
+
email:
|
71
|
+
- tbpgr@tbpgr.jp
|
72
|
+
executables:
|
73
|
+
- akapen
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- .gitignore
|
78
|
+
- .rspec
|
79
|
+
- Gemfile
|
80
|
+
- LICENSE.txt
|
81
|
+
- README.md
|
82
|
+
- Rakefile
|
83
|
+
- akapen.gemspec
|
84
|
+
- bin/akapen
|
85
|
+
- doc_image/akapen structure.png
|
86
|
+
- lib/akapen/version.rb
|
87
|
+
- lib/akapen_core.rb
|
88
|
+
- lib/akapen_dsl.rb
|
89
|
+
- spec/akapen_core_spec.rb
|
90
|
+
- spec/akapen_dsl_spec.rb
|
91
|
+
- spec/spec_helper.rb
|
92
|
+
homepage: https://github.com/tbpgr/akapen
|
93
|
+
licenses:
|
94
|
+
- MIT
|
95
|
+
post_install_message:
|
96
|
+
rdoc_options: []
|
97
|
+
require_paths:
|
98
|
+
- lib
|
99
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ! '>='
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ! '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
requirements: []
|
112
|
+
rubyforge_project:
|
113
|
+
rubygems_version: 1.8.11
|
114
|
+
signing_key:
|
115
|
+
specification_version: 3
|
116
|
+
summary: Akapen is grading & report generator
|
117
|
+
test_files:
|
118
|
+
- spec/akapen_core_spec.rb
|
119
|
+
- spec/akapen_dsl_spec.rb
|
120
|
+
- spec/spec_helper.rb
|
121
|
+
has_rdoc:
|