Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ gem "ferrum"

# Math markup conversion (OMML ↔ MathML ↔ LaTeX ↔ AsciiMath)
gem "plurimath", github: "jcasimir/plurimath", branch: "main"
# Pin plurimath's own markup dependencies: newer releases restructure APIs
# (e.g. mml drops `mml/configuration`) that this plurimath revision requires.
gem "mml", "= 2.0.3"
gem "lutaml-model", "= 0.7.7"

group :development, :test do
# See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
Expand Down
18 changes: 10 additions & 8 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ GIT
GEM
remote: https://rubygems.org/
specs:
action_text-trix (2.1.17)
action_text-trix (2.1.19)
railties
actioncable (8.1.3)
actionpack (= 8.1.3)
Expand Down Expand Up @@ -89,7 +89,7 @@ GEM
securerandom (>= 0.3)
tzinfo (~> 2.0, >= 2.0.5)
uri (>= 0.13.1)
addressable (2.8.9)
addressable (2.9.0)
public_suffix (>= 2.0.2, < 8.0)
ast (2.4.3)
base64 (0.3.0)
Expand All @@ -105,7 +105,7 @@ GEM
bundler-audit (0.9.3)
bundler (>= 1.2.0)
thor (~> 1.0)
concurrent-ruby (1.3.7)
concurrent-ruby (1.3.8)
connection_pool (3.0.2)
crass (1.0.7)
date (3.5.1)
Expand All @@ -122,7 +122,7 @@ GEM
sxp (~> 2.0)
unicode-types (~> 1.8)
ed25519 (1.4.0)
erb (6.0.5)
erb (6.0.6)
erubi (1.13.1)
et-orbi (1.4.0)
tzinfo
Expand Down Expand Up @@ -203,8 +203,8 @@ GEM
lutaml-model
moxml
moxml (0.1.10)
msgpack (1.8.1)
net-imap (0.6.3)
msgpack (1.8.3)
net-imap (0.6.4.1)
date
net-protocol
net-pop (0.1.2)
Expand Down Expand Up @@ -256,7 +256,7 @@ GEM
activesupport (>= 7.0.0)
rack
public_suffix (7.0.5)
puma (7.2.0)
puma (8.0.2)
nio4r (~> 2.0)
raabro (1.4.0)
racc (1.8.1)
Expand Down Expand Up @@ -428,7 +428,7 @@ GEM
bindex (>= 0.4.0)
railties (>= 8.0.0)
webrick (1.9.2)
websocket-driver (0.8.0)
websocket-driver (0.8.2)
base64
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
Expand All @@ -455,6 +455,8 @@ DEPENDENCIES
importmap-rails
jbuilder
kamal
lutaml-model (= 0.7.7)
mml (= 2.0.3)
pg (~> 1.1)
plurimath!
propshaft
Expand Down
8 changes: 4 additions & 4 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@

root "grades#index"

resources :grades, only: [:show] do
resources :content_modules, only: [:show], path: "modules" do
resources :topics, only: [:show] do
resources :lessons, only: [:show]
resources :grades, only: [ :show ] do
resources :content_modules, only: [ :show ], path: "modules" do
resources :topics, only: [ :show ] do
resources :lessons, only: [ :show ]
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions db/migrate/20260324160002_create_modules.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def change
t.timestamps
end

add_index :content_modules, [:grade_id, :number], unique: true
add_index :content_modules, [:grade_id, :position]
add_index :content_modules, [ :grade_id, :number ], unique: true
add_index :content_modules, [ :grade_id, :position ]
end
end
4 changes: 2 additions & 2 deletions db/migrate/20260324160003_create_topics.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def change
t.timestamps
end

add_index :topics, [:content_module_id, :letter], unique: true
add_index :topics, [:content_module_id, :position]
add_index :topics, [ :content_module_id, :letter ], unique: true
add_index :topics, [ :content_module_id, :position ]
end
end
4 changes: 2 additions & 2 deletions db/migrate/20260324160004_create_lessons.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def change
t.timestamps
end

add_index :lessons, [:topic_id, :number], unique: true
add_index :lessons, [:topic_id, :position]
add_index :lessons, [ :topic_id, :number ], unique: true
add_index :lessons, [ :topic_id, :position ]
end
end
2 changes: 1 addition & 1 deletion db/migrate/20260324160009_create_assessments.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ def change
t.timestamps
end

