From dbe240ac4bb8de5015998a1473f366315a3f773c Mon Sep 17 00:00:00 2001 From: "R. Tyler Croy" Date: Tue, 2 Jan 2018 15:03:18 -0800 Subject: [PATCH] Move file accesses into more opaque objects In the future I expect some of this data to be driven from a database or the Kubernetes REST API --- webapp/Dockerfile | 6 ++-- webapp/Gemfile | 3 ++ webapp/Gemfile.lock | 4 ++- webapp/app.rb | 7 +++-- webapp/lib/codevalet/webapp/authfailure.rb | 2 +- webapp/lib/codevalet/webapp/monkeys.rb | 21 ++++++++++++++ webapp/lib/codevalet/webapp/plugins.rb | 32 ++++++++++++++++++++++ webapp/spec/monkeys_spec.rb | 20 ++++++++++++++ webapp/spec/plugins_spec.rb | 26 ++++++++++++++++++ 9 files changed, 113 insertions(+), 8 deletions(-) create mode 100644 webapp/lib/codevalet/webapp/monkeys.rb create mode 100644 webapp/lib/codevalet/webapp/plugins.rb create mode 100644 webapp/spec/monkeys_spec.rb create mode 100644 webapp/spec/plugins_spec.rb diff --git a/webapp/Dockerfile b/webapp/Dockerfile index c5f069d..48c5c79 100644 --- a/webapp/Dockerfile +++ b/webapp/Dockerfile @@ -33,9 +33,9 @@ ENV BUNDLE_DISABLE_SHARED_GEMS=true ADD app.rb ${APP_DIR}/ ADD monkeys.txt ${APP_DIR}/ ADD config.ru ${APP_DIR}/ -ADD lib ${APP_DIR}/ -ADD views ${APP_DIR}/ -ADD assets ${APP_DIR}/ +ADD lib ${APP_DIR}/lib +ADD views ${APP_DIR}/views +ADD assets ${APP_DIR}/assets ADD plugins.yaml ${APP_DIR}/ diff --git a/webapp/Gemfile b/webapp/Gemfile index f20f853..ca9bae0 100644 --- a/webapp/Gemfile +++ b/webapp/Gemfile @@ -9,6 +9,9 @@ gem 'puma' # For rendering all the views gem 'haml' +# For dotted references to Hashes +gem 'hashie' + # Provides some semblance of github-based authentication and authorization # within the rack app gem 'warden-github' diff --git a/webapp/Gemfile.lock b/webapp/Gemfile.lock index 42bbd7c..119ef75 100644 --- a/webapp/Gemfile.lock +++ b/webapp/Gemfile.lock @@ -16,6 +16,7 @@ GEM haml (5.0.1) temple (>= 0.8.0) tilt + hashie (3.5.7) i18n (0.8.6) kramdown (1.14.0) minitest (5.10.3) @@ -71,6 +72,7 @@ PLATFORMS DEPENDENCIES dalli haml + hashie kramdown puma rack-cache @@ -80,4 +82,4 @@ DEPENDENCIES warden-github BUNDLED WITH - 1.16.0 + 1.16.1 diff --git a/webapp/app.rb b/webapp/app.rb index 4119fd0..30f55c1 100644 --- a/webapp/app.rb +++ b/webapp/app.rb @@ -10,11 +10,13 @@ require 'sinatra/base' require 'warden/github' require 'codevalet/webapp/authfailure' +require 'codevalet/webapp/monkeys' +require 'codevalet/webapp/plugins' Haml::TempleEngine.disable_option_validator! module CodeValet - + # Primary web application for CodeValet.io class App < Sinatra::Base include Warden::GitHub::SSO @@ -57,8 +59,7 @@ module CodeValet end def masters - file_path = File.expand_path(File.dirname(__FILE__) + '/monkeys.txt') - @monkeys ||= File.open(file_path, 'r').readlines.map(&:chomp).sort + return CodeValet::WebApp::Monkeys.data end def admin? diff --git a/webapp/lib/codevalet/webapp/authfailure.rb b/webapp/lib/codevalet/webapp/authfailure.rb index 12aa77f..dca99fa 100644 --- a/webapp/lib/codevalet/webapp/authfailure.rb +++ b/webapp/lib/codevalet/webapp/authfailure.rb @@ -4,7 +4,7 @@ module CodeValet module WebApp # Simple Sinatra application for enumerating a complete authentication # failure with Warden - class AuthFailre < Sinatra::Base + class AuthFailure < Sinatra::Base get '/unauthenticated' do status 403 <<-EOS diff --git a/webapp/lib/codevalet/webapp/monkeys.rb b/webapp/lib/codevalet/webapp/monkeys.rb new file mode 100644 index 0000000..b516ffe --- /dev/null +++ b/webapp/lib/codevalet/webapp/monkeys.rb @@ -0,0 +1,21 @@ +require 'yaml' + +require 'hashie' + +module CodeValet + module WebApp + # Simple object wrapping the monkeys.txt for exposure within the web app + class Monkeys + MONKEYS_FILE = File.expand_path(File.dirname(__FILE__) + '/../../../monkeys.txt') + + def self.data + @@monkeys_data ||= File.readlines(MONKEYS_FILE).map(&:chomp).sort + end + + # Delete the singleton's internal state. + def self.clear! + @@monkeys_data = nil + end + end + end +end diff --git a/webapp/lib/codevalet/webapp/plugins.rb b/webapp/lib/codevalet/webapp/plugins.rb new file mode 100644 index 0000000..faa4b1f --- /dev/null +++ b/webapp/lib/codevalet/webapp/plugins.rb @@ -0,0 +1,32 @@ +require 'yaml' + +require 'hashie' + +module CodeValet + module WebApp + # Simple object wrapping the plugins.yaml for exposure within the web app + class Plugins + PLUGINS_FILE = File.expand_path(File.dirname(__FILE__) + '/../../../plugins.yaml') + + # Load and return the raw plugin data from +plugins.yaml+ + # + # @return [Hash] deserialized representation of +plugins.yaml+ + def self.data + @@plugin_data ||= YAML.load(File.read(PLUGINS_FILE)) + end + + + # Load and return the essential list of plugins and their repositories + # + # @return [Hash] + def self.essential + return self.data['essential'] + end + + # Delete the singleton's internal state. + def self.clear! + @@plugin_data = nil + end + end + end +end diff --git a/webapp/spec/monkeys_spec.rb b/webapp/spec/monkeys_spec.rb new file mode 100644 index 0000000..7a4d9c1 --- /dev/null +++ b/webapp/spec/monkeys_spec.rb @@ -0,0 +1,20 @@ +require 'spec_helper' +require 'codevalet/webapp/monkeys' + +describe CodeValet::WebApp::Monkeys do + subject(:klass) { described_class } + before(:each) { klass.clear! } + + it { should respond_to :data } + describe '.data' do + subject(:data) { klass.data } + + it { should be_kind_of Array } + + it 'should only read the file once' do + expect(File).to receive(:readlines).and_call_original.once + + 1..3.times { klass.data } + end + end +end diff --git a/webapp/spec/plugins_spec.rb b/webapp/spec/plugins_spec.rb new file mode 100644 index 0000000..a556e67 --- /dev/null +++ b/webapp/spec/plugins_spec.rb @@ -0,0 +1,26 @@ +require 'spec_helper' +require 'codevalet/webapp/plugins' + +describe CodeValet::WebApp::Plugins do + subject(:klass) { described_class } + before(:each) { klass.clear! } + + it { should respond_to :data } + describe '.data' do + subject(:data) { klass.data } + + it { should be_kind_of Hash } + + it 'should only read the file once' do + expect(File).to receive(:read).and_call_original.once + + 1..3.times { klass.data } + end + end + + it { should respond_to :essential } + describe '.essential' do + subject(:essential) { klass.essential} + it { should be_kind_of Hash } + end +end