jungi 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,193 @@
1
+ # JungI - A simple program for taking open source personality tests.
2
+ # Copyright (C) 2015 Mfrogy Starmade
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ # Global Question Module
18
+ module Question
19
+ # Question Type Enum
20
+ module Type
21
+ YESORNO = :yn
22
+ SCALE = :scale
23
+ end
24
+
25
+ # Question Answer Module
26
+ module Answer
27
+ YES = :yes
28
+ NO = :no
29
+
30
+ # Check value for yes or no value
31
+ def self.yes_or_no?(value)
32
+ if value == Question::Answer::YES || value == Question::Answer::NO
33
+ return true
34
+ else
35
+ return false
36
+ end
37
+ end
38
+
39
+ # Check value for scale value
40
+ def self.scale?(value)
41
+ if value == 1 || value == 2 || value == 3 || value == 4 || value == 5
42
+ return true
43
+ else
44
+ return false
45
+ end
46
+ end
47
+
48
+ # Reverse scale value
49
+ def self.reverse_scale(value)
50
+ unless Question::Answer.scale?(value)
51
+ fail "#{type} is not a proper scale!"
52
+ end
53
+ [5, 4, 3, 2, 1].to_a[value - 1]
54
+ end
55
+
56
+ # Checks value follows type
57
+ def self.follows_type?(type, value)
58
+ if type == Question::Type::YESORNO
59
+ return Question::Answer.yes_or_no?(value)
60
+ elsif type == Question::Type::SCALE
61
+ return Question::Answer.scale?(value)
62
+ else
63
+ fail "#{type} is an invalid question type!"
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ # Basic Test Class
70
+ class Test
71
+ # The test's questions plus the type of question they are
72
+ QUESTIONS = [
73
+ ['This is a standard question.', :yn],
74
+ ['This is another question.', :scale]
75
+ ]
76
+
77
+ def initialize
78
+ @answers = []
79
+ end
80
+
81
+ # Enable the use of self.Q<number> for easy implementation of tests
82
+ def method_missing(name, *args)
83
+ section = name[1..(name.length - 1)]
84
+ if name[0] == 'Q' && self.out_of_index?(section.to_i - 1)
85
+ return @answers[section.to_i - 1]
86
+ else
87
+ super
88
+ end
89
+ end
90
+
91
+ # Check for out of index
92
+ def out_of_index?(index, truism = false)
93
+ if (index) > (self.class.const_get(:QUESTIONS).length - 1)
94
+ if truism
95
+ false
96
+ else
97
+ fail "##{index} Out of Index"
98
+ end
99
+ end
100
+ true
101
+ end
102
+
103
+ # Get question via index
104
+ def get_question(index)
105
+ self.out_of_index? index
106
+ self.class.const_get(:QUESTIONS)[index].dup
107
+ end
108
+
109
+ # Alias get_question
110
+ def question(*args)
111
+ get_question(*args)
112
+ end
113
+
114
+ # Set question answer to value
115
+ def set_answer(index, value)
116
+ self.out_of_index? index
117
+ type = self.class.const_get(:QUESTIONS)[index][1]
118
+
119
+ unless Question::Answer.follows_type?(type, value)
120
+ fail "Type doesn't match with question type!"
121
+ end
122
+ @answers[index] = value
123
+ end
124
+
125
+ # Alias set_answer
126
+ def answer(*args)
127
+ set_answer(*args)
128
+ end
129
+
130
+ # Alias set_answer
131
+ def answer=(args)
132
+ set_answer(*args)
133
+ end
134
+
135
+ # Get a list of the answers so far
136
+ def answers
137
+ Marshal.load(Marshal.dump(@answers))
138
+ end
139
+
140
+ # Done supplying answers to questions?
141
+ def finished?
142
+ if @answers.length >= self.class.const_get(:QUESTIONS).length
143
+ return true
144
+ else
145
+ return false
146
+ end
147
+ end
148
+
149
+ # Alias finished?
150
+ def done?
151
+ self.finished?
152
+ end
153
+
154
+ # Stub method for result of test
155
+ def result
156
+ fail 'Not ready yet!' unless self.finished?
157
+ @answers.to_s
158
+ end
159
+ end
160
+
161
+ # Basic Scale5 Test Class
162
+ class ScaleTest < Test
163
+ # Default scale questions
164
+ QUESTIONS = ['very not dead|very dead', 'very not alive|very alive']
165
+
166
+ # Set question answer to value
167
+ def set_answer(index, value)
168
+ self.out_of_index? index
169
+ fail "#{value} is not a scale!" unless Question::Answer.scale?(value)
170
+ @answers[index] = value
171
+ end
172
+
173
+ # Randomize the answers to a scale test
174
+ def randomize!
175
+ self.class.const_get(:QUESTIONS).length.times do |num|
176
+ set_answer(num, rand(1..5))
177
+ end
178
+ nil
179
+ end
180
+
181
+ # Default results for scale test
182
+ def result
183
+ fail 'Not ready yet!' unless self.finished?
184
+ val = @answers[1] - @answers[0]
185
+ if val < 0
186
+ "Sad to hear you're dead."
187
+ elsif val > 0
188
+ "Good to hear you're alive!"
189
+ else
190
+ "You're hard to figure out."
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,105 @@
1
+ # JungI - A simple program for taking open source personality tests.
2
+ # Copyright (C) 2015 Mfrogy Starmade
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ begin
18
+ require_relative './classes'
19
+ rescue LoadError
20
+ require 'jungi/classes'
21
+ end
22
+
23
+ # JungiCli utility module
24
+ module JungiCli
25
+ # Fetch terminal width
26
+ def self.width
27
+ val = `tput cols`.chomp.to_i
28
+ val = 80 if val == 0
29
+ val
30
+ rescue Errno::ENOENT
31
+ 80
32
+ end
33
+
34
+ # Fetch prototype objects
35
+ def self.scale_proto
36
+ start = (' |1|2|3|4|5| '.center width)
37
+ start.partition(' |1|2|3|4|5| ')
38
+ end
39
+
40
+ # Handle question via scale
41
+ def self.parse_scale(scale)
42
+ p1, p2 = scale.split '|'
43
+ if p2
44
+ s1, c1, s2 = scale_proto
45
+ s1[s1.length - p1.length, s1.length - 1] = p1
46
+ s2[0, p2.length - 1] = p2
47
+ s1 + c1 + s2
48
+ else
49
+ (p1 + ' |1|2|3|4|5| ').center WIDTH
50
+ end
51
+ end
52
+
53
+ # Ask for integer
54
+ def self.ask_integer(prompt)
55
+ result = nil
56
+ until yield result
57
+ print prompt
58
+ result = gets.chomp.to_i
59
+ end
60
+ result
61
+ end
62
+
63
+ # Nicely ask a scale
64
+ def self.ask_scale(scale, randomize = false)
65
+ puts parse_scale scale
66
+
67
+ if randomize
68
+ int = rand(1..5)
69
+ puts "> #{int}"
70
+ int
71
+
72
+ else
73
+ ask_integer '> ' do |r|
74
+ Question::Answer.scale? r
75
+ end
76
+ end
77
+ end
78
+
79
+ # Pad a document to width
80
+ def self.center_doc(doc)
81
+ doc = doc.split "\n"
82
+ out = []
83
+ doc.length.times do |int|
84
+ out[int] = doc[int].center width
85
+ end
86
+ out
87
+ end
88
+
89
+ # Display document centered
90
+ def self.display_doc(doc)
91
+ center_doc(doc).each do |line|
92
+ puts line
93
+ end
94
+ end
95
+
96
+ # Render line
97
+ def self.line
98
+ puts '-' * width
99
+ end
100
+
101
+ # Clear screen
102
+ def self.clr
103
+ system('clear') || system('cls')
104
+ end
105
+ end
@@ -0,0 +1,170 @@
1
+ # JungI - A simple program for taking open source personality tests.
2
+ # Copyright (C) 2015 Mfrogy Starmade
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ # The items of the Open Extended Jungian Type Scales 1.2 are licenced
18
+ # under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0
19
+ # International License by Eric Jorgenson. The OEJTS comes with no
20
+ # guarantees of reliability or accuracy of any kind.
21
+ #
22
+ # https://creativecommons.org/licenses/by-nc-sa/4.0/
23
+
24
+ begin
25
+ require_relative './classes'
26
+ rescue LoadError
27
+ require 'jungi/classes'
28
+ end
29
+
30
+ # Implementation of OEJTS
31
+ class OEJTSTest < ScaleTest
32
+ DOC = <<END_FILE
33
+ Open Extended Jungian Type Scales 1.2
34
+
35
+ In this test there are 32 pairs of personality descriptions
36
+ connected by a five point scale. For each pair, you must
37
+ choose where on the scale between them you think you are.
38
+ For example, if the pair is "angry” versus “calm”,
39
+ you should type in a 1 if you are always angry and never
40
+ calm, a 3 if you are half and half, etc. Press <ENTER>
41
+ after typing your answer. Answer honestly and as you are,
42
+ not as you hope to be.
43
+ END_FILE
44
+ QUESTIONS = [
45
+ 'makes lists|relies on memory',
46
+ 'sceptical|wants to believe',
47
+ 'bored by time alone|needs time alone',
48
+ 'accepts things as they are|unsatisfied with the way things are',
49
+ 'keeps a clean room|just puts stuff where ever',
50
+ "thinks \"robotic\" is an insult|strives to have a mechanical mind",
51
+ 'energetic|mellow',
52
+ 'prefer to take multiple choice test|prefer essay answers',
53
+ 'chaotic|organized',
54
+ 'easily hurt|thick-skinned',
55
+ 'works best in groups|works best alone',
56
+ 'focused on the past|focused on the future',
57
+ 'plans far ahead|plans at the last minute',
58
+ "wants people's respect|wants their love",
59
+ 'gets worn out by parties|gets fired up by parties',
60
+ 'fits in|stands out',
61
+ 'keeps options open|commits',
62
+ 'wants to be good at fixing things|wants to be good at fixing people',
63
+ 'talks more|listens more',
64
+ 'when describing an event, will tell people what happened|when descr'\
65
+ 'ibing an event, will tell people what it meant',
66
+ 'gets work done right away|procrastinates',
67
+ 'follows the heart|follows the head',
68
+ 'stays at home|goest out on the town',
69
+ 'wants the big picture|wants the details',
70
+ 'improvises|prepares',
71
+ 'bases morality on justice|bases morality on compassion',
72
+ 'finds it difficult to yell very loudly|yelling to others when they are'\
73
+ ' far away comes naturally',
74
+ 'theoretical|empirical',
75
+ 'works hard|plays hard',
76
+ 'uncomfortable with emotions|values emotions',
77
+ 'likes to perform in front of other people|avoids public speaking',
78
+ "likes to know \"who?\", \"what?\", \"when?\"|likes to know \"why?\""
79
+ ]
80
+
81
+ def result
82
+ fail 'Not ready yet!' unless self.finished?
83
+ ie = 30 - self.Q3 - self.Q7 - self.Q11 + self.Q15 -
84
+ self.Q19 + self.Q23 + self.Q27 - self.Q31
85
+ sn = 12 + self.Q4 + self.Q8 + self.Q12 + self.Q16 +
86
+ self.Q20 - self.Q24 - self.Q28 + self.Q32
87
+ ft = 30 - self.Q2 + self.Q6 + self.Q10 - self.Q14 -
88
+ self.Q18 + self.Q22 - self.Q26 - self.Q30
89
+ jp = 18 + self.Q1 + self.Q5 - self.Q9 + self.Q13 -
90
+ self.Q17 + self.Q21 - self.Q25 + self.Q29
91
+ desig = ''
92
+
93
+ if ie > 24
94
+ desig << 'E'
95
+ else
96
+ desig << 'I'
97
+ end
98
+ if sn > 24
99
+ desig << 'N'
100
+ else
101
+ desig << 'S'
102
+ end
103
+ if ft > 24
104
+ desig << 'T'
105
+ else
106
+ desig << 'F'
107
+ end
108
+ if jp > 24
109
+ desig << 'P'
110
+ else
111
+ desig << 'J'
112
+ end
113
+
114
+ iev = (ie - 24).abs
115
+ snv = (sn - 24).abs
116
+ ftv = (ft - 24).abs
117
+ jpv = (jp - 24).abs
118
+
119
+ [desig, iev, snv, ftv, jpv]
120
+ end
121
+
122
+ def self.parse_iev(desig, iev)
123
+ word = desig[0] == 'E' ? 'Extraversion' : 'Intraversion'
124
+ if iev.between?(0, 1)
125
+ "Lukewarm #{word}, "
126
+ elsif iev < 4
127
+ "Weak(#{iev}) #{word}, "
128
+ else
129
+ "Strong(#{iev}) #{word}, "
130
+ end
131
+ end
132
+
133
+ def self.parse_snv(desig, snv)
134
+ word = desig[1] == 'S' ? 'Sensing' : 'Intuition'
135
+ if snv.between?(0, 1)
136
+ "Lukewarm #{word}\n"
137
+ elsif snv < 4
138
+ "Weak(#{snv}) #{word}\n"
139
+ else
140
+ "Strong(#{snv}) #{word}\n"
141
+ end
142
+ end
143
+
144
+ def self.parse_ftv(desig, ftv)
145
+ word = desig[2] == 'F' ? 'Feeling' : 'Thinking'
146
+ if ftv.between?(0, 1)
147
+ "Lukewarm #{word}, "
148
+ elsif ftv < 4
149
+ "Weak(#{ftv}) #{word} "
150
+ else
151
+ "Strong(#{ftv}) #{word}, "
152
+ end
153
+ end
154
+
155
+ def self.parse_jpv(desig, jpv)
156
+ word = desig[3] == 'J' ? 'Judging' : 'Perceiving'
157
+ if jpv.between?(0, 1)
158
+ "Lukewarm #{word}"
159
+ elsif jpv < 4
160
+ "Weak(#{jpv}) #{word}"
161
+ else
162
+ "Strong(#{jpv}) #{word}"
163
+ end
164
+ end
165
+
166
+ def self.parse_result(desig, iev, snv, ftv, jpv)
167
+ parse_iev(desig, iev) << parse_snv(desig, snv) <<
168
+ parse_ftv(desig, ftv) << parse_jpv(desig, jpv)
169
+ end
170
+ end