2014-10-07 2 views
-1

У меня есть следующий метод, чтобы прочитать файл в формате JSON и преобразовать его в Question объекта:Как преобразовать строку в объект

def self.deserializeQuestions(json) 
    if json.nil? 
    else 
    data = JSON.parse(json) 
    questions = Hash.new 
    data['questions'].map do |q| 
     questions[q['id']] = Question.new(q['id'], q['questionText']) 
    end 
    end 
end 

JSON содержит вопросы разных типов, которые соответствуют различным классам. Типы: 'multichoice', 'truefalse' и т. Д., А классы - MultichoiceQuestion, TrueFalseQuestion и т. Д. Все они наследуют от Question, которые все еще имеют id и questionText.

Ниже приведен пример файла JSON я использую:

{ "questions": 
    [ 
    { 
     "type": "multichoice", 
     "id" : 1, 
     "questionText": "Scala is...", 
     "alternatives": [ 
      { "text": "alternative 1", "code": 1, "value": 1 }, 
      { "text": "alternative 2", "code": 2, "value": -0.25 }, 
      { "text": "alternative 3", "code": 3, "value": -0.25 } 
     ] 
    }, 
    { 
     "type" : "truefalse", 
     "id" : 2, 
     "questionText": "Ruby creator is Yukihiro Matsumoto", 
     "correct": true, 
     "valueOK": 1, 
     "valueFailed": -0.25, 
    } 
    ] 
} 

Как я могу изменить этот код, чтобы иметь возможность создавать определенные типы Question на основе типа атрибута?

+3

Как бы вы поняли, когда создавать объекты класса ... Вам нужно предоставить дополнительную информацию .. –

+0

Я отредактировал вопрос на примере используемого файла JSON. –

+1

Вы не упомянули 'questionId' в JSON, который вы разбираете. Вы уверены, что это 'questionId', а не' id'? – Surya

ответ

2

Вот что, я бы моделировать вашу проблему с помощью Struct -

hash = { "questions" => 
     [ 
      { 
      "type" => "multichoice", 
      "id" => 1, 
      "questionText" => "Scala is...", 
      }, 
      { 
      "type" => "truefalse", 
      "id" => 2, 
      "questionText" => "Ruby creator is Yukihiro Matsumoto", 
      } 
     ] 
     } 

questions = hash['questions'].map do |inner_hash| 
    Struct.new(inner_hash['type'].capitalize, :id, :question_text).new(*inner_hash.values_at('id', 'questionText')) 
end 

questions 
# => [#<struct Struct::Multichoice id=1, question_text="Scala is...">, 
#  #<struct Struct::Truefalse 
#  id=2, 
#  question_text="Ruby creator is Yukihiro Matsumoto">] 

questions.map(&:values) 
# => [[1, "Scala is..."], [2, "Ruby creator is Yukihiro Matsumoto"]] 
+0

Я думаю, что это имеет ту же проблему, что и в ответе выше. Мне нужно, чтобы конкретный тип вопроса мог задавать его конкретные значения. В случае истинного вопроса JSON содержит правильный ответ (true false), который должен храниться в объекте. То же самое происходит с другими типами вопросов, у которых есть свои атрибуты. Извини, была моя ошибка. Я слишком упростил JSON. –

+1

Я думаю, что 'Struct' - это способ решить вашу проблему. Вы снова отредактируете сообщение, если сможете, я постараюсь помочь вам в следующем, когда я снова откроюсь в SO. –

+0

Отредактировано. Я добавил еще несколько свойств. Я решил эту проблему с помощью блоков, но я искал более элегантный код. Спасибо за помощь. –

1

Пусть тип класса соответствие выражается в виде хэша

TypeClass = { 
    "multichoice" => MultichoiceQuestion, 
    "truefalse" => TrueFalseQuestion, 
    ... 
} 

Затем, сделайте следующее:

JSON.parse(json)["questions"].each_with_object({}) do |h, questions| 
    questions[h["id"]] = TypeClass[h["type"]].new(h["id"], h["questionText"]) 
end 
+0

Да, это действительно хорошее решение, но мне нужно знать тип вопроса, потому что у каждого типа есть свои атрибуты. Например, вопросы многозадачности могут иметь фиксированное количество ответов, но вопрос истинного ответа будет иметь только два (истинные и ложные), и только один может быть действительным. –

+0

@ DavidMorenoGarcía Я не понимаю, что вы подразумеваете под «необходимостью знать тип вопроса». Вы не получаете это от JSON? – sawa

+0

Я имею в виду, что в этом примере вы создаете вопрос, основанный на типе, но после этого есть больше значений, которые необходимо добавить к объекту. Пример Myabe JSON недостаточно ясен, но, например, в истинном вопросе я должен добавить правильный ответ. Можно ли создать хэш с помощью метода вместо класса? Таким образом я мог бы создать конкретные обработчики для каждого типа вопросов. –

Смежные вопросы