Skip to content
This repository has been archived by the owner on Dec 23, 2017. It is now read-only.

Commit

Permalink
refactored Languages caching
Browse files Browse the repository at this point in the history
  • Loading branch information
JonJagger committed Jul 27, 2015
1 parent 1e1138a commit af2b393
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 57 deletions.
11 changes: 2 additions & 9 deletions app/controllers/setup_worker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,11 @@ module SetupWorker # mixin
include Chooser

def read_languages
dir = disk[languages.path]
if dir.exists?(cache_filename)
# languages/cache.json is created with languages/cache.rb
read = JSON.parse(dir.read(cache_filename))
else
read = languages.select{ |language|
languages.select{ |language|
language.runnable?
}.map{ |language|
language.display_name
}
end
read.sort
}.sort
end

def read_exercises
Expand Down
10 changes: 6 additions & 4 deletions app/models/Language.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,22 @@
class Language
include ExternalParentChain

def initialize(languages,name,test_name)
@parent,@name,@test_name = languages,name,test_name
def initialize(languages,dir_name,test_dir_name,display_name=nil)
@parent,@dir_name,@test_dir_name,@display_name = languages,dir_name,test_dir_name,display_name
end

attr_reader :dir_name, :test_dir_name

def path
@parent.path + @name + '/' + @test_name + '/'
@parent.path + dir_name + '/' + test_dir_name + '/'
end

def name
display_name.split(',').map{ |s| s.strip }.join('-')
end

def display_name
manifest_property
@display_name ||= manifest_property
end

def exists?
Expand Down
42 changes: 30 additions & 12 deletions app/models/Languages.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# See comments at end of file

class Languages

include ExternalParentChain
include Enumerable

Expand All @@ -17,8 +18,8 @@ def each
end

def [](name)
language_name,testing_name = renamed(name)
make_language(language_name,testing_name)
dir_name,test_dir_name = renamed(name)
make_language(dir_name,test_dir_name)
end

def renamed(was_name)
Expand All @@ -30,11 +31,27 @@ def renamed(was_name)
was_name.split('-')
end

def refresh_cache
cache = { }
dir.each_dir do |dir_name|
disk[path + dir_name].each_dir do |test_dir_name|
language = make_language(dir_name,test_dir_name)
if language.exists?
cache[language.display_name] = {
:dir_name => language.dir_name,
:test_dir_name => language.test_dir_name
}
end
end
end
dir.write(cache_filename,cache)
end

private

