Skip to content
Permalink
Browse files

Speed up load time by avoiding loading YAML

Due to its sheer size, requiring YAML takes ~21 ms on Ruby 2.0.0. To
handle hub's very simple config format, we won't need most of YAML's
features, so we can afford to reimplement YAML just for the syntax we
need to support the existing config format.
  • Loading branch information...
mislav committed Dec 20, 2013
1 parent 1242b2f commit f2421405cbbc5205b9262fb54afa1a6e48bb195d
Showing with 104 additions and 3 deletions.
  1. +37 −3 lib/hub/github_api.rb
  2. +67 −0 test/github_api_test.rb
@@ -1,4 +1,3 @@
require 'yaml'
require 'forwardable'
require 'fileutils'

@@ -378,12 +377,47 @@ def save_if_needed

def load
existing_data = File.read(@filename)
@data.update YAML.load(existing_data) unless existing_data.strip.empty?
@data.update yaml_load(existing_data) unless existing_data.strip.empty?
end

def save
FileUtils.mkdir_p File.dirname(@filename)
File.open(@filename, 'w', 0600) {|f| f << YAML.dump(@data) }
File.open(@filename, 'w', 0600) {|f| f << yaml_dump(@data) }
end

def yaml_load(string)
hash = {}
host = nil
string.split("\n").each do |line|
case line
when /^---\s*$/, /^\s*(?:#|$)/
# ignore
when /^(.+):\s*$/
host = hash[$1] = []
when /^([- ]) (.+?): (.+)/
key, value = $2, $3
host << {} if $1 == '-'
host.last[key] = value
else
raise "unsupported YAML line: #{line}"
end
end
hash
end

def yaml_dump(data)
yaml = ['---']
data.each do |host, values|
yaml << "#{host}:"
values.each do |hash|
dash = '-'
hash.each do |key, value|
yaml << "#{dash} #{key}: #{value}"
dash = ' '
end
end
end
yaml.join("\n")
end
end

@@ -0,0 +1,67 @@
require 'helper'
require 'hub/github_api'
require 'forwardable'
require 'delegate'

class FileStoreTest < Minitest::Test
extend Forwardable
def_delegators :@store, :yaml_dump, :yaml_load

def setup
@store = Hub::GitHubAPI::FileStore.new('')
end

class OrderedHash < DelegateClass(::Hash)
def self.[](*args)
hash = new
while args.any?
key, value = args.shift, args.shift
hash[key] = value
end
hash
end

def initialize(hash = {})
@keys = hash.keys
super(hash)
end

def []=(key, value) @keys << key; super end

def each
@keys.each { |key| yield(key, self[key]) }
end
end

def test_yaml_dump
output = yaml_dump("github.com" => [
OrderedHash['user', 'mislav', 'oauth_token', 'OTOKEN'],
OrderedHash['user', 'tpw', 'oauth_token', 'POKEN'],
])

assert_equal <<-YAML.chomp, output
---
github.com:
- user: mislav
oauth_token: OTOKEN
- user: tpw
oauth_token: POKEN
YAML
end

def test_yaml_load
data = yaml_load <<-YAML
---
github.com:
- user: mislav
oauth_token: OTOKEN
- user: tpw
oauth_token: POKEN
YAML

assert_equal 'mislav', data['github.com'][0]['user']
assert_equal 'OTOKEN', data['github.com'][0]['oauth_token']
assert_equal 'tpw', data['github.com'][1]['user']
assert_equal 'POKEN', data['github.com'][1]['oauth_token']
end
end

0 comments on commit f242140

Please sign in to comment.
You can’t perform that action at this time.