Class: Exercise
- Inherits:
-
ApplicationRecord
show all
- Includes:
- Assistable, FriendlyName, ParentNavigation, Questionable, SiblingsNavigation, Submittable, WithAssignments, WithDescription, WithDiscussions, WithLanguage, WithLocale, WithName, WithNumber, WithRandomizations
- Defined in:
- app/models/exercise.rb
Constant Summary
collapse
- RANDOMIZED_FIELDS =
[:default_content, :description, :extra, :hint, :test, :expectations, :custom_expectations]
- BASIC_RESOURCE_FIELDS =
i(
name layout editor corollary teacher_info manual_evaluation locale
choices assistance_rules randomizations tag_list goal
free_form_editor_source initial_state final_state)
Class Method Summary
collapse
Instance Method Summary
collapse
#navigable_name, #next_for, #restart, #siblings
#leave, #navigable_name, #navigable_parent, #navigation_end?
#find_assignment_and_submit!, #submit!
#submit_question!
#assignment_for, #find_assignment_for, #has_messages_for?, #has_progress_for?, #messages_for, #status_for
#friendly_name, #to_param
Methods included from Assistable
#assist_with, #assistant
#randomizer, #seed, #seed_with!
#discuss!, #new_discussion_for, #try_solve_discussions!
active_between, aggregate_of, all_except, defaults, #delete, #destroy!, enum_prefixed_translations_for, numbered, organic_on, resource_fields, #save, #save_and_notify!, #save_and_notify_changes!, serialize_symbolized_hash_array, teaser_on, #update_and_notify!, update_or_create!, whitelist_attributes, with_pg_retry, with_temporary_token
Methods included from WithPgLock
#with_pg_lock
Class Method Details
.default_scope ⇒ Object
31
32
33
|
# File 'app/models/exercise.rb', line 31
def self.default_scope
where(manual_evaluation: false) if hide_manual_evaluation?
end
|
.find_transparently!(params) ⇒ Object
220
221
222
|
# File 'app/models/exercise.rb', line 220
def self.find_transparently!(params)
Guide.find_transparently!(params).locate_exercise! params[:bibliotheca_id]
end
|
.locate!(slug_and_bibliotheca_id) ⇒ Object
224
225
226
227
|
# File 'app/models/exercise.rb', line 224
def self.locate!(slug_and_bibliotheca_id)
slug, bibliotheca_id = slug_and_bibliotheca_id
Guide.locate!(slug).locate_exercise! bibliotheca_id
end
|
Instance Method Details
#choice? ⇒ Boolean
71
72
73
|
# File 'app/models/exercise.rb', line 71
def choice?
false
end
|
#choice_index_for(value) ⇒ Object
129
130
131
|
# File 'app/models/exercise.rb', line 129
def choice_index_for(value)
choice_values.index(value)
end
|
#choice_values ⇒ Object
125
126
127
|
# File 'app/models/exercise.rb', line 125
def choice_values
choices.map { |it| it.indifferent_get(:value) }
end
|
#console? ⇒ Boolean
47
48
49
|
# File 'app/models/exercise.rb', line 47
def console?
queriable?
end
|
#content_used_in?(organization) ⇒ Boolean
59
60
61
|
# File 'app/models/exercise.rb', line 59
def content_used_in?(organization)
navigable_content_in(organization).present?
end
|
#custom? ⇒ Boolean
183
184
185
|
# File 'app/models/exercise.rb', line 183
def custom?
false
end
|
#description_context ⇒ Object
171
172
173
|
# File 'app/models/exercise.rb', line 171
def description_context
splitted_description.first.markdownified
end
|
#description_task ⇒ Object
179
180
181
|
# File 'app/models/exercise.rb', line 179
def description_task
splitted_description.drop(1).join("\n").markdownified
end
|
#ensure_type!(type) ⇒ Object
158
159
160
161
162
163
164
|
# File 'app/models/exercise.rb', line 158
def ensure_type!(type)
if self.type != type
reclassify! type
else
self
end
end
|
#files_for(current_content) ⇒ Object
213
214
215
216
217
218
|
# File 'app/models/exercise.rb', line 213
def files_for(current_content)
language
.directives_sections
.split_sections(current_content)
.map { |name, content| Mumuki::Domain::File.new name, content }
end
|
#friendly ⇒ Object
96
97
98
|
# File 'app/models/exercise.rb', line 96
def friendly
defaulting_name { "#{navigable_parent.friendly} - #{name}" }
end
|
#guide_done_for?(user) ⇒ Boolean
67
68
69
|
# File 'app/models/exercise.rb', line 67
def guide_done_for?(user)
guide.done_for?(user)
end
|
#import_from_resource_h!(number, resource_h) ⇒ Object
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
# File 'app/models/exercise.rb', line 108
def import_from_resource_h!(number, resource_h)
self.language = Language.for_name(resource_h.dig(:language, :name)) || guide.language
self.locale = guide.locale
reset!
attrs = whitelist_attributes(resource_h, except: [:type, :id])
attrs[:choices] = resource_h[:choices].to_a
attrs[:bibliotheca_id] = resource_h[:id]
attrs[:number] = number
attrs[:manual_evaluation] ||= false
attrs = attrs.except(:expectations, :custom_expectations) if type != 'Problem'
assign_attributes(attrs)
save!
end
|
#inspection_keywords ⇒ Object
187
188
189
|
# File 'app/models/exercise.rb', line 187
def inspection_keywords
{}
end
|
#limited? ⇒ Boolean
An exercise with hidden results cannot be limited as those exercises can be submitted as many times as the student wants because no result output is given
205
206
207
|
# File 'app/models/exercise.rb', line 205
def limited?
!results_hidden? && navigable_parent.limited_for?(self)
end
|
#navigable_content_in(organization = Organization.current) ⇒ Object
55
56
57
|
# File 'app/models/exercise.rb', line 55
def navigable_content_in(organization = Organization.current)
self if used_in?(organization)
end
|
#new_solution ⇒ Object
104
105
106
|
# File 'app/models/exercise.rb', line 104
def new_solution
Mumuki::Domain::Submission::Solution.new(content: default_content)
end
|
#pending_siblings_for(user) ⇒ Object
233
234
235
|
# File 'app/models/exercise.rb', line 233
def pending_siblings_for(user)
guide.pending_exercises(user)
end
|
#previous ⇒ Object
75
76
77
|
# File 'app/models/exercise.rb', line 75
def previous
sibling_at number.pred
end
|
#reclassify!(type) ⇒ Object
166
167
168
169
|
# File 'app/models/exercise.rb', line 166
def reclassify!(type)
update!(type: type)
Exercise.find(id)
end
|
#reset! ⇒ Object
149
150
151
152
153
154
155
156
|
# File 'app/models/exercise.rb', line 149
def reset!
self.name = nil
self.description = nil
self.corollary = nil
self.hint = nil
self. = nil
self.tag_list = []
end
|
#results_hidden? ⇒ Boolean
209
210
211
|
# File 'app/models/exercise.rb', line 209
def results_hidden?
navigable_parent&.results_hidden_for?(self)
end
|
84
85
86
|
# File 'app/models/exercise.rb', line 84
def search_tags
[language&.name, *tag_list].compact
end
|
#settings ⇒ Object
229
230
231
|
# File 'app/models/exercise.rb', line 229
def settings
guide.settings.deep_merge super
end
|
#sibling_at(index) ⇒ Object
79
80
81
82
|
# File 'app/models/exercise.rb', line 79
def sibling_at(index)
index = number + index unless index.positive?
guide.exercises.find_by(number: index)
end
|
#solvable? ⇒ Boolean
237
238
239
|
# File 'app/models/exercise.rb', line 237
def solvable?
is_a? ::Problem
end
|
#splitted_description ⇒ Object
175
176
177
|
# File 'app/models/exercise.rb', line 175
def splitted_description
description.split('> ')
end
|
#structural_parent ⇒ Object
63
64
65
|
# File 'app/models/exercise.rb', line 63
def structural_parent
guide
end
|
#submission_for(user) ⇒ Object
100
101
102
|
# File 'app/models/exercise.rb', line 100
def submission_for(user)
assignment_for(user).submission
end
|
#to_expanded_resource_h(options = {}) ⇒ Object
Keep this list up to date with Mumuki::Domain::Store::Github::ExerciseSchema
139
140
141
142
143
144
145
146
147
|
# File 'app/models/exercise.rb', line 139
def to_expanded_resource_h(options={})
language_resource_h = language.to_embedded_resource_h if language != guide.language
as_json(only: BASIC_RESOURCE_FIELDS)
.merge(id: bibliotheca_id, language: language_resource_h, type: type.underscore)
.merge(settings: self[:settings])
.merge(RANDOMIZED_FIELDS.map { |it| [it, self[it]] }.to_h)
.symbolize_keys
.tap { |it| it.markdownified!(:hint, :corollary, :description, :teacher_info) if options[:markdownified] }
end
|
#to_resource_h(*args) ⇒ Object
133
134
135
|
# File 'app/models/exercise.rb', line 133
def to_resource_h(*args)
to_expanded_resource_h(*args).compact
end
|
#transparent_id ⇒ Object
88
89
90
|
# File 'app/models/exercise.rb', line 88
def transparent_id
"#{guide.transparent_id}/#{bibliotheca_id}"
end
|
#transparent_params ⇒ Object
92
93
94
|
# File 'app/models/exercise.rb', line 92
def transparent_params
guide.transparent_params.merge(bibliotheca_id: bibliotheca_id)
end
|
#try_submit_solution!(user, solution = {}) ⇒ Object
Submits the user solution only if the corresponding assignment has attemps left
193
194
195
196
197
198
199
200
|
# File 'app/models/exercise.rb', line 193
def try_submit_solution!(user, solution={})
assignment = assignment_for(user)
if assignment.attempts_left?
submit_solution!(user, solution)
else
assignment
end
end
|
#used_in?(organization = Organization.current) ⇒ Boolean
51
52
53
|
# File 'app/models/exercise.rb', line 51
def used_in?(organization=Organization.current)
guide.usage_in_organization(organization).present?
end
|