glyph 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +80 -0
- data/Rakefile +51 -0
- data/VERSION +1 -0
- data/bin/glyph +7 -0
- data/book/config.yml +5 -0
- data/book/document.glyph +55 -0
- data/book/images/glyph.png +0 -0
- data/book/images/glyph.svg +351 -0
- data/book/lib/macros/reference.rb +98 -0
- data/book/output/html/glyph.html +1809 -0
- data/book/output/html/images/glyph.png +0 -0
- data/book/output/html/images/glyph.svg +351 -0
- data/book/output/pdf/glyph.pdf +4277 -0
- data/book/snippets.yml +13 -0
- data/book/styles/css3.css +220 -0
- data/book/styles/default.css +190 -0
- data/book/text/authoring.textile +351 -0
- data/book/text/extending.textile +148 -0
- data/book/text/getting_started.textile +152 -0
- data/book/text/introduction.textile +88 -0
- data/book/text/ref_commands.textile +74 -0
- data/book/text/ref_config.textile +0 -0
- data/book/text/ref_macros.textile +256 -0
- data/book/text/troubleshooting.textile +118 -0
- data/config.yml +63 -0
- data/document.glyph +29 -0
- data/glyph.gemspec +138 -0
- data/lib/glyph.rb +128 -0
- data/lib/glyph/commands.rb +124 -0
- data/lib/glyph/config.rb +152 -0
- data/lib/glyph/document.rb +145 -0
- data/lib/glyph/glyph_language.rb +530 -0
- data/lib/glyph/glyph_language.treetop +27 -0
- data/lib/glyph/interpreter.rb +84 -0
- data/lib/glyph/macro.rb +69 -0
- data/lib/glyph/node.rb +126 -0
- data/lib/glyph/system_extensions.rb +77 -0
- data/macros/common.rb +66 -0
- data/macros/filters.rb +69 -0
- data/macros/html/block.rb +119 -0
- data/macros/html/inline.rb +43 -0
- data/macros/html/structure.rb +138 -0
- data/spec/files/container.textile +5 -0
- data/spec/files/document.glyph +2 -0
- data/spec/files/document_with_toc.glyph +3 -0
- data/spec/files/included.textile +4 -0
- data/spec/files/ligature.jpg +449 -0
- data/spec/files/markdown.markdown +8 -0
- data/spec/files/test.sass +2 -0
- data/spec/lib/commands_spec.rb +83 -0
- data/spec/lib/config_spec.rb +79 -0
- data/spec/lib/document_spec.rb +100 -0
- data/spec/lib/glyph_spec.rb +76 -0
- data/spec/lib/interpreter_spec.rb +90 -0
- data/spec/lib/macro_spec.rb +60 -0
- data/spec/lib/node_spec.rb +76 -0
- data/spec/macros/filters_spec.rb +42 -0
- data/spec/macros/macros_spec.rb +159 -0
- data/spec/spec_helper.rb +92 -0
- data/spec/tasks/generate_spec.rb +31 -0
- data/spec/tasks/load_spec.rb +37 -0
- data/spec/tasks/project_spec.rb +41 -0
- data/styles/css3.css +220 -0
- data/styles/default.css +190 -0
- data/tasks/generate.rake +57 -0
- data/tasks/load.rake +55 -0
- data/tasks/project.rake +33 -0
- metadata +192 -0
data/glyph.gemspec
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{glyph}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Fabio Cevasco"]
|
12
|
+
s.date = %q{2010-04-09}
|
13
|
+
s.default_executable = %q{glyph}
|
14
|
+
s.description = %q{Glyph is a framework for structured document authoring.}
|
15
|
+
s.email = %q{h3rald@h3rald.com}
|
16
|
+
s.executables = ["glyph"]
|
17
|
+
s.extra_rdoc_files = [
|
18
|
+
"README.textile"
|
19
|
+
]
|
20
|
+
s.files = [
|
21
|
+
"README.textile",
|
22
|
+
"Rakefile",
|
23
|
+
"VERSION",
|
24
|
+
"bin/glyph",
|
25
|
+
"book/config.yml",
|
26
|
+
"book/document.glyph",
|
27
|
+
"book/images/glyph.png",
|
28
|
+
"book/images/glyph.svg",
|
29
|
+
"book/lib/macros/reference.rb",
|
30
|
+
"book/output/html/glyph.html",
|
31
|
+
"book/output/html/images/glyph.png",
|
32
|
+
"book/output/html/images/glyph.svg",
|
33
|
+
"book/output/pdf/glyph.pdf",
|
34
|
+
"book/snippets.yml",
|
35
|
+
"book/styles/css3.css",
|
36
|
+
"book/styles/default.css",
|
37
|
+
"book/text/authoring.textile",
|
38
|
+
"book/text/extending.textile",
|
39
|
+
"book/text/getting_started.textile",
|
40
|
+
"book/text/introduction.textile",
|
41
|
+
"book/text/ref_commands.textile",
|
42
|
+
"book/text/ref_config.textile",
|
43
|
+
"book/text/ref_macros.textile",
|
44
|
+
"book/text/troubleshooting.textile",
|
45
|
+
"config.yml",
|
46
|
+
"document.glyph",
|
47
|
+
"glyph.gemspec",
|
48
|
+
"lib/glyph.rb",
|
49
|
+
"lib/glyph/commands.rb",
|
50
|
+
"lib/glyph/config.rb",
|
51
|
+
"lib/glyph/document.rb",
|
52
|
+
"lib/glyph/glyph_language.rb",
|
53
|
+
"lib/glyph/glyph_language.treetop",
|
54
|
+
"lib/glyph/interpreter.rb",
|
55
|
+
"lib/glyph/macro.rb",
|
56
|
+
"lib/glyph/node.rb",
|
57
|
+
"lib/glyph/system_extensions.rb",
|
58
|
+
"macros/common.rb",
|
59
|
+
"macros/filters.rb",
|
60
|
+
"macros/html/block.rb",
|
61
|
+
"macros/html/inline.rb",
|
62
|
+
"macros/html/structure.rb",
|
63
|
+
"spec/files/container.textile",
|
64
|
+
"spec/files/document.glyph",
|
65
|
+
"spec/files/document_with_toc.glyph",
|
66
|
+
"spec/files/included.textile",
|
67
|
+
"spec/files/ligature.jpg",
|
68
|
+
"spec/files/markdown.markdown",
|
69
|
+
"spec/files/test.sass",
|
70
|
+
"spec/lib/commands_spec.rb",
|
71
|
+
"spec/lib/config_spec.rb",
|
72
|
+
"spec/lib/document_spec.rb",
|
73
|
+
"spec/lib/glyph_spec.rb",
|
74
|
+
"spec/lib/interpreter_spec.rb",
|
75
|
+
"spec/lib/macro_spec.rb",
|
76
|
+
"spec/lib/node_spec.rb",
|
77
|
+
"spec/macros/filters_spec.rb",
|
78
|
+
"spec/macros/macros_spec.rb",
|
79
|
+
"spec/spec_helper.rb",
|
80
|
+
"spec/tasks/generate_spec.rb",
|
81
|
+
"spec/tasks/load_spec.rb",
|
82
|
+
"spec/tasks/project_spec.rb",
|
83
|
+
"styles/css3.css",
|
84
|
+
"styles/default.css",
|
85
|
+
"tasks/generate.rake",
|
86
|
+
"tasks/load.rake",
|
87
|
+
"tasks/project.rake"
|
88
|
+
]
|
89
|
+
s.homepage = %q{http://www.h3rald.com/glyph/}
|
90
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
91
|
+
s.require_paths = ["lib"]
|
92
|
+
s.rubygems_version = %q{1.3.5}
|
93
|
+
s.summary = %q{Glyph -- A Ruby-powered Document Authoring Framework}
|
94
|
+
s.test_files = [
|
95
|
+
"spec/macros/filters_spec.rb",
|
96
|
+
"spec/macros/macros_spec.rb",
|
97
|
+
"spec/lib/interpreter_spec.rb",
|
98
|
+
"spec/lib/commands_spec.rb",
|
99
|
+
"spec/lib/node_spec.rb",
|
100
|
+
"spec/lib/macro_spec.rb",
|
101
|
+
"spec/lib/config_spec.rb",
|
102
|
+
"spec/lib/glyph_spec.rb",
|
103
|
+
"spec/lib/document_spec.rb",
|
104
|
+
"spec/tasks/load_spec.rb",
|
105
|
+
"spec/tasks/generate_spec.rb",
|
106
|
+
"spec/tasks/project_spec.rb",
|
107
|
+
"spec/spec_helper.rb"
|
108
|
+
]
|
109
|
+
|
110
|
+
if s.respond_to? :specification_version then
|
111
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
112
|
+
s.specification_version = 3
|
113
|
+
|
114
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
115
|
+
s.add_runtime_dependency(%q<gli>, [">= 0.3.1"])
|
116
|
+
s.add_runtime_dependency(%q<extlib>, [">= 0.9.12"])
|
117
|
+
s.add_runtime_dependency(%q<treetop>, [">= 0.4.3"])
|
118
|
+
s.add_runtime_dependency(%q<rake>, [">= 0.8.7"])
|
119
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
120
|
+
s.add_development_dependency(%q<yard>, [">= 0"])
|
121
|
+
else
|
122
|
+
s.add_dependency(%q<gli>, [">= 0.3.1"])
|
123
|
+
s.add_dependency(%q<extlib>, [">= 0.9.12"])
|
124
|
+
s.add_dependency(%q<treetop>, [">= 0.4.3"])
|
125
|
+
s.add_dependency(%q<rake>, [">= 0.8.7"])
|
126
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
127
|
+
s.add_dependency(%q<yard>, [">= 0"])
|
128
|
+
end
|
129
|
+
else
|
130
|
+
s.add_dependency(%q<gli>, [">= 0.3.1"])
|
131
|
+
s.add_dependency(%q<extlib>, [">= 0.9.12"])
|
132
|
+
s.add_dependency(%q<treetop>, [">= 0.4.3"])
|
133
|
+
s.add_dependency(%q<rake>, [">= 0.8.7"])
|
134
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
135
|
+
s.add_dependency(%q<yard>, [">= 0"])
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
data/lib/glyph.rb
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
# Copyright (c) 2009-2010 Fabio Cevasco
|
2
|
+
# website: http://www.h3rald.com/glyph
|
3
|
+
# license: BSD
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'pathname'
|
7
|
+
require 'yaml'
|
8
|
+
require 'gli'
|
9
|
+
require 'extlib'
|
10
|
+
require 'treetop'
|
11
|
+
require 'rake'
|
12
|
+
|
13
|
+
# Glyph is a Rapid Document Authoring Framework able to produce structured documents effortlessly.
|
14
|
+
module Glyph
|
15
|
+
|
16
|
+
LIB = Pathname(__FILE__).dirname.expand_path/'glyph'
|
17
|
+
|
18
|
+
HOME = LIB/'../../'
|
19
|
+
|
20
|
+
require LIB/'system_extensions'
|
21
|
+
require LIB/'config'
|
22
|
+
require LIB/'node'
|
23
|
+
require LIB/'document'
|
24
|
+
require LIB/'glyph_language'
|
25
|
+
require LIB/'macro'
|
26
|
+
require LIB/'interpreter'
|
27
|
+
|
28
|
+
VERSION = file_load HOME/'VERSION'
|
29
|
+
|
30
|
+
SPEC_DIR = Pathname(__FILE__).dirname.expand_path/'../spec'
|
31
|
+
|
32
|
+
TASKS_DIR = Pathname(__FILE__).dirname.expand_path/'../tasks'
|
33
|
+
|
34
|
+
APP = Rake.application
|
35
|
+
|
36
|
+
SNIPPETS = {}
|
37
|
+
|
38
|
+
MACROS = {}
|
39
|
+
|
40
|
+
TODOS = []
|
41
|
+
|
42
|
+
ERRORS = []
|
43
|
+
|
44
|
+
# Returns true if Glyph is running in test mode
|
45
|
+
def self.testing?
|
46
|
+
const_defined? :TEST_MODE rescue false
|
47
|
+
end
|
48
|
+
|
49
|
+
PROJECT = (Glyph.testing?) ? Glyph::SPEC_DIR/"test_project" : Pathname.new(Dir.pwd)
|
50
|
+
|
51
|
+
CONFIG = Glyph::Config.new :resettable => true, :mutable => false
|
52
|
+
|
53
|
+
home_dir = Pathname.new(RUBY_PLATFORM.match(/win32|mingw/) ? ENV['HOMEPATH'] : ENV['HOME'])
|
54
|
+
SYSTEM_CONFIG = Glyph::Config.new(:file => HOME/'config.yml')
|
55
|
+
GLOBAL_CONFIG = Glyph.testing? ? Glyph::Config.new(:file => SPEC_DIR/'.glyphrc') : Glyph::Config.new(:file => home_dir/'.glyphrc')
|
56
|
+
PROJECT_CONFIG = Glyph::Config.new(:file => PROJECT/'config.yml')
|
57
|
+
|
58
|
+
# Loads all Rake tasks
|
59
|
+
def self.setup
|
60
|
+
FileList["#{TASKS_DIR}/**/*.rake"].each do |f|
|
61
|
+
load f
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Overrides a configuration setting
|
66
|
+
# @param setting [String, Symbol] the configuration setting to change
|
67
|
+
# @param value the new value
|
68
|
+
def self.config_override(setting, value)
|
69
|
+
PROJECT_CONFIG.set setting, value
|
70
|
+
reset_config
|
71
|
+
end
|
72
|
+
|
73
|
+
# Resets Glyph configuration
|
74
|
+
def self.reset_config
|
75
|
+
CONFIG.merge!(SYSTEM_CONFIG.merge(GLOBAL_CONFIG.merge(PROJECT_CONFIG)))
|
76
|
+
end
|
77
|
+
|
78
|
+
# Returns true if the PROJECT constant is set to a valid Glyph project directory
|
79
|
+
def self.project?
|
80
|
+
children = ["styles", "text", "output", "snippets.yml", "config.yml", "document.glyph"].sort
|
81
|
+
actual_children = PROJECT.children.map{|c| c.basename.to_s}.sort
|
82
|
+
(actual_children & children) == children
|
83
|
+
end
|
84
|
+
|
85
|
+
# Enables a Rake task
|
86
|
+
# @param task the task to enable
|
87
|
+
def self.enable(task)
|
88
|
+
Rake::Task[task].reenable
|
89
|
+
end
|
90
|
+
|
91
|
+
# Reenables and runs a Rake task
|
92
|
+
# @param task the task to enable
|
93
|
+
# @param *args the task arguments
|
94
|
+
def self.run!(task, *args)
|
95
|
+
Rake::Task[task].reenable
|
96
|
+
self.run task, *args
|
97
|
+
end
|
98
|
+
|
99
|
+
# Runs a Rake task
|
100
|
+
# @param task the task to enable
|
101
|
+
# @param *args the task arguments
|
102
|
+
def self.run(task, *args)
|
103
|
+
Rake::Task[task].invoke *args
|
104
|
+
end
|
105
|
+
|
106
|
+
# Defines a new macro
|
107
|
+
# @param name [Symbol, String] the name of the macro
|
108
|
+
def self.macro(name, &block)
|
109
|
+
MACROS[name] = block
|
110
|
+
end
|
111
|
+
|
112
|
+
# Defines an alias for an existing macro
|
113
|
+
# @param [Hash] pair the single-key hash defining the alias
|
114
|
+
# @example
|
115
|
+
# {:old_name => :new_name}
|
116
|
+
def self.macro_alias(pair)
|
117
|
+
name = pair.keys[0].to_sym
|
118
|
+
found = MACROS[name]
|
119
|
+
if found then
|
120
|
+
warning "Invalid alias: macro '#{name}' already exists."
|
121
|
+
return
|
122
|
+
end
|
123
|
+
MACROS[name] = MACROS[pair.values[0].to_sym]
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
Glyph.setup
|
@@ -0,0 +1,124 @@
|
|
1
|
+
include GLI
|
2
|
+
|
3
|
+
|
4
|
+
GLI.desc "Enable debugging"
|
5
|
+
switch [:d, :debug]
|
6
|
+
|
7
|
+
GLI.desc 'Create a new Glyph project'
|
8
|
+
command :init do |c|
|
9
|
+
c.action do |global_options,options,args|
|
10
|
+
Glyph.run 'project:create', Dir.pwd
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
GLI.desc 'Add a new text file to the project'
|
15
|
+
arg_name "file_name"
|
16
|
+
command :add do |c|
|
17
|
+
c.action do |global_options,options,args|
|
18
|
+
raise ArgumentError, "Please specify a file name." if args.blank?
|
19
|
+
Glyph.run 'project:add', args[0]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
GLI.desc 'Compile the project'
|
24
|
+
arg_name "[output_target]"
|
25
|
+
command :compile do |c|
|
26
|
+
c.desc "Specify a glyph file to compile (default: document.glyph)"
|
27
|
+
c.flag [:s, :source]
|
28
|
+
c.desc "Specify the format of the output file (default: html)"
|
29
|
+
c.flag [:f, :format]
|
30
|
+
c.action do |global_options, options, args|
|
31
|
+
Glyph.run 'load:config'
|
32
|
+
output_targets = Glyph::CONFIG.get('document.output_targets')
|
33
|
+
target = nil
|
34
|
+
Glyph.config_override('document.output', options[:f]) if options[:f]
|
35
|
+
target = cfg('document.output')
|
36
|
+
target = nil if target.blank?
|
37
|
+
target ||= cfg('filters.target')
|
38
|
+
Glyph.config_override('document.source', options[:s]) if options[:s]
|
39
|
+
raise ArgumentError, "Output target not specified" unless target
|
40
|
+
raise ArgumentError, "Unknown output target '#{target}'" unless output_targets.include? target.to_sym
|
41
|
+
Glyph.run "generate:#{target}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
GLI.desc 'Display all project TODO items'
|
46
|
+
command :todo do |c|
|
47
|
+
c.action do |global_options, options, args|
|
48
|
+
Glyph.run "generate:document"
|
49
|
+
unless Glyph::TODOS.blank?
|
50
|
+
info "*** TODOs: ***"
|
51
|
+
Glyph::TODOS.each do |t|
|
52
|
+
info t
|
53
|
+
end
|
54
|
+
else
|
55
|
+
info "Nothing left to do."
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
GLI.desc 'Get/set configuration settings'
|
61
|
+
arg_name "setting [new_value]"
|
62
|
+
command :config do |c|
|
63
|
+
c.desc "Save to global configuration"
|
64
|
+
c.switch [:g, :global]
|
65
|
+
c.action do |global_options,options,args|
|
66
|
+
Glyph.run 'load:config'
|
67
|
+
if options[:g] then
|
68
|
+
cfg = Glyph::GLOBAL_CONFIG
|
69
|
+
else
|
70
|
+
cfg = Glyph::PROJECT_CONFIG
|
71
|
+
end
|
72
|
+
case args.length
|
73
|
+
when 0 then
|
74
|
+
raise ArgumentError, "Too few arguments."
|
75
|
+
when 1 then # read current config
|
76
|
+
setting = cfg(args[0])
|
77
|
+
raise RuntimeError, "Unknown setting '#{args[0]}'" if setting.blank?
|
78
|
+
info Glyph::CONFIG.get(args[0])
|
79
|
+
when 2 then
|
80
|
+
cfg.set args[0], args[1]
|
81
|
+
Glyph.reset_config
|
82
|
+
else
|
83
|
+
raise ArgumentError, "Too many arguments."
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
pre do |global,command,options,args|
|
89
|
+
# Pre logic here
|
90
|
+
# Return true to proceed; false to abourt and not call the
|
91
|
+
# chosen command
|
92
|
+
if global[:d] then
|
93
|
+
Glyph::DEBUG = true
|
94
|
+
end
|
95
|
+
if !command || command.name == :help then
|
96
|
+
puts "====================================="
|
97
|
+
puts "Glyph v#{Glyph::VERSION}"
|
98
|
+
puts "====================================="
|
99
|
+
end
|
100
|
+
true
|
101
|
+
end
|
102
|
+
|
103
|
+
post do |global,command,options,args|
|
104
|
+
# Post logic here
|
105
|
+
end
|
106
|
+
|
107
|
+
on_error do |exception|
|
108
|
+
if exception.is_a? MacroError then
|
109
|
+
#warning exception.message
|
110
|
+
puts exception.message
|
111
|
+
false
|
112
|
+
else
|
113
|
+
if Glyph.const_defined? :DEBUG then
|
114
|
+
puts "Exception: #{exception.message}"
|
115
|
+
puts "Backtrace:"
|
116
|
+
exception.backtrace.each do |b|
|
117
|
+
puts b
|
118
|
+
end
|
119
|
+
end
|
120
|
+
true
|
121
|
+
end
|
122
|
+
# Error logic here
|
123
|
+
# return false to skip default error handling
|
124
|
+
end
|
data/lib/glyph/config.rb
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
module Glyph
|
2
|
+
|
3
|
+
# The Glyph::Config class is used (you don't say!) to store configuration data. Essentially it wraps a Hash of Hashes
|
4
|
+
# and provides some useful methods to access keys and subkeys.
|
5
|
+
class Config
|
6
|
+
|
7
|
+
# Initializes the configuration with a hash of options:
|
8
|
+
# * :file (default: nil) - A YAML file to read data from
|
9
|
+
# * :data (default: {})- The initial contents
|
10
|
+
# * :resettable (default: false) - Whether the configuration can be reset (cleared) or not
|
11
|
+
# * :mutable (default: true) - Whether the configuration can be changed or not
|
12
|
+
#
|
13
|
+
# @param [Hash] options the configuration options (merged with the the defaults)
|
14
|
+
def initialize(options={})
|
15
|
+
default_options = {:file => nil, :data => {}, :resettable => false, :mutable => true}
|
16
|
+
@options = default_options.merge options
|
17
|
+
@file = @options[:file]
|
18
|
+
@data = @options[:data]
|
19
|
+
read if @file
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns the underlying data hash
|
23
|
+
# @return [Hash] Configuration data
|
24
|
+
def to_hash
|
25
|
+
@data
|
26
|
+
end
|
27
|
+
|
28
|
+
# Resets all configuration data
|
29
|
+
# @param [Hash] hash the new configuration data to store
|
30
|
+
# @raise [RuntimeError] unless the configuration is resettable or if no hash is passed
|
31
|
+
# @return [Hash] Configuration data
|
32
|
+
def reset(hash={})
|
33
|
+
raise RuntimeError, "Configuration cannot be reset" unless @options[:resettable]
|
34
|
+
raise RuntimeError, "Configuration data is not stored in a Hash" unless hash.is_a? Hash
|
35
|
+
@data = hash
|
36
|
+
end
|
37
|
+
|
38
|
+
# Updates configuration data by applying Hash#update to each sub-hash of data, recursively.
|
39
|
+
# @param [Glyph::Config] cfg the configuration to update from
|
40
|
+
# @raise [ArgumentError] unless cfg is a Glyph::Config
|
41
|
+
# @return self
|
42
|
+
def update(cfg)
|
43
|
+
merge_or_update cfg, :update
|
44
|
+
end
|
45
|
+
|
46
|
+
# Merges configuration data by applying Hash#merge to each sub-hash of data, recursively.
|
47
|
+
# @param [Glyph::Config] cfg the configuration to merge with
|
48
|
+
# @raise [ArgumentError] unless cfg is a Glyph::Config
|
49
|
+
# @return [Glyph::Config] a new merged configuration
|
50
|
+
def merge(cfg)
|
51
|
+
merge_or_update cfg, :merge
|
52
|
+
end
|
53
|
+
|
54
|
+
alias merge! update
|
55
|
+
|
56
|
+
# Reads the contents of a file and stores them as configuration data
|
57
|
+
# @return [Hash] Configuration data
|
58
|
+
# @raise [RuntimeError] if self is not linked to a file or if the file does not contain a serialized Hash
|
59
|
+
def read
|
60
|
+
raise RuntimeError, "Configuration is not stored in a file." if @file.blank?
|
61
|
+
if @file.exist? then
|
62
|
+
contents = yaml_load @file
|
63
|
+
raise RuntimeError, "Invalid configuration file '#{@file}'" unless contents.is_a? Hash
|
64
|
+
@data = contents
|
65
|
+
else
|
66
|
+
@data = {}
|
67
|
+
end
|
68
|
+
@data
|
69
|
+
end
|
70
|
+
|
71
|
+
# Updates a configuration setting
|
72
|
+
# @param [String, Symbol] setting the setting to update
|
73
|
+
# @param [Object] value the value to store. Where applicable (Array, Hash, Boolean, Nil), attempts
|
74
|
+
# to evaluate string values
|
75
|
+
# @return [Object] the new value
|
76
|
+
# @raise [RuntimeError] unless the configuration is mutable
|
77
|
+
# @raise [ArgumentError] if the setting refers to an invalid namespace
|
78
|
+
# @example
|
79
|
+
# cfg = Glyph::Config.new
|
80
|
+
# cfg.set "quiet", true # Sets :quiet => true
|
81
|
+
# cfg.set "test.test_value", "[1,2,3]" # Sets :test => {:test_value => [1,2,3]}
|
82
|
+
# cfg.sef :quiet, "false" # Sets :quiet => false
|
83
|
+
def set(setting, value)
|
84
|
+
raise RuntimeError, "Configuration cannot be changed" unless @options[:mutable]
|
85
|
+
if value.is_a?(String) && value.match(/^(["'].*["']|:.+|\[.*\]|\{.*\}|true|false|nil)$/) then
|
86
|
+
value = Kernel.instance_eval value
|
87
|
+
end
|
88
|
+
hash = @data
|
89
|
+
path = setting.to_s.split(".").map{|s| s.intern}
|
90
|
+
count = 1
|
91
|
+
path.each do |s|
|
92
|
+
if hash.has_key? s then
|
93
|
+
if count == path.length then
|
94
|
+
# destination
|
95
|
+
hash[s] = value
|
96
|
+
else
|
97
|
+
if hash[s].is_a?(Hash) then
|
98
|
+
hash = hash[s]
|
99
|
+
count +=1
|
100
|
+
else
|
101
|
+
raise ArgumentError, "Invalid namespace #{s}"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
else
|
105
|
+
# key not found
|
106
|
+
if count == path.length then # destination
|
107
|
+
hash[s] = value
|
108
|
+
else
|
109
|
+
# create a new namespace
|
110
|
+
hash[s] = {}
|
111
|
+
hash = hash[s]
|
112
|
+
count +=1
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
value
|
117
|
+
end
|
118
|
+
|
119
|
+
# Returns a configuration setting
|
120
|
+
# @param [String, Symbol] setting the setting to retrieve
|
121
|
+
# @return [Object] the new value
|
122
|
+
# @see Glyph::Config#set
|
123
|
+
# @example
|
124
|
+
# cfg = Glyph::Config.new
|
125
|
+
# cfg.get :quiet # true
|
126
|
+
# cfg.get "test.test_value" # [1,2,3]
|
127
|
+
def get(setting)
|
128
|
+
@data.instance_eval "self#{setting.to_s.split(".").map{|key| "[:#{key}]" }.join}" rescue nil
|
129
|
+
end
|
130
|
+
|
131
|
+
# Serialize configuration data and writes it to a file
|
132
|
+
# @raise [RuntimeError] if the configuration is not linked to a file
|
133
|
+
def write
|
134
|
+
raise RuntimeError, "Configuration is not stored in a file." if @file.blank?
|
135
|
+
yaml_dump @file, @data
|
136
|
+
end
|
137
|
+
|
138
|
+
private
|
139
|
+
|
140
|
+
def merge_or_update(cfg, method=:merge)
|
141
|
+
raise ArgumentError, "#{cfg} is not a Glyph::Config" unless cfg.is_a? Glyph::Config
|
142
|
+
block = lambda do |key, v1, v2|
|
143
|
+
(v1.is_a?(Hash) && v2.is_a?(Hash)) ? v1.send(method, v2, &block) : v2
|
144
|
+
end
|
145
|
+
new_data = @data.send(method, cfg.to_hash, &block)
|
146
|
+
opts = @options.merge :data => new_data, :file => nil
|
147
|
+
(method == :merge) ? Config.new(opts) : self
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|