def new_name(name)
# maps from a language&test display_name into a
# Language-Test name corresponding to its Language/Test/ folder
# Language-Test name corresponding to its Language/Test/ *folder*
# See comment at bottom of file.
renames = {
# from way back when test name was not part of language name
Expand Down Expand Up @@ -112,24 +129,25 @@ def new_name(name)
end

def languages
@languages ||= make_cache
@languages ||= read_cache
end

def make_cache
def read_cache
cache = [ ]
dir.each_dir do |language_dir|
disk[path + language_dir].each_dir do |test_dir|
language = make_language(language_dir, test_dir)
cache << language if language.exists? && language.runnable?
end
JSON.parse(dir.read(cache_filename)).each do |display_name,language|
cache << make_language(language['dir_name'],language['test_dir_name'],display_name)
end
cache
end

def make_language(language_dir,test_dir)
Language.new(self,language_dir,test_dir)
def make_language(dir_name,test_dir_name,display_name=nil)
Language.new(self,dir_name,test_dir_name,display_name)
end

def cache_filename
'cache.json'
end

end

# - - - - - - - - - - - - - - - - - - - - - - - -
Expand Down
7 changes: 1 addition & 6 deletions languages/cache.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,4 @@

require_relative '../admin_scripts/lib_domain'

this_dir = File.expand_path('.', File.dirname(__FILE__))
manifest_filename = this_dir + '/' + 'cache.json'
File.open(manifest_filename, 'w') { |file|
cache = dojo.languages.map { |language| language.display_name }
file.write(JSON.unparse(cache))
}
dojo.languages.refresh_cache
21 changes: 18 additions & 3 deletions test/app_controllers/setup_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,29 @@ def setup_show(n)
# exercises/cache.json was out of date and this test failed.
# Some code uses cache.json and some code does not.
# There is a disconnect between the cache.json files in the
# exercises/ and languages/ folders and the caches used
# in Exercises.rb and Languages.rb whose caches do *not*
# exercises/ and languages/ folders (for dojo setup) and the
# caches used in Exercises.rb and Languages.rb whose caches do *not*
# use the disk cache but iterate through their respective
# folders on disk.
#
# Note further that different Runners may have a different
# opinion on what languages exist (are supported). Should
# there be a languages/ cache file per Runner class?
# there be a languages/ cache.json file per Runner class?
# Or just one cache.json file and the client filters. Yes.
#
#
# languages/cache.json is a cache of language.display_name values.
# [ "Asm, assert", "C (gcc), assert", ...]
# It is used by app/controllers/setup_worker.rb
#
# The cache used by Languages.rb is different. It is a cache
# of Language objects and needs to know the language/test folder names.
# Seems like there is obvious scope for merging these two caches
# into one. However some care is needed. The script the *creates*
# the cache uses the domain model. So if there is no cache there
# needs to be a backup which actually iterates. Script to create
# cache can then simply delete cache.json file and use the domain model
# to recreate it.

set_runner_class_name('RunnerStub')
runner.stub_runnable(true)
Expand Down
63 changes: 45 additions & 18 deletions test/app_models/languages_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,36 +21,61 @@ class LanguagesTests < ModelTestBase
assert path_ends_in_slash?(languages)
assert path_has_no_adjacent_separators?(languages)
end

#- - - - - - - - - - - - - - - - - - - - -

test 'refresh_cache requires manifest.json for each file to read display_name from' do
set_disk_class_name('DiskFake')
runey = languages['R-runey']
runey.dir.write('manifest.json',
{
'display_name' => 'R,Rooney'
}
)
languages.refresh_cache
languages_names = languages.map {|language| language.name }.sort
assert_equal ['R-Rooney'], languages_names
assert_equal 'R', runey.dir_name
assert_equal 'runey', runey.test_dir_name
assert_equal 'R,Rooney', runey.display_name
end

#- - - - - - - - - - - - - - - - - - - - -

test 'each() empty' do
runner.stub_runnable(false)
languages.dir.write('cache.json', cache={})
assert_equal [], languages.each.map {|language| language.name}
end

#- - - - - - - - - - - - - - - - - - - - -

test 'each() not empty' do
runner.stub_runnable(true)
languages_names = languages.each.map {|language| language.name }
['C#-NUnit','Ruby-Test::Unit'].each do |name|
assert languages_names.include? name
end
end
test 'each() not empty (also checks languages.map works directly viz you dont need languages.each.map)' do
cache = {
'Asm, assert' => {
:dir_name => 'Asm',
:test_dir_name => 'assert'
},
'C++ (g++), assert' => {
:dir_name => 'g++4.8.1',
:test_dir_name => 'assert'
}
}
languages.dir.write('cache.json', cache)
languages_names = languages.map {|language| language.name }.sort

#- - - - - - - - - - - - - - - - - - - - -

test 'is Enumerable, eg each() not needed if doing a map' do
runner.stub_runnable(true)
languages_names = languages.map {|language| language.name}
['C#-NUnit','Ruby-Test::Unit'].each do |name|
assert languages_names.include? name
end
assert_equal ['Asm-assert', 'C++ (g++)-assert'], languages_names

assert_equal 'Asm, assert', languages['Asm-assert'].display_name
assert_equal 'Asm', languages['Asm-assert'].dir_name
assert_equal 'assert', languages['Asm-assert'].test_dir_name

assert_equal 'C++ (g++), assert', languages['C++ (g++)-assert'].display_name
assert_equal 'g++4.8.1', languages['C++ (g++)-assert'].dir_name
assert_equal 'assert', languages['C++ (g++)-assert'].test_dir_name
end

#- - - - - - - - - - - - - - - - - - - - -

test 'languages[X] is language named X' do
['C (gcc)-assert','C#-NUnit'].each do |name|
assert_equal name, languages[name].name
Expand All @@ -65,6 +90,8 @@ class LanguagesTests < ModelTestBase
assert exists?(*new_name), old_name
end
end

#- - - - - - - - - - - - - - - - - - - - -

def all_language_manifest_entries
# these names harvested from cyber-dojo.org using
Expand Down
10 changes: 5 additions & 5 deletions test/test-summary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
test-summary
t a f e s time t/s a/s cov
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
app_helpers 14 32 0 0 0 0.03 507.38 1159.71 100.00
app_lib 112 4871 0 0 0 0.62 180.83 7864.57 100.00
app_models 113 371 0 0 0 0.58 194.66 639.10 100.00
lib 87 537 0 0 0 4.08 21.31 131.51 100.00
app_helpers 14 32 0 0 0 0.02 573.70 1311.31 100.00
app_lib 112 4871 0 0 0 0.63 177.09 7701.93 100.00
app_models 113 378 0 0 0 0.56 202.85 678.56 100.00
lib 87 537 0 0 0 4.09 21.29 131.38 100.00
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
total 326 5811 0 0 0 5.31 61.39 1094.35
total 326 5818 0 0 0 5.30 61.51 1097.74

t == number of tests
a == number of assertions
Expand Down

0 comments on commit af2b393

Please sign in to comment.