jungi 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.
- checksums.yaml +7 -0
- data/LICENSE +675 -0
- data/README.md +49 -0
- data/Rakefile +38 -0
- data/bin/jungi +181 -0
- data/lib/jungi/bigfive.rb +329 -0
- data/lib/jungi/classes.rb +193 -0
- data/lib/jungi/cli.rb +105 -0
- data/lib/jungi/oejts.rb +170 -0
- data/lib/jungi/paulhus.rb +130 -0
- metadata +53 -0
@@ -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
|
data/lib/jungi/cli.rb
ADDED
@@ -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
|
data/lib/jungi/oejts.rb
ADDED
@@ -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
|