/app/models/doclets/pdf_worksheet_creator.rb
Ruby | 839 lines | 669 code | 144 blank | 26 comment | 48 complexity | 945e4032a2815f6df5fda446dab0b8d8 MD5 | raw file
- # -*- encoding : utf-8 -*-
- require 'open-uri'
- module Doclets
- class PdfWorksheetCreator
-
- attr_accessor :form_language,:rand_seed,:use_max_items
-
- def self.section_list
- @@section_list ||= Widget::PdfWidget.all.map{ |w| w.lookup }
- end
-
- def self.section_categories(section_name)
- @@section_categories_by_name ||= Hash.new
- @@section_categories_by_name[section_name] ||= Widget::PdfWidget.find_by_lookup(section_name).public_categories.split('|');
- @@section_categories = @@section_categories_by_name[section_name]
- raise "Invalid Section Name" if(@@section_categories.nil?)
- @@section_categories
- end
-
- def self.section_categories_force(section_name)
- @@section_categories_by_name.delete(section_name)
- return self.section_categories(section_name)
- end
-
- #make sure white spaces are in middle of word and separate from each other
- # It is not super optimized but will just keep retrying until a satisfying
- #random configuration is found.
- def scramble_text(text)
- scramble_text=text_stripped=text.squeeze(' ').strip;
- if(scramble_text.length>1) then
- scramble_squeeze=scramble_text.gsub(' ','');
- num_white=scramble_text.length-scramble_squeeze.length
- while(scramble_text==text_stripped)
- mix=scramble_squeeze.split(//u).sort_by { my_rand(3)-1 }.join('')
- chunks=[mix]
-
- white_error=false;
- once=false;
- while(white_error==true || once==false)
- chunks=[mix]
- once=true
- white_error=false;
- splice_chunk=lambda do |chunk,white_left|
- return chunk if(white_left<=0)
- str=chunk[0].split(//u) #done to not split in middle of utf8 sequence
- if(str.length<2) then
- white_error=true
- return chunk
- end
- pos=my_rand(str.length-1);
- str_split=[ str[0...pos+1].join('') , str[pos+1..-1].join('') ]
- rnd=my_rand(2);
- str_split[rnd]=splice_chunk.call([str_split[rnd]],white_left-1)
- return str_split
- end
- chunks=splice_chunk.call chunks,num_white
- end
- scramble_text=chunks.flatten.join(' ')
- end
- end
- scramble_text
- end
-
-
- def section_list
- self.class.section_list
- end
-
-
- def rand_seed=(new_seed)
- @rand_seed=(0xfffff ^ new_seed.to_i)&0xfffff;
- @examcode=@rand_seed.to_s(16);
- @random_generator=Random.new(@rand_seed);
- end
-
- def rand_seed
- @rand_seed
- end
-
- def initialize
- self.rand_seed=rand(1 << 31).to_s
- self.use_max_items=true
- @pdf=::Prawn::Document.new(:page_layout => :portrait,
- :left_margin => 10.mm, # different
- :right_margin => 1.cm, # units
- :top_margin => 0.84.in, # work
- :bottom_margin => 0.01.m, # well
- :page_size => "LETTER")
- @pdf.font("Helvetica", :size=>10)
- @exam_key_lambdas=[]
- @had_new_page=false
- end
-
- def my_rand(max)
- answer=@random_generator.rand(max)
- end
-
- def examcode
- @examcode
- end
- def self.max_query_cats
- 8
- end
-
- def self.max_query_sections
- 8
- end
-
- def max_query_cats
- self.class.max_query_cats
- end
-
- def max_query_sections
- self.class.max_query_sections
- end
-
- def pdf
- @pdf
- end
-
- def form_string(str)
- {
- :name=>["Name","Nombre"],
- :date=>["Date","Fecha"],
- :answer_key_title=>["Answer Key for Worksheet","Respuestas para la hoja de trabajo"],
- :continued=>["(continued)","(continuado)"],
- :categories=>["Categories","las Categorías"],
- :category=>["Category","la Categoría"],
-
- :sentence_match_answer_key=>["Sentence Match Quiz starting on page","Match de Frases en la página "],
- :fill_blanks_answer_key=>["Fill In The Blanks starting on page","Llena los Vacíos en la página "],
- :matching_quiz_answer_key=>["Word Match Quiz starting on page","Match de Palabras en la página "],
- :spelling_quiz_answer_key=>["Spelling Quiz starting on page","Corrige la Ortografía en la página "],
- :sentence_match_for=>["Sentence Match Quiz for","Match de Frases para "],
- :fill_blanks_for=>["Fill In The Blanks for","Llena los Vacíos para "],
- :matching_quiz_for=>["Word Match Quiz for","Match de Palabras para "],
- :spelling_quiz_for=>["Spelling Quiz for","Corrige la Ortografía para "],
-
- :sentence_match_instructions=>[
- "Mark the sentence that matches each item below.",
- "Marca la pareja de cada frase que se encuentra abajo.",
- ],
- :fill_blanks_instructions=>[
- "Fill in the blank with the best option that completes each sentence.",
- "Escribe en el espacio la opción que mejor completa la frase.",
- ],
- :matching_quiz_instructions=>[
- "Fill each blank with the matching word that corresponds to it from up top.",
- "Escribe en el espacio la palabra pareja de las que se encuentran arriba.",
- ],
- :spelling_quiz_instructions=>[
- "Order all the letters and fill in the blank with the corrected word.",
- "Ordena las letras y escriba en el espacio la palabra corregida.",
- ],
-
- :words_to_match=>[
- "Words to Match",
- "Palabras para Emparejar"
- ]
-
-
- }[str][self.form_language==:english ? 0 : 1]
- end
- #
- def generate_from_query!(query)
- qs0=query.split('||')
- meta=Hash[(qs0.length==2 ? qs0[0] : "exam_key:true.form_language:english").split('.').map{|s| s.split(':')}]
- self.form_language=meta["form_language"].to_sym
- self.rand_seed=meta["rand_seed"] if(!meta["rand_seed"].blank?)
- sections=qs0[1] || qs0[0]
- qs1=sections.split('|')
- raise "Too many sections (limit is #{self.max_query_sections})" if(qs1.length>self.max_query_sections)
- qs1.each do |qi|
- qs2=qi.split('.')
- parm={}
- qs2.each do |qi2|
- qk=qi2.split(':')
- parm[qk[0]]=qk[1]
- end
- if(
- !parm['wsType'].nil? &&
- !self.section_list.index(parm['wsType']).nil? &&
- !parm['categories'].nil?) then
- cats=parm["categories"].split(',')
- raise "Too many categories selected for "+parm['wsType'].gsub(/[^a-zA-Z0-09_]/,'_') if(cats.length>self.max_query_cats)
- case(parm["wsType"])
- when "word_match"
- quiz_type=["normal","large","text"].index(parm["quiz_type"]).nil? ? :normal : parm["quiz_type"].to_sym
- self.add_image_word_match!(cats,parm["maxItems"].to_i,quiz_type)
- when "kids_word_match"
- self.add_image_word_match!(cats,parm["maxItems"].to_i,:large)
- when "text_word_match"
- self.add_image_word_match!(cats,parm["maxItems"].to_i,:text)
- when "spelling_fix"
- quiz_type=["normal","large","text"].index(parm["quiz_type"]).nil? ? :normal : parm["quiz_type"].to_sym
- self.add_spelling_quiz!(cats,parm["maxItems"].to_i,quiz_type)
- when "kids_spelling_fix"
- self.add_spelling_quiz!(cats,parm["maxItems"].to_i,:large)
- when "text_spelling_fix"
- self.add_spelling_quiz!(cats,parm["maxItems"].to_i,:text)
- when "sentence_matcher"
- self.add_sentence_match!(cats,parm["maxItems"].to_i,parm["quiz_language"]!="en_to_sp",parm["random_sentences"]!="random")
- when "fill_in_the_blanks"
- self.add_blanks_quiz!(cats,parm["maxItems"].to_i)
- end
- end
- end
- self.add_exam_key! unless(meta["exam_key"]=="false")
- end
-
- def safe_pdf_text(textto)
- textto
- end
-
- #put all the static markings like copyright and page number
- def mark_page!
- @pdf.text_box("#{self.form_string :name}:_______________________________________________",:at=>[0,10.1.in])
- @pdf.text_box("#{self.form_string :date}:______________",:align=>:right,:at=>[5.5.in,10.1.in],:width=>2.in)
- @pdf.text_box("Copyright © #{Time.now.year} - 123TeachMe.com",:at=>[0.1.in,0.2.in])
- @pdf.text_box(@examcode,:at=>[6.in,0.2.in],:align=>:right,:width=>1.in)
- @pdf.text_box(@pdf.page_count.to_s,:style=>:bold,:at=>[7.in,0.2.in],:align=>:right,:width=>0.3.in)
- end
-
- def add_new_page!
- @pdf.start_new_page if(@had_new_page)
- @had_new_page=true
- self.mark_page!
- end
-
- #renders everything in the exam_key_lamdas
- def add_exam_key!
- self.add_new_page!
- @pdf.text("#{self.form_string :answer_key_title} #{@examcode}\n\n",:style=>:bold)
- #RAILS_DEFAULT_LOGGER.debug "Adding exam key"
- i_pdf=self
- @exam_key_lambdas.each do |key_lambda|
- i_pdf.add_new_page! if @pdf.cursor < 1.6.in
- key_lambda.call
- @pdf.text('')
- end
- end
-
-
- def add_image_safely!(img_uri,opts)
- #RAILS_DEFAULT_LOGGER.debug "Image #{img_uri}"
- #puts "Image #{img_uri}"
- @pdf.image(open(URI.escape(img_uri)),opts)
- rescue => e
- begin
- @pdf.image(open(URI.escape('http://static.123teachme.com/images/logo.png')),opts)
- rescue => e2
- nil
- end
- end
-
-
- def add_sentence_match!(category_array,max_items,is_sp_to_eng=true,is_matching_qa_pool=true)
- raise "Too large max_items" if(max_items>32 && self.use_max_items)
- raise "Too few max_items" if(max_items<4)
- is_cmulti_str = category_array.length>1 ? "#{self.form_string :categories}: "+category_array.join(", ") : "#{self.form_string :category}: "+category_array[0]
- tlist=[
-
- "(" + (0...category_array.length).to_a.map {"categories RLIKE ?"}.join(" OR ") +")"
- ].concat( category_array.map { |cai| "[[:<:]]#{cai}[[:>:]]"} )
- tso=TranslatedSentence.all(:conditions=>tlist,:order=>"rand(#{self.rand_seed})",:limit=>max_items)
- raise "Too few Translated Sentences returned (#{tso.length})<4" if(tso.length<4)
- answer_key_str="#{self.form_string :sentence_match_answer_key} #{@pdf.page_count} "
- answer_key_ar=[];
- self.add_new_page!
- @pdf.text("#{self.form_string :sentence_match_for} #{is_cmulti_str} \n",:style=>:bold)
- @pdf.text("#{self.form_string :sentence_match_instructions} \n")
- num_incorrect=3;
- throw :too_many_sentence_match_possibilities if(num_incorrect>26)
-
- if(!is_matching_qa_pool) then
- #limit should provide a safe amount even in worse case repetition of questions scenario
- tso_rand=TranslatedSentence.all(:order=>"rand(#{self.rand_seed})",:limit=>max_items*(num_incorrect+1)+1)
- end
-
- tso.each_with_index do |tsi,i|
- if @pdf.cursor < 1.2.in then
- self.add_new_page!
- @pdf.text("#{self.form_string :continued} #{self.form_string :sentence_match_for} #{is_cmulti_str} \n",:style=>:bold);
- @pdf.text("#{self.form_string :sentence_match_instructions} \n");
- end
- get_question=is_sp_to_eng ? lambda {|ts| ts.spanish } : lambda {|ts| ts.english }
- get_answer=is_sp_to_eng ? lambda {|ts| ts.english } : lambda {|ts| ts.spanish }
- letter_array="ABCDEFGHIJKLMNOPQRSTUVWXYZ".split(//)
- if(is_matching_qa_pool) then
- ts_copy=tso.dup;
- tmp_ar=[tsi].concat( ts_copy[0...i].concat(ts_copy[i+1...(ts_copy.length)]).sort{my_rand(3)-1}[0...num_incorrect])
- else
- ts_copy=tso_rand.shift(num_incorrect)
- cutout_idx=ts_copy.find {|o| o.id==tsi.id }
- tso_final=
- if(cutout_idx) then
- tso_rand.push(ts_copy[cutout_idx])
- ts_copy[0...cutout_idx].concat(ts_copy[i+1...(ts_copy.length)]).concat([tso_rand.shift])
- else
- ts_copy
- end
- tmp_ar=[tsi].concat(tso_final)
- end
-
- ans_ar=(0..num_incorrect).sort{ my_rand(3)-1 }
- correct_letter=letter_array[ans_ar.index(0)]
- @pdf.text("\n#{i+1}) #{get_question.call(tsi)}",:style=>:bold)
- ans_ar.each_with_index do |ai,idx2|
- @pdf.text(" - #{letter_array[idx2]}: #{get_answer.call(tmp_ar[ai])}")
- end
-
- answer_key_ar<<"#{i+1} = #{correct_letter}"
-
- end
-
- self.add_exam_key_lambda {
- @pdf.text(answer_key_str,:style=>:italic)
- @pdf.text(answer_key_ar.join(" , ")+"\n\n")
- };
- end
- #quiz_type is one of :normal, :large (for kids), :text
- def add_spelling_quiz!(category_array,max_items,quiz_type=:normal)
-
- raise "Too large max_items" if(max_items>40 && self.use_max_items)
- is_cmulti_str = category_array.length>1 ? "#{self.form_string :categories}: "+category_array.join(", ") : "#{self.form_string :category}: "+category_array[0];
- tlist=[
- "(length(image_best)>10 OR length(image)>10) AND"+
- "(image_best LIKE '%jpg' OR image LIKE '%jpg' ) AND "+
- "(" + (0...category_array.length).to_a.map {"categories RLIKE ?"}.join(" OR ") +")"
- ].concat( category_array.map { |cai| "[[:<:]]#{cai}[[:>:]]"} )
- mm=MediaMapping.all(:conditions=>tlist,:order=>"rand(#{self.rand_seed})",:limit=>max_items)
-
- answer_key_str="#{self.form_string :spelling_quiz_answer_key} #{@pdf.page_count} "
- answer_key_ar=[];
- per_page=
- case(quiz_type)
- when :text
- 16
- when :large
- 4
- when :normal
- 10
- end
-
-
- mm.each_with_index do |mmi,i|
- spanish_segment=mmi.spanish.split('(')[0]
- local_i=i%per_page;
- if(local_i==0) then
- self.add_new_page!
- if(i>0) then
-
- @pdf.text("#{self.form_string :continued} #{self.form_string :spelling_quiz_for} #{is_cmulti_str}",:style=>:bold);
- else
- @pdf.text("#{self.form_string :spelling_quiz_for} #{is_cmulti_str}",:style=>:bold);
- end
- @pdf.text("#{self.form_string :spelling_quiz_instructions} \n");
-
-
- end
-
- vertical_spacing=
- case(quiz_type)
- when :text
- 2.67.cm
- when :large
- 4.36.in
- when :normal
- 4.58.cm;
- end
-
- xy_fit_size=
- case(quiz_type)
- when :text
- 2.28.cm
- when :large
- 6.25.cm
- when :normal
- 3.cm
- end.to_f;
-
- img_y=9.in-(vertical_spacing*(local_i/2).floor)
- img_x=(local_i%2)*(8.in/2)+0.5.cm
-
-
- img_uri_tmp=
- !mmi.image_best.blank? && ( !mmi.image_best.index('.jpg').nil? ) ?
- mmi.image_best : mmi.image;
-
- img_uri=img_uri_tmp.index('http').nil? ? 'http://static.123teachme.com'+img_uri_tmp : img_uri_tmp;
-
- image=nil;
- if(quiz_type==:large) then
- @pdf.bounding_box([img_x,img_y],:width=>8.cm,:height=>xy_fit_size) do
- image=self.add_image_safely!(img_uri,:fit=>[xy_fit_size,xy_fit_size],:position=>:center,:vposition=>:centre)
- end
- elsif(quiz_type==:normal)
- image=self.add_image_safely!(img_uri,:fit=>[xy_fit_size,xy_fit_size],:at=>[img_x,img_y])
- else
- image=-1
- end
- if(!image.nil?) then
-
- if(image!=-1) then
- horiz_ratio=image.width.to_f/image.height.to_f;
- vert_ratio=1.0/horiz_ratio;
- end
-
- label_width=
- case(quiz_type)
- when :large, :text
- 8.cm
- when :normal
- 4.cm
- end.to_f;
-
-
- label_x,label_y=
- case(quiz_type)
- when :text
- [img_x,img_y]
- when :normal
- [
- horiz_ratio<1.0 ? img_x- (label_width- xy_fit_size*horiz_ratio)/2.0 : img_x-(label_width-xy_fit_size)/2.0,
- vert_ratio<1.0 ? img_y- (xy_fit_size*vert_ratio+2.mm) : img_y- (xy_fit_size+2.mm)
- ]
- when :large
- [
- img_x,
- img_y-xy_fit_size-0.1.cm
- ]
- end
-
- @pdf.text_box(
- mmi.english,
- :at=>[label_x,label_y],
- :align=>:center,
- :width=>label_width,
- :height=>1.cm,
- :size=>(quiz_type==:large ? 15 : 12)
- )
-
- line_x,line_x2,line_y=
- case(quiz_type)
- when :text
- [img_x+0.27.cm,img_x+label_width-0.27.cm,img_y-1.4.cm]
- when :normal
- tx=img_x+xy_fit_size+0.5.cm;
- [ tx,tx+5.cm,label_y ]
- when :large
- [ img_x,img_x+8.cm, label_y-1.74.cm]
- end
- tmp_width=@pdf.line_width
- @pdf.line_width=0.04.cm
- @pdf.stroke { @pdf.horizontal_line( line_x,line_x2,:at=>line_y, :width=>0.1.cm) }
- @pdf.line_width=tmp_width
-
-
- number_x=img_x-0.75.cm;
- number_y=img_y+0.1.cm;
- @pdf.text_box((i+1).to_s+")",:at=>[number_x,number_y],:align=>:right,:width=>0.70.cm)
- scrambled_x,scrambled_y=
- case(quiz_type)
- when :normal
- [ line_x,img_y+0.1.cm ]
- when :large,:text
- [ label_x,line_y-0.21.cm ]
- end
-
- #simple way to make sure it is scrambled
-
- scrambled_text=self.scramble_text(spanish_segment)
-
-
- @pdf.fill_color('334499')
- @pdf.text_box(
- scrambled_text,
- :at=>[scrambled_x,scrambled_y],
- :align=>:center,
- :style=>:bold,
- :fill_color=>'ccbbaa',
- :width=>label_width,
- :size=>(quiz_type==:large ? 14 : 11.5)
- )
- @pdf.fill_color('000000')
-
- if(quiz_type==:text) then
- @pdf.bounding_box([img_x,img_y+0.12.cm],:width=>8.cm,:height=>2.34.cm) { @pdf.stroke_bounds }
- end
-
- answer_key_ar<< "#{i+1} = #{spanish_segment}"
- end
- end
- self.add_exam_key_lambda {
- @pdf.text(answer_key_str,:style=>:italic)
- @pdf.text(answer_key_ar.join(" , ")+"\n\n")
- };
- end
- def add_image_word_match!(category_array,max_items,quiz_type=:normal)
-
- raise "Too large max_items" if(max_items>32 && self.use_max_items)
- is_cmulti_str = category_array.length>1 ? "#{self.form_string :categories}: "+category_array.join(", ") : "#{self.form_string :category}: "+category_array[0];
- tlist=[
- "(length(image_best)>10 OR length(image)>10) AND"+
- "(image_best LIKE '%jpg' OR image LIKE '%jpg' ) AND "+
- "(" + (0...category_array.length).to_a.map {"categories RLIKE ?"}.join(" OR ") +")"
- ].concat( category_array.map { |cai| "[[:<:]]#{cai}[[:>:]]"} )
- mm=MediaMapping.all(:conditions=>tlist,:order=>"rand(#{self.rand_seed})",:limit=>max_items)
-
- if(quiz_type!=:large) then
- spanish_to_match=
- "<u>#{self.form_string :words_to_match}:</u> <i>"+
- mm.map { |mmi| mmi.spanish }.sort {my_rand(3)-1}.join(" - ")+
- "</i>"
- end
- answer_key_str="#{self.form_string :matching_quiz_answer_key} #{@pdf.page_count} "
- answer_key_ar=[];
- per_page=
- case(quiz_type)
- when :text
- 16
- when :large
- 4
- when :normal
- 8
- end
-
-
- mm.each_with_index do |mmi,i|
- local_i=i%per_page;
- if(local_i==0) then
- self.add_new_page!
- if(i>0) then
-
- @pdf.text("#{self.form_string :continued} #{self.form_string :matching_quiz_for} #{is_cmulti_str}",:style=>:bold);
- else
- @pdf.text("#{self.form_string :matching_quiz_for} #{is_cmulti_str}",:style=>:bold);
- end
- @pdf.text("#{self.form_string :matching_quiz_instructions} \n");
- @pdf.y=@pdf.y-2.5.mm
- if(quiz_type==:large) then
- mma=mm[i...i+4].sort{my_rand(3)-1}
- spanish_to_match=
- "<u>#{self.form_string :words_to_match}:</u>\n<i>"+
- mma.map{ |cur_mi| "<b>#{cur_mi.spanish}</b>" }.join(" - ")+
- "</i>"
- end
- @pdf.text("#{spanish_to_match}",:align=>:center,:inline_format => true,:size=>(quiz_type==:large ? 16 : 11 ))
-
-
- end
-
- vertical_spacing=
- case(quiz_type)
- when :text
- 2.54.cm
- when :large
- 4.36.in
- when :normal
- 5.1.cm;
- end
-
- xy_fit_size=
- case(quiz_type)
- when :text
- 2.28.cm
- when :large
- 6.25.cm
- when :normal
- 3.cm
- end.to_f;
-
- img_y=8.25.in-(vertical_spacing*(local_i/2).floor)
- img_x=(local_i%2)*(8.in/2)+0.5.cm
-
- img_uri_tmp=
- !mmi.image_best.blank? && ( !mmi.image_best.index('.jpg').nil? ) ?
- mmi.image_best : mmi.image;
-
- img_uri=img_uri_tmp.index('http').nil? ? 'http://static.123teachme.com'+img_uri_tmp : img_uri_tmp;
-
- image=nil;
- if(quiz_type==:large) then
- @pdf.bounding_box([img_x,img_y],:width=>8.cm,:height=>xy_fit_size) do
- image=self.add_image_safely!(img_uri,:fit=>[xy_fit_size,xy_fit_size],:position=>:center,:vposition=>:centre)
- end
- elsif(quiz_type==:normal)
- image=self.add_image_safely!(img_uri,:fit=>[xy_fit_size,xy_fit_size],:at=>[img_x,img_y])
- else
- image=-1
- end
-
-
- if(!image.nil?) then
- if(image!=-1) then
- horiz_ratio=image.width.to_f/image.height.to_f;
- vert_ratio=1.0/horiz_ratio;
- end
-
- label_width=
- case(quiz_type)
- when :large, :text
- 8.cm
- when :normal
- 4.cm
- end.to_f;
-
-
- label_x,label_y=
- case(quiz_type)
- when :text
- [img_x,img_y-0.58.cm]
- when :normal
- [
- horiz_ratio<1.0 ? img_x- (label_width- xy_fit_size*horiz_ratio)/2.0 : img_x-(label_width-xy_fit_size)/2.0,
- vert_ratio<1.0 ? img_y- (xy_fit_size*vert_ratio+2.mm) : img_y- (xy_fit_size+2.mm)
- ]
- when :large
- [
- img_x,
- img_y-xy_fit_size-0.1.cm
- ]
- end
-
- @pdf.text_box(
- mmi.english,
- :at=>[label_x,label_y],
- :align=>:center,
- :width=>label_width,
- :height=>1.cm,
- :size=>(quiz_type==:large ? 15 : 12)
- )
-
- line_x,line_x2,line_y=
- case(quiz_type)
- when :text
- [img_x+0.27.cm,img_x+label_width-0.27.cm,img_y-0.4.cm]
- when :normal
- tx=img_x+xy_fit_size+0.5.cm;
- [ tx,tx+5.cm,label_y ]
- when :large
- [ img_x,img_x+8.cm, label_y-1.74.cm]
- end
- tmp_width=@pdf.line_width
- @pdf.line_width=0.04.cm
- @pdf.stroke { @pdf.horizontal_line( line_x,line_x2,:at=>line_y, :width=>0.1.cm) }
- @pdf.line_width=tmp_width
-
-
- number_x=img_x-0.75.cm;
- number_y=img_y+0.1.cm;
- @pdf.text_box((i+1).to_s+")",:at=>[number_x,number_y],:align=>:right,:width=>0.70.cm)
-
- #if(quiz_type==:text) then
- # @pdf.bounding_box([img_x,img_y+0.12.cm],:width=>8.cm,:height=>2.34.cm) { @pdf.stroke_bounds }
- #end
-
- answer_key_ar<< "#{i+1} = #{mmi.spanish}"
- end
- end
- self.add_exam_key_lambda {
- @pdf.text(answer_key_str,:style=>:italic)
- @pdf.text(answer_key_ar.join(" , ")+"\n\n")
- };
-
- end
-
-
- def add_blanks_quiz!(category_array,max_items)
- #Build items
- raise "Too large max_items" if(max_items>80 && self.use_max_items)
- tlist=[
- "length(correct_answer)>1 AND length(wrong_answers)>1 AND ("+
- (0...category_array.length).to_a.map {"quiz_categories RLIKE ?"}.join(" OR ")+
- ")"
- ].concat( category_array.map { |cai| "[[:<:]]#{cai}[[:>:]]"} )
-
- data=[];
- self.add_new_page!
-
- is_cmulti_str = category_array.length>1 ? "#{self.form_string :categories}: "+category_array.join(", ") : "#{self.form_string :category}: "+category_array[0];
-
- @pdf.text("#{self.form_string :fill_blanks_for} #{is_cmulti_str} \n",:style=>:bold);
- @pdf.text("#{self.form_string :fill_blanks_instructions} \n\n");
-
- TranslatedSentence.all(:conditions=>tlist,:order=>"rand(#{self.rand_seed})",:limit=>max_items).each do |sq|
-
- #verb might be in a different case in the sentence
- sp=sq.spanish;
- ca=sq.correct_answer;
-
-
- m=sp.upcase.match(Regexp.new(
- '(\b|[¿¡])('+
- ca.upcase+')(\b)',true));
- if(!m.nil?) then
-
- i=m.begin(1)+m[1].length;
- sqn=sp[0...i]+("___"*3)+sp[(i+ca.length)..-1];
-
- data<<{
- :cats=>sq.quiz_categories,
- :english=>sq.english,
- :spanish=>sqn,
- :correct=>ca,
- :incorrect=>sq.wrong_answers.gsub("|",",").split(","),
- };
- else
- #do a looser check
- i=sp.upcase.index(ca.upcase);
- if(!i.nil?) then
-
- sqn=sp[0...i]+("___"*3)+sp[(i+ca.length)..-1];
- data<<{
- :cats=>sq.quiz_categories,
- :english=>sq.english,
- :spanish=>sqn,
- :correct=>ca,
- :incorrect=>sq.wrong_answers.gsub("|",",").split(",")
- };
- else
- #Flag there is something strange with the data
- next
- data<<{
- :cats=>sq.quiz_categories,
- :flag=>true,
- :id=>sq.id,
- :english=>sq.english,
- :spanish=>sp,
- :correct=>ca,
- :incorrect=>sq.wrong_answers.gsub("|",",").split(",")
- };
- end
- end
- end
-
- #---step categories, so similar quizzes are not all next to each other
-
- #first separate data into categories
- data_tmp={}
- data.each do |i|
- data_tmp[i[:cats]]||=[];
- data_tmp[i[:cats]]<< i;
- end
-
- #count how many are in each category and assign 0 to frequency weight
- full_count=data.length+0.0;
- cat_cnt={};
- cat_weight={};
- cat_len=data_tmp.keys.length;
- data_tmp.keys.each do |k|
- cat_cnt[k]=data_tmp[k].length+0.0;
- cat_weight[k]=0.0;
- end
-
- data=[];
-
- #now separate, putting one from each category weighted by how many elements are in that category
- while(!data_tmp.empty?) do
- data_ntmp={};
- data_tmp.keys.sort.each do |k|
- cat_weight[k]+=cat_cnt[k]/full_count;
- ar=data_tmp[k].dup;
- if(cat_weight[k]>1.0) then
-
- cat_weight[k]-=1.0;
- i=ar.pop();
- i.delete(:cats); #cats unused in widget now, delete done for security and transmission efficiency
- data<< i;
- if(!ar.empty?) then
- data_ntmp[k]=ar;
- end
- else
- data_ntmp[k]=ar;
- end
- end
- data_tmp=data_ntmp;
- end
-
- #Now render the page
- answer_key_str="#{self.form_string :fill_blanks_answer_key} #{@pdf.page_count} "
- answer_key_ar=[];
-
- data.each_with_index do |di,i|
-
- safe_text=self.safe_pdf_text(di[:spanish])
- ::Rails.logger.debug safe_text
- if @pdf.cursor < 1.in then
- self.add_new_page!
- @pdf.text("#{self.form_string :continued} #{self.form_string :fill_blanks_for} #{is_cmulti_str} \n",:style=>:bold);
- @pdf.text("#{self.form_string :fill_blanks_instructions}\n\n");
- end
- @pdf.text("#{i+1}) #{safe_text} ")
- @pdf.text(" ("+di[:incorrect].concat([di[:correct]]).sort{my_rand(3)-1}.join(', ')+") \n\n",:style=>:italic)
-
- answer_key_ar<< "#{i+1} = #{di[:correct]}"
- end
-
- self.add_exam_key_lambda {
- @pdf.text(answer_key_str,:style=>:italic)
- @pdf.text(answer_key_ar.join(" , ")+"\n\n")
- };
-
- end
- protected
- #These are all executed right before rendering the page
- def add_exam_key_lambda(&proc)
- @exam_key_lambdas<<proc
- end
-
-
- end
- end