caruby-scat 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +25 -0
- data/Gemfile.lock +158 -0
- data/History.md +9 -0
- data/LEGAL +4 -0
- data/LICENSE +22 -0
- data/README.md +131 -0
- data/Rakefile +41 -0
- data/bin/scat +7 -0
- data/bin/scatseed +10 -0
- data/caruby-scat.gemspec +30 -0
- data/conf/fields.yaml +22 -0
- data/conf/redis.conf +492 -0
- data/config.ru +15 -0
- data/features/edit.feature +29 -0
- data/features/step_definitions/scat_steps.rb +50 -0
- data/features/support/env.rb +18 -0
- data/features/support/seed.rb +2 -0
- data/lib/scat.rb +56 -0
- data/lib/scat/autocomplete.rb +74 -0
- data/lib/scat/cache.rb +90 -0
- data/lib/scat/configuration.rb +79 -0
- data/lib/scat/edit.rb +160 -0
- data/lib/scat/field.rb +99 -0
- data/lib/scat/version.rb +3 -0
- data/public/images/apple-touch-icon-114x114.png +0 -0
- data/public/images/apple-touch-icon-72x72.png +0 -0
- data/public/images/apple-touch-icon.png +0 -0
- data/public/images/favicon.ico +0 -0
- data/public/images/help.png +0 -0
- data/public/javascripts/tabs.js +29 -0
- data/public/robots.txt +5 -0
- data/public/stylesheets/base.css +342 -0
- data/public/stylesheets/layout.css +58 -0
- data/public/stylesheets/scat.css +64 -0
- data/public/stylesheets/skeleton.css +242 -0
- data/redis.rdb +0 -0
- data/spec/autocomplete_spec.rb +17 -0
- data/spec/edit_spec.rb +60 -0
- data/spec/spec_helper.rb +13 -0
- data/test/fixtures/seed.rb +25 -0
- data/views/edit.haml +12 -0
- data/views/layout.haml +40 -0
- metadata +216 -0
@@ -0,0 +1,58 @@
|
|
1
|
+
/*
|
2
|
+
* Skeleton V1.1
|
3
|
+
* Copyright 2011, Dave Gamache
|
4
|
+
* www.getskeleton.com
|
5
|
+
* Free to use under the MIT license.
|
6
|
+
* http://www.opensource.org/licenses/mit-license.php
|
7
|
+
* 8/17/2011
|
8
|
+
*/
|
9
|
+
|
10
|
+
/* Table of Content
|
11
|
+
==================================================
|
12
|
+
#Site Styles
|
13
|
+
#Page Styles
|
14
|
+
#Media Queries
|
15
|
+
#Font-Face */
|
16
|
+
|
17
|
+
/* #Site Styles
|
18
|
+
================================================== */
|
19
|
+
|
20
|
+
/* #Page Styles
|
21
|
+
================================================== */
|
22
|
+
|
23
|
+
/* #Media Queries
|
24
|
+
================================================== */
|
25
|
+
|
26
|
+
/* Smaller than standard 960 (devices and browsers) */
|
27
|
+
@media only screen and (max-width: 959px) {}
|
28
|
+
|
29
|
+
/* Tablet Portrait size to standard 960 (devices and browsers) */
|
30
|
+
@media only screen and (min-width: 768px) and (max-width: 959px) {}
|
31
|
+
|
32
|
+
/* All Mobile Sizes (devices and browser) */
|
33
|
+
@media only screen and (max-width: 767px) {}
|
34
|
+
|
35
|
+
/* Mobile Landscape Size to Tablet Portrait (devices and browsers) */
|
36
|
+
@media only screen and (min-width: 480px) and (max-width: 767px) {}
|
37
|
+
|
38
|
+
/* Mobile Portrait Size to Mobile Landscape Size (devices and browsers) */
|
39
|
+
@media only screen and (max-width: 479px) {}
|
40
|
+
|
41
|
+
|
42
|
+
/* #Font-Face
|
43
|
+
================================================== */
|
44
|
+
/* This is the proper syntax for an @font-face file
|
45
|
+
Just create a "fonts" folder at the root,
|
46
|
+
copy your FontName into code below and remove
|
47
|
+
comment brackets */
|
48
|
+
|
49
|
+
/* @font-face {
|
50
|
+
font-family: 'FontName';
|
51
|
+
src: url('../fonts/FontName.eot');
|
52
|
+
src: url('../fonts/FontName.eot?iefix') format('eot'),
|
53
|
+
url('../fonts/FontName.woff') format('woff'),
|
54
|
+
url('../fonts/FontName.ttf') format('truetype'),
|
55
|
+
url('../fonts/FontName.svg#webfontZam02nTh') format('svg');
|
56
|
+
font-weight: normal;
|
57
|
+
font-style: normal; }
|
58
|
+
*/
|
@@ -0,0 +1,64 @@
|
|
1
|
+
body {
|
2
|
+
background: #FAFFF6
|
3
|
+
}
|
4
|
+
|
5
|
+
h1.application {
|
6
|
+
font-family: "Handwriting - Dakota", Pristina, "Rage Italic", "Comic Sans MS", Georgia, serif;
|
7
|
+
font-weight: bold;
|
8
|
+
color: DarkBlue;
|
9
|
+
}
|
10
|
+
|
11
|
+
a.help {
|
12
|
+
display: block;
|
13
|
+
float: left;
|
14
|
+
left: -20px;
|
15
|
+
top: 4px;
|
16
|
+
text-decoration: none;
|
17
|
+
position: relative;
|
18
|
+
}
|
19
|
+
|
20
|
+
a.help img {
|
21
|
+
width: 15px;
|
22
|
+
height: 15px;
|
23
|
+
}
|
24
|
+
|
25
|
+
a.help span {
|
26
|
+
display: none;
|
27
|
+
}
|
28
|
+
|
29
|
+
a.help:hover span {
|
30
|
+
display: block;
|
31
|
+
position: absolute;
|
32
|
+
width: 180px;
|
33
|
+
padding: 5px 5px;
|
34
|
+
margin: 0 0 1px;
|
35
|
+
border: 1px solid black;
|
36
|
+
z-index: 100;
|
37
|
+
background-color: #eeeeee;
|
38
|
+
font: 10px sans-serif;
|
39
|
+
}
|
40
|
+
|
41
|
+
label {
|
42
|
+
left: -15px;
|
43
|
+
position: relative;
|
44
|
+
}
|
45
|
+
|
46
|
+
.ui-menu .ui-menu-item a {
|
47
|
+
font-size: smaller;
|
48
|
+
line-height: 1;
|
49
|
+
}
|
50
|
+
|
51
|
+
input[type='checkbox'] {
|
52
|
+
position: relative;
|
53
|
+
left: -1em;
|
54
|
+
margin-bottom: 20px;
|
55
|
+
}
|
56
|
+
|
57
|
+
#malignant label {
|
58
|
+
float: left;
|
59
|
+
}
|
60
|
+
|
61
|
+
#quantity input {
|
62
|
+
max-width: 8em;
|
63
|
+
}
|
64
|
+
|
@@ -0,0 +1,242 @@
|
|
1
|
+
/*
|
2
|
+
* Skeleton V1.1
|
3
|
+
* Copyright 2011, Dave Gamache
|
4
|
+
* www.getskeleton.com
|
5
|
+
* Free to use under the MIT license.
|
6
|
+
* http://www.opensource.org/licenses/mit-license.php
|
7
|
+
* 8/17/2011
|
8
|
+
*/
|
9
|
+
|
10
|
+
|
11
|
+
/* Table of Contents
|
12
|
+
==================================================
|
13
|
+
#Base 960 Grid
|
14
|
+
#Tablet (Portrait)
|
15
|
+
#Mobile (Portrait)
|
16
|
+
#Mobile (Landscape)
|
17
|
+
#Clearing */
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
/* #Base 960 Grid
|
22
|
+
================================================== */
|
23
|
+
|
24
|
+
.container { position: relative; width: 960px; margin: 0 auto; padding: 0; }
|
25
|
+
.container .column,
|
26
|
+
.container .columns { float: left; display: inline; margin-left: 10px; margin-right: 10px; }
|
27
|
+
.row { margin-bottom: 20px; }
|
28
|
+
|
29
|
+
/* Nested Column Classes */
|
30
|
+
.column.alpha, .columns.alpha { margin-left: 0; }
|
31
|
+
.column.omega, .columns.omega { margin-right: 0; }
|
32
|
+
|
33
|
+
/* Base Grid */
|
34
|
+
.container .one.column,
|
35
|
+
.container .one.columns { width: 40px; }
|
36
|
+
.container .two.columns { width: 100px; }
|
37
|
+
.container .three.columns { width: 160px; }
|
38
|
+
.container .four.columns { width: 220px; }
|
39
|
+
.container .five.columns { width: 280px; }
|
40
|
+
.container .six.columns { width: 340px; }
|
41
|
+
.container .seven.columns { width: 400px; }
|
42
|
+
.container .eight.columns { width: 460px; }
|
43
|
+
.container .nine.columns { width: 520px; }
|
44
|
+
.container .ten.columns { width: 580px; }
|
45
|
+
.container .eleven.columns { width: 640px; }
|
46
|
+
.container .twelve.columns { width: 700px; }
|
47
|
+
.container .thirteen.columns { width: 760px; }
|
48
|
+
.container .fourteen.columns { width: 820px; }
|
49
|
+
.container .fifteen.columns { width: 880px; }
|
50
|
+
.container .sixteen.columns { width: 940px; }
|
51
|
+
|
52
|
+
.container .one-third.column { width: 300px; }
|
53
|
+
.container .two-thirds.column { width: 620px; }
|
54
|
+
|
55
|
+
/* Offsets */
|
56
|
+
.container .offset-by-one { padding-left: 60px; }
|
57
|
+
.container .offset-by-two { padding-left: 120px; }
|
58
|
+
.container .offset-by-three { padding-left: 180px; }
|
59
|
+
.container .offset-by-four { padding-left: 240px; }
|
60
|
+
.container .offset-by-five { padding-left: 300px; }
|
61
|
+
.container .offset-by-six { padding-left: 360px; }
|
62
|
+
.container .offset-by-seven { padding-left: 420px; }
|
63
|
+
.container .offset-by-eight { padding-left: 480px; }
|
64
|
+
.container .offset-by-nine { padding-left: 540px; }
|
65
|
+
.container .offset-by-ten { padding-left: 600px; }
|
66
|
+
.container .offset-by-eleven { padding-left: 660px; }
|
67
|
+
.container .offset-by-twelve { padding-left: 720px; }
|
68
|
+
.container .offset-by-thirteen { padding-left: 780px; }
|
69
|
+
.container .offset-by-fourteen { padding-left: 840px; }
|
70
|
+
.container .offset-by-fifteen { padding-left: 900px; }
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
/* #Tablet (Portrait)
|
75
|
+
================================================== */
|
76
|
+
|
77
|
+
/* Note: Design for a width of 768px */
|
78
|
+
|
79
|
+
@media only screen and (min-width: 768px) and (max-width: 959px) {
|
80
|
+
.container { width: 768px; }
|
81
|
+
.container .column,
|
82
|
+
.container .columns { margin-left: 10px; margin-right: 10px; }
|
83
|
+
.column.alpha, .columns.alpha { margin-left: 0; margin-right: 10px; }
|
84
|
+
.column.omega, .columns.omega { margin-right: 0; margin-left: 10px; }
|
85
|
+
.alpha.omega { margin-left: 0; margin-right: 0; }
|
86
|
+
|
87
|
+
.container .one.column,
|
88
|
+
.container .one.columns { width: 28px; }
|
89
|
+
.container .two.columns { width: 76px; }
|
90
|
+
.container .three.columns { width: 124px; }
|
91
|
+
.container .four.columns { width: 172px; }
|
92
|
+
.container .five.columns { width: 220px; }
|
93
|
+
.container .six.columns { width: 268px; }
|
94
|
+
.container .seven.columns { width: 316px; }
|
95
|
+
.container .eight.columns { width: 364px; }
|
96
|
+
.container .nine.columns { width: 412px; }
|
97
|
+
.container .ten.columns { width: 460px; }
|
98
|
+
.container .eleven.columns { width: 508px; }
|
99
|
+
.container .twelve.columns { width: 556px; }
|
100
|
+
.container .thirteen.columns { width: 604px; }
|
101
|
+
.container .fourteen.columns { width: 652px; }
|
102
|
+
.container .fifteen.columns { width: 700px; }
|
103
|
+
.container .sixteen.columns { width: 748px; }
|
104
|
+
|
105
|
+
.container .one-third.column { width: 236px; }
|
106
|
+
.container .two-thirds.column { width: 492px; }
|
107
|
+
|
108
|
+
/* Offsets */
|
109
|
+
.container .offset-by-one { padding-left: 48px; }
|
110
|
+
.container .offset-by-two { padding-left: 96px; }
|
111
|
+
.container .offset-by-three { padding-left: 144px; }
|
112
|
+
.container .offset-by-four { padding-left: 192px; }
|
113
|
+
.container .offset-by-five { padding-left: 240px; }
|
114
|
+
.container .offset-by-six { padding-left: 288px; }
|
115
|
+
.container .offset-by-seven { padding-left: 336px; }
|
116
|
+
.container .offset-by-eight { padding-left: 384px; }
|
117
|
+
.container .offset-by-nine { padding-left: 432px; }
|
118
|
+
.container .offset-by-ten { padding-left: 480px; }
|
119
|
+
.container .offset-by-eleven { padding-left: 528px; }
|
120
|
+
.container .offset-by-twelve { padding-left: 576px; }
|
121
|
+
.container .offset-by-thirteen { padding-left: 624px; }
|
122
|
+
.container .offset-by-fourteen { padding-left: 672px; }
|
123
|
+
.container .offset-by-fifteen { padding-left: 720px; }
|
124
|
+
}
|
125
|
+
|
126
|
+
|
127
|
+
/* #Mobile (Portrait)
|
128
|
+
================================================== */
|
129
|
+
|
130
|
+
/* Note: Design for a width of 320px */
|
131
|
+
|
132
|
+
@media only screen and (max-width: 767px) {
|
133
|
+
.container { width: 300px; }
|
134
|
+
.container .columns,
|
135
|
+
.container .column { margin: 0; }
|
136
|
+
|
137
|
+
.container .one.column,
|
138
|
+
.container .one.columns,
|
139
|
+
.container .two.columns,
|
140
|
+
.container .three.columns,
|
141
|
+
.container .four.columns,
|
142
|
+
.container .five.columns,
|
143
|
+
.container .six.columns,
|
144
|
+
.container .seven.columns,
|
145
|
+
.container .eight.columns,
|
146
|
+
.container .nine.columns,
|
147
|
+
.container .ten.columns,
|
148
|
+
.container .eleven.columns,
|
149
|
+
.container .twelve.columns,
|
150
|
+
.container .thirteen.columns,
|
151
|
+
.container .fourteen.columns,
|
152
|
+
.container .fifteen.columns,
|
153
|
+
.container .sixteen.columns,
|
154
|
+
.container .one-third.column,
|
155
|
+
.container .two-thirds.column { width: 300px; }
|
156
|
+
|
157
|
+
/* Offsets */
|
158
|
+
.container .offset-by-one,
|
159
|
+
.container .offset-by-two,
|
160
|
+
.container .offset-by-three,
|
161
|
+
.container .offset-by-four,
|
162
|
+
.container .offset-by-five,
|
163
|
+
.container .offset-by-six,
|
164
|
+
.container .offset-by-seven,
|
165
|
+
.container .offset-by-eight,
|
166
|
+
.container .offset-by-nine,
|
167
|
+
.container .offset-by-ten,
|
168
|
+
.container .offset-by-eleven,
|
169
|
+
.container .offset-by-twelve,
|
170
|
+
.container .offset-by-thirteen,
|
171
|
+
.container .offset-by-fourteen,
|
172
|
+
.container .offset-by-fifteen { padding-left: 0; }
|
173
|
+
|
174
|
+
}
|
175
|
+
|
176
|
+
|
177
|
+
/* #Mobile (Landscape)
|
178
|
+
================================================== */
|
179
|
+
|
180
|
+
/* Note: Design for a width of 480px */
|
181
|
+
|
182
|
+
@media only screen and (min-width: 480px) and (max-width: 767px) {
|
183
|
+
.container { width: 420px; }
|
184
|
+
.container .columns,
|
185
|
+
.container .column { margin: 0; }
|
186
|
+
|
187
|
+
.container .one.column,
|
188
|
+
.container .one.columns,
|
189
|
+
.container .two.columns,
|
190
|
+
.container .three.columns,
|
191
|
+
.container .four.columns,
|
192
|
+
.container .five.columns,
|
193
|
+
.container .six.columns,
|
194
|
+
.container .seven.columns,
|
195
|
+
.container .eight.columns,
|
196
|
+
.container .nine.columns,
|
197
|
+
.container .ten.columns,
|
198
|
+
.container .eleven.columns,
|
199
|
+
.container .twelve.columns,
|
200
|
+
.container .thirteen.columns,
|
201
|
+
.container .fourteen.columns,
|
202
|
+
.container .fifteen.columns,
|
203
|
+
.container .sixteen.columns,
|
204
|
+
.container .one-third.column,
|
205
|
+
.container .two-thirds.column { width: 420px; }
|
206
|
+
}
|
207
|
+
|
208
|
+
|
209
|
+
/* #Clearing
|
210
|
+
================================================== */
|
211
|
+
|
212
|
+
/* Self Clearing Goodness */
|
213
|
+
.container:after { content: "\0020"; display: block; height: 0; clear: both; visibility: hidden; }
|
214
|
+
|
215
|
+
/* Use clearfix class on parent to clear nested columns,
|
216
|
+
or wrap each row of columns in a <div class="row"> */
|
217
|
+
.clearfix:before,
|
218
|
+
.clearfix:after,
|
219
|
+
.row:before,
|
220
|
+
.row:after {
|
221
|
+
content: '\0020';
|
222
|
+
display: block;
|
223
|
+
overflow: hidden;
|
224
|
+
visibility: hidden;
|
225
|
+
width: 0;
|
226
|
+
height: 0; }
|
227
|
+
.row:after,
|
228
|
+
.clearfix:after {
|
229
|
+
clear: both; }
|
230
|
+
.row,
|
231
|
+
.clearfix {
|
232
|
+
zoom: 1; }
|
233
|
+
|
234
|
+
/* You can also use a <br class="clear" /> to clear columns */
|
235
|
+
.clear {
|
236
|
+
clear: both;
|
237
|
+
display: block;
|
238
|
+
overflow: hidden;
|
239
|
+
visibility: hidden;
|
240
|
+
width: 0;
|
241
|
+
height: 0;
|
242
|
+
}
|
data/redis.rdb
ADDED
Binary file
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe Scat do
|
4
|
+
describe 'Auto-complete' do
|
5
|
+
include Scat::Autocomplete
|
6
|
+
|
7
|
+
AC_TARGET ||= 'Malignant lymphoma'
|
8
|
+
|
9
|
+
it "should find matching diagnoses" do
|
10
|
+
matches = autocomplete(:clinical_diagnosis, AC_TARGET)
|
11
|
+
matches.should_not be_empty
|
12
|
+
matches.each do |cv|
|
13
|
+
cv.downcase.should match AC_TARGET.downcase
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/spec/edit_spec.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
require 'jinx/helpers/string_uniquifier'
|
3
|
+
require 'scat/edit'
|
4
|
+
require File.dirname(__FILE__) + '/../test/fixtures/seed'
|
5
|
+
|
6
|
+
describe Scat do
|
7
|
+
describe 'Edit' do
|
8
|
+
before(:all) do
|
9
|
+
title = Jinx::StringUniquifier.uniquify('Scat')
|
10
|
+
pcl = Scat::Seed.protocol_for(title).find(:create)
|
11
|
+
@params = {
|
12
|
+
:user => pcl.coordinators.first,
|
13
|
+
:protocol => title,
|
14
|
+
:mrn => Jinx::StringUniquifier.uniquify('Test'),
|
15
|
+
:spn => Jinx::StringUniquifier.uniquify('Test'),
|
16
|
+
:diagnosis => '[M]Adrenal cortical adenoma NOS',
|
17
|
+
:tissue_site => 'Adrenal gland, NOS',
|
18
|
+
:malignant => 'Malignant',
|
19
|
+
:quantity => '4'
|
20
|
+
}
|
21
|
+
@spc = Scat::Edit.instance.save(@params)
|
22
|
+
end
|
23
|
+
|
24
|
+
subject { @spc }
|
25
|
+
|
26
|
+
it "should save the specimen" do
|
27
|
+
subject.identifier.should_not be nil
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should set the properties" do
|
31
|
+
subject.pathological_status.should == 'Malignant'
|
32
|
+
scg = subject.specimen_collection_group
|
33
|
+
scg.clinical_diagnosis.should == '[M]Adrenal cortical adenoma NOS'
|
34
|
+
subject.characteristics.tissue_site.should == 'Adrenal gland, NOS'
|
35
|
+
subject.initial_quantity.should == 4.0
|
36
|
+
end
|
37
|
+
|
38
|
+
context "add a normal specimen to an existing SCG" do
|
39
|
+
before(:all) do
|
40
|
+
oparams = @params.delete_if { |k, v| k == :malignant }
|
41
|
+
oparams[:quantity] = '5'
|
42
|
+
@other = Scat::Edit.instance.save(oparams)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should save the additional specimen" do
|
46
|
+
@other.identifier.should_not be nil
|
47
|
+
@other.identifier.should_not == subject.identifier
|
48
|
+
@other.initial_quantity.should == 5.0
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should be non-malignant" do
|
52
|
+
@other.pathological_status.should == 'Non-Malignant'
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should use the same SCG" do
|
56
|
+
@other.specimen_collection_group.identifier.should be subject.specimen_collection_group.identifier
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
Bundler.require(:test, :development)
|
4
|
+
require 'scat'
|
5
|
+
|
6
|
+
module Scat::Test
|
7
|
+
RESULTS = File.dirname(__FILE__) + '/../test/results'
|
8
|
+
end
|
9
|
+
|
10
|
+
# Open the logger.
|
11
|
+
logger(Scat::Test::RESULTS + '/log/scat.log', :debug => true)
|
12
|
+
|
13
|
+
Dir[File.dirname(__FILE__) + '/support/**/*.rb'].each { |f| require f }
|