add_index :assessments, [:content_module_id, :assessment_type], unique: true
add_index :assessments, [ :content_module_id, :assessment_type ], unique: true
end
end
2 changes: 1 addition & 1 deletion db/migrate/20260324160010_create_problems.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ def change
t.timestamps
end

add_index :problems, [:source_type, :source_id, :position], unique: true
add_index :problems, [ :source_type, :source_id, :position ], unique: true
end
end
2 changes: 1 addition & 1 deletion db/migrate/20260324160012_create_standard_taggings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ def change
t.timestamps
end

add_index :standard_taggings, [:standard_id, :taggable_type, :taggable_id],
add_index :standard_taggings, [ :standard_id, :taggable_type, :taggable_id ],
unique: true, name: "idx_standard_taggings_uniqueness"
end
end
2 changes: 1 addition & 1 deletion db/migrate/20260324223010_create_supplemental_resources.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def change
end

add_index :supplemental_resources,
[:resourceable_type, :resourceable_id, :resource_type],
[ :resourceable_type, :resourceable_id, :resource_type ],
name: "idx_supplemental_resources_lookup"
add_index :supplemental_resources, :resource_type
add_index :supplemental_resources, :source
Expand Down
2 changes: 1 addition & 1 deletion db/migrate/20260325120001_create_expressions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def change
t.timestamps
end

add_index :expressions, [:source_type, :source_id, :position], unique: true,
add_index :expressions, [ :source_type, :source_id, :position ], unique: true,
name: "idx_expressions_source_position"
add_index :expressions, :conversion_status
end
Expand Down
6 changes: 3 additions & 3 deletions lib/engageny/html_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def self.wrap_section(head_html, section_html)
def split_document
# Find the boundary between head and body content
body_match = @html.match(/\A(.*?<body[^>]*>)(.*)\z/m)
return ["", [], ""] unless body_match
return [ "", [], "" ] unless body_match

head = body_match[1]
body = body_match[2]
Expand All @@ -77,7 +77,7 @@ def split_document
body_close = body.index("</body>") || body.length

if section_starts.empty?
return [head + body[0...body_close], [], body[body_close..]]
return [ head + body[0...body_close], [], body[body_close..] ]
end

# Head includes everything up to and including the first section's start
Expand All @@ -92,7 +92,7 @@ def split_document

tail = body[body_close..]

[full_head, sections, tail]
[ full_head, sections, tail ]
end

def find_student_section_indices
Expand Down
14 changes: 7 additions & 7 deletions lib/engageny/math_converter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def manifest_summary
# We keep only the final (inserted) content and discard deletions.
def try_strip_track_changes(xml)
# Check for ins/del in either namespace
return [xml, nil] unless xml.match?(/(?:<[mw]:ins\b|<[mw]:del\b)/)
return [ xml, nil ] unless xml.match?(/(?:<[mw]:ins\b|<[mw]:del\b)/)

doc = Nokogiri::XML(xml)
word_ns = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
Expand All @@ -110,23 +110,23 @@ def try_strip_track_changes(xml)
changed = false

# Remove <w:del> and <m:del> elements entirely (deleted content)
[["w", word_ns], ["m", math_ns]].each do |prefix, ns|
[ [ "w", word_ns ], [ "m", math_ns ] ].each do |prefix, ns|
doc.xpath("//#{prefix}:del", prefix => ns).each do |del|
del.remove
changed = true
end
end

# Unwrap <w:ins> and <m:ins> elements (keep children, remove wrapper)
[["w", word_ns], ["m", math_ns]].each do |prefix, ns|
[ [ "w", word_ns ], [ "m", math_ns ] ].each do |prefix, ns|
doc.xpath("//#{prefix}:ins", prefix => ns).each do |ins|
ins.children.each { |child| ins.add_previous_sibling(child) }
ins.remove
changed = true
end
end

[doc.root.to_xml, changed ? FIXES[:strip_track_changes] : nil]
[ doc.root.to_xml, changed ? FIXES[:strip_track_changes] : nil ]
end

# Fix: Convert <m:sym> special symbol references to Unicode.
Expand All @@ -148,12 +148,12 @@ def try_strip_track_changes(xml)
"Symbol:F070" => "\u03C0", # pi π
"Symbol:F071" => "\u03B8", # theta θ
"Symbol:F044" => "\u0394", # Delta Δ
"Symbol:F053" => "\u03A3", # Sigma Σ
"Symbol:F053" => "\u03A3" # Sigma Σ
}.freeze

def try_sym_to_unicode(xml)
# <w:sym> lives in the Word namespace, not math namespace
return [xml, nil] unless xml.match?(/(?:<[mw]:sym\b)/)
return [ xml, nil ] unless xml.match?(/(?:<[mw]:sym\b)/)

doc = Nokogiri::XML(xml)
changed = false
Expand Down Expand Up @@ -184,7 +184,7 @@ def try_sym_to_unicode(xml)
end
end

[doc.root.to_xml, changed ? FIXES[:sym_to_unicode] : nil]
[ doc.root.to_xml, changed ? FIXES[:sym_to_unicode] : nil ]
end

def extract_text(omml_xml)
Expand Down
15 changes: 6 additions & 9 deletions lib/engageny/page_comparator.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require "ferrum"
require "fileutils"
require "zip"

module Engageny
class PageComparator
Expand Down Expand Up @@ -37,7 +38,7 @@ def screenshot_html
browser_path: CHROME_PATH,
headless: "new",
timeout: 30,
window_size: [900, 1200]
window_size: [ 900, 1200 ]
)

begin
Expand Down Expand Up @@ -92,18 +93,14 @@ def find_original_pdf
return nil unless zip_path.exist?

# Find the PDF inside the ZIP
output = `unzip -l "#{zip_path}" 2>/dev/null | grep "#{pdf_name}" | grep -v Archived`
return nil if output.strip.empty?

# Extract the path from the unzip listing
zip_entry = output.strip.split(/\s+/, 4).last
zip_entry = Zip::File.open(zip_path.to_s) do |zip|
zip.glob("**/*#{pdf_name}").reject { |e| e.name.include?("Archived") }.first&.name
end
return nil unless zip_entry

dest = OUTPUT_DIR.join("original.pdf")
system("unzip", "-o", zip_path.to_s, zip_entry, "-d", OUTPUT_DIR.to_s)
Zip::File.open(zip_path.to_s) { |zip| zip.extract(zip_entry, dest.to_s) { true } }

extracted = OUTPUT_DIR.join(zip_entry)
FileUtils.cp(extracted, dest) if extracted.exist?
dest.exist? ? dest : nil
end

Expand Down
8 changes: 4 additions & 4 deletions lib/tasks/engageny.rake
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ namespace :engageny do
original.chars.each_with_index do |c, i|
if reconstructed[i] != c
puts " First diff at byte #{i}"
puts " Original: #{original[[i - 30, 0].max..i + 30].inspect}"
puts " Reconstructed: #{reconstructed[[i - 30, 0].max..i + 30].inspect}"
puts " Original: #{original[[ i - 30, 0 ].max..i + 30].inspect}"
puts " Reconstructed: #{reconstructed[[ i - 30, 0 ].max..i + 30].inspect}"
break
end
end
Expand All @@ -82,7 +82,7 @@ namespace :engageny do
end

desc "Visual comparison: screenshot HTML rendering and compare against original PDF"
task :compare, [:lesson_id] => :environment do |_t, args|
task :compare, [ :lesson_id ] => :environment do |_t, args|
require_relative "../engageny/html_parser"
require_relative "../engageny/html_normalizer"
require "ferrum"
Expand Down Expand Up @@ -126,7 +126,7 @@ namespace :engageny do
browser_path: "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
headless: "new",
timeout: 30,
window_size: [1000, 1400]
window_size: [ 1000, 1400 ]
)

browser.goto("data:text/html;charset=utf-8,#{ERB::Util.url_encode(html)}")
Expand Down
4 changes: 2 additions & 2 deletions scripts/fetch_ccss_standards.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
}.freeze

TARGET_GRADES = %w[04 05 06].freeze
TARGET_GRADE_INTS = [4, 5, 6].freeze
TARGET_GRADE_INTS = [ 4, 5, 6 ].freeze

$stderr.puts "Fetching CCSS data from #{SOURCE_URL}..."
raw = URI.open(SOURCE_URL).read
Expand Down Expand Up @@ -104,7 +104,7 @@
end

# Sort by grade, domain, then code
standards.sort_by! { |s| [s[:grade_level], s[:domain_code], s[:code]] }
standards.sort_by! { |s| [ s[:grade_level], s[:domain_code], s[:code] ] }

output = {
source: "Common Core State Standards via SirFizX/standards-data (GitHub)",
Expand Down
Loading