Class: Rust::GoogleForm

Inherits:
Object show all
Defined in:
lib/rust/forms/google_forms.rb

Constant Summary collapse

ALLOWED_TYPES =
[:multiple, :checkbox, :scale, :text]

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data_frame, schema, mappings = {}) ⇒ GoogleForm

Returns a new instance of GoogleForm.

Raises:

  • (TypeError)


87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/rust/forms/google_forms.rb', line 87

def initialize(data_frame, schema, mappings={})
    raise TypeError, "Expected Rust::DataFrame" unless data_frame.is_a?(Rust::DataFrame)
    raise TypeError, "Expected Hash or Array" if !schema.is_a?(Hash) && !schema.is_a?(Array)
    raise TypeError, "Schema keys must all be numbers or strings" if schema.is_a?(Hash) && !schema.keys.all? { |k| k.is_a?(String) }
    raise TypeError, "Mappings should be an hash [String, Integer] -> GoogleFormMapping" if !mappings.is_a?(Hash) || !mappings.keys.all? { |k| k.is_a?(String) || k.is_a?(Integer) } || !mappings.values.all? { |v| v.is_a?(GoogleFormMapping) }
    if schema.is_a?(Array)
        new_schema = {}
        for i in 0...schema.size
            new_schema[index_to_title(i+1, data_frame)] = schema[i]
        end
        schema = new_schema
    end
    raise TypeError, "Schema values must all be #{ALLOWED_TYPES}; #{schema.values.uniq - ALLOWED_TYPES} given instead" if !schema.values.all? { |v| ALLOWED_TYPES.include?(v)}
    raise TypeError, "Schema must include types for all the questions" if schema.size != (data_frame.columns - 1)

    @data_frame = data_frame
    @questions  = data_frame.colnames
    @schema = schema

    mappings.each do |question, mapping|
        raise "Mappings can not be defined for :scale questions" if schema[title_to_index(question)] == :scale
    end
    @mappings = mappings
end

Class Method Details

.read(filename, schema, mappings = {}, **options) ⇒ Object

Reads the CSV at filename and returns a GoogleForm. The schema must be a hash that contains, for each question number or name, the type of answer (:multiple, :checkbox, :scale, or :text). For the other options, see Rust::CSV.read.



81
82
83
84
85
# File 'lib/rust/forms/google_forms.rb', line 81

def self.read(filename, schema, mappings={}, **options)
    data_frame = Rust::CSV.read(filename, **options)

    return GoogleForm.new(data_frame, schema, mappings)
end

Instance Method Details

#answer(i) ⇒ Object



128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/rust/forms/google_forms.rb', line 128

def answer(i)
    row = @data_frame.row(i)

    @questions.each_with_index do |colname, i|
        if i == 0
            row[colname] = Time.parse(row[colname])
        else
            row[colname] = get_value(row[colname], colname)
        end
    end

    return row
end

#answersObject



148
149
150
151
152
153
154
# File 'lib/rust/forms/google_forms.rb', line 148

def answers
    answers = []
    for i in 0...@data_frame.rows
        answers << self.answer(i)
    end
    return answers
end

#answers_to(question) ⇒ Object



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/rust/forms/google_forms.rb', line 178

def answers_to(question)
    question = index_to_title(question) if question.is_a?(Integer)

    results = {}

    (@data_frame|question).each do |value|
        value = get_value(value, question)
        if value.is_a?(Array)
            value.each do |v|
                results[v] = 0 unless results[v]
                results[v] += 1
            end
        else
            results[value] = 0 unless results[value]
            results[value] += 1
        end
    end
    results.delete(nil)

    return results
end

#data_frameObject



112
113
114
# File 'lib/rust/forms/google_forms.rb', line 112

def data_frame
    @data_frame
end

#each_answerObject



142
143
144
145
146
# File 'lib/rust/forms/google_forms.rb', line 142

def each_answer
    for i in 0...@data_frame.rows
        yield(self.answer(i))
    end
end

#filterObject



156
157
158
159
160
161
162
163
164
# File 'lib/rust/forms/google_forms.rb', line 156

def filter
    matching = Rust::DataFrame.new(@questions)

    for i in 0...@data_frame.rows
        matching << @data_frame.row(i) if yield(self.answer(i))
    end

    return GoogleForm.new(matching, @schema, @mappings)
end

#mapped_data_frameObject



116
117
118
119
120
121
122
# File 'lib/rust/forms/google_forms.rb', line 116

def mapped_data_frame
    df = Rust::DataFrame.new(@data_frame.colnames)
    self.each_answer do |a|
        df << a
    end
    return df
end

#percentual_answers_to(question, exclude = []) ⇒ Object



218
219
220
221
222
223
224
225
226
227
228
# File 'lib/rust/forms/google_forms.rb', line 218

def percentual_answers_to(question, exclude=[])
    answers = answers_to(question)

    exclude.each do |ex|
        answers.delete(ex)
    end

    tot = answers.values.sum
    answers = answers.map { |k, v| [k, v.to_f/tot] }.to_h
    return answers
end

#percentual_textual_answers_to(question, &block) ⇒ Object



230
231
232
233
234
235
236
# File 'lib/rust/forms/google_forms.rb', line 230

def percentual_textual_answers_to(question, &block)
    answers = textual_answers_to(question, &block)

    tot = answers.values.sum
    answers = answers.map { |k, v| [k, v.to_f/tot] }.to_h
    return answers
end

#raw_answers_to(question) ⇒ Object



166
167
168
169
170
171
172
173
174
175
176
# File 'lib/rust/forms/google_forms.rb', line 166

def raw_answers_to(question)
    question = index_to_title(question) if question.is_a?(Integer)
    results = []

    (@data_frame|question).each do |value|
        value = get_value(value, question)
        results << value
    end

    return results
end

#rowsObject



124
125
126
# File 'lib/rust/forms/google_forms.rb', line 124

def rows
    @data_frame.rows
end

#textual_answers_to(question) ⇒ Object

Raises:

  • (TypeError)


200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/rust/forms/google_forms.rb', line 200

def textual_answers_to(question)
    question = index_to_title(question) if question.is_a?(Integer)
    raise TypeError, "Expected textual question, #{@schema[question]} instead" if @schema[question] != :text

    results = {}

    (@data_frame|question).each do |value|
        value = get_value(value, question)
        next if value == nil

        category = yield(value)
        results[category] = 0 unless results[category]
        results[category] += 1
    end

    return results
end