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]
- BASIC_RESOURCE_FIELDS =
%i(
name layout editor corollary teacher_info manual_evaluation locale
choices assistance_rules randomizations tag_list extra_visible 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?, #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
#description_teaser
aggregate_of, all_except, defaults, #delete, #destroy!, numbered, organic_on, resource_fields, #save, #save_and_notify!, #save_and_notify_changes!, serialize_symbolized_hash_array, #update_and_notify!, update_or_create!, whitelist_attributes
Class Method Details
.find_transparently!(params) ⇒ Object
217
218
219
|
# File 'app/models/exercise.rb', line 217
def self.find_transparently!(params)
Guide.find_transparently!(params).locate_exercise! params[:bibliotheca_id]
end
|
.locate!(slug_and_bibliotheca_id) ⇒ Object
221
222
223
224
|
# File 'app/models/exercise.rb', line 221
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
58
59
60
|
# File 'app/models/exercise.rb', line 58
def choice?
false
end
|
#choice_index_for(value) ⇒ Object
116
117
118
|
# File 'app/models/exercise.rb', line 116
def choice_index_for(value)
choice_values.index(value)
end
|
#choice_values ⇒ Object
112
113
114
|
# File 'app/models/exercise.rb', line 112
def choice_values
choices.map { |it| it.indifferent_get(:value) }
end
|
#console? ⇒ Boolean
42
43
44
|
# File 'app/models/exercise.rb', line 42
def console?
queriable?
end
|
#custom? ⇒ Boolean
180
181
182
|
# File 'app/models/exercise.rb', line 180
def custom?
false
end
|
#description_context ⇒ Object
168
169
170
|
# File 'app/models/exercise.rb', line 168
def description_context
splitted_description.first.markdownified
end
|
#description_task ⇒ Object
176
177
178
|
# File 'app/models/exercise.rb', line 176
def description_task
splitted_description.drop(1).join("\n").markdownified
end
|
#ensure_type!(type) ⇒ Object
147
148
149
150
151
152
153
|
# File 'app/models/exercise.rb', line 147
def ensure_type!(type)
if self.type != type
reclassify! type
else
self
end
end
|
#files_for(current_content) ⇒ Object
210
211
212
213
214
215
|
# File 'app/models/exercise.rb', line 210
def files_for(current_content)
language
.directives_sections
.split_sections(current_content)
.map { |name, content| Mumuki::Domain::File.new name, content }
end
|
#friendly ⇒ Object
83
84
85
|
# File 'app/models/exercise.rb', line 83
def friendly
defaulting_name { "#{navigable_parent.friendly} - #{name}" }
end
|
#guide_done_for?(user) ⇒ Boolean
54
55
56
|
# File 'app/models/exercise.rb', line 54
def guide_done_for?(user)
guide.done_for?(user)
end
|
#import_from_resource_h!(number, resource_h) ⇒ Object
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
# File 'app/models/exercise.rb', line 95
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
184
185
186
|
# File 'app/models/exercise.rb', line 184
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
202
203
204
|
# File 'app/models/exercise.rb', line 202
def limited?
!results_hidden? && navigable_parent.limited_for?(self)
end
|
#messages_path_for(user) ⇒ Object
160
161
162
|
# File 'app/models/exercise.rb', line 160
def messages_path_for(user)
"api/guides/#{guide.slug}/#{bibliotheca_id}/student/#{URI.escape user.uid}/messages?language=#{language}"
end
|
#messages_url_for(user) ⇒ Object
164
165
166
|
# File 'app/models/exercise.rb', line 164
def messages_url_for(user)
Mumukit::Platform.classroom_api.organic_url_for(Organization.current, messages_path_for(user))
end
|
#pending_siblings_for(user) ⇒ Object
230
231
232
|
# File 'app/models/exercise.rb', line 230
def pending_siblings_for(user)
guide.pending_exercises(user)
end
|
#previous ⇒ Object
62
63
64
|
# File 'app/models/exercise.rb', line 62
def previous
sibling_at number.pred
end
|
#reclassify!(type) ⇒ Object
155
156
157
158
|
# File 'app/models/exercise.rb', line 155
def reclassify!(type)
update!(type: type)
Exercise.find(id)
end
|
#reset! ⇒ Object
138
139
140
141
142
143
144
145
|
# File 'app/models/exercise.rb', line 138
def reset!
self.name = nil
self.description = nil
self.corollary = nil
self.hint = nil
self. = nil
self.tag_list = []
end
|
#results_hidden? ⇒ Boolean
206
207
208
|
# File 'app/models/exercise.rb', line 206
def results_hidden?
navigable_parent&.results_hidden_for?(self)
end
|
71
72
73
|
# File 'app/models/exercise.rb', line 71
def search_tags
[language&.name, *tag_list].compact
end
|
#settings ⇒ Object
226
227
228
|
# File 'app/models/exercise.rb', line 226
def settings
guide.settings.deep_merge super
end
|
#sibling_at(index) ⇒ Object
66
67
68
69
|
# File 'app/models/exercise.rb', line 66
def sibling_at(index)
index = number + index unless index.positive?
guide.exercises.find_by(number: index)
end
|
#splitted_description ⇒ Object
172
173
174
|
# File 'app/models/exercise.rb', line 172
def splitted_description
description.split('> ')
end
|
#structural_parent ⇒ Object
50
51
52
|
# File 'app/models/exercise.rb', line 50
def structural_parent
guide
end
|
#submission_for(user) ⇒ Object
87
88
89
|
# File 'app/models/exercise.rb', line 87
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
126
127
128
129
130
131
132
133
134
135
136
|
# File 'app/models/exercise.rb', line 126
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(expectations: self[:expectations])
.merge(custom_expectations: self[:custom_expectations])
.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
120
121
122
|
# File 'app/models/exercise.rb', line 120
def to_resource_h(*args)
to_expanded_resource_h(*args).compact
end
|
#transparent_id ⇒ Object
75
76
77
|
# File 'app/models/exercise.rb', line 75
def transparent_id
"#{guide.transparent_id}/#{bibliotheca_id}"
end
|
#transparent_params ⇒ Object
79
80
81
|
# File 'app/models/exercise.rb', line 79
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
190
191
192
193
194
195
196
197
|
# File 'app/models/exercise.rb', line 190
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
46
47
48
|
# File 'app/models/exercise.rb', line 46
def used_in?(organization=Organization.current)
guide.usage_in_organization(organization).present?
end
|