camping 2.1.532 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +72 -53
- data/Rakefile +25 -20
- data/bin/camping +1 -0
- data/book/01_introduction.md +6 -6
- data/book/02_getting_started.md +348 -267
- data/book/03_more_about_controllers.md +124 -0
- data/book/04_more_about_views.md +118 -0
- data/book/05_more_about_markaby.md +173 -0
- data/book/06_more_about_models.md +58 -0
- data/book/06_rules_of_thumb.md +143 -0
- data/book/07_philosophy.md +23 -0
- data/book/08_publishing_an_app.md +118 -0
- data/book/09_upgrade_notes.md +96 -0
- data/book/10_middleware.md +69 -0
- data/book/11_gear.md +50 -0
- data/examples/blog.rb +38 -38
- data/lib/camping/ar.rb +20 -5
- data/lib/camping/commands.rb +388 -0
- data/lib/camping/gear/filters.rb +48 -0
- data/lib/camping/gear/inspection.rb +32 -0
- data/lib/camping/gear/kuddly.rb +178 -0
- data/lib/camping/gear/nancy.rb +170 -0
- data/lib/camping/loads.rb +15 -0
- data/lib/camping/mab.rb +1 -1
- data/lib/camping/reloader.rb +22 -17
- data/lib/camping/server.rb +145 -70
- data/lib/camping/session.rb +8 -5
- data/lib/camping/template.rb +1 -2
- data/lib/camping/tools.rb +43 -0
- data/lib/camping/version.rb +6 -0
- data/lib/camping-unabridged.rb +360 -133
- data/lib/camping.rb +78 -47
- data/lib/campingtrip.md +341 -0
- data/test/app_camping_gear.rb +121 -0
- data/test/app_camping_tools.rb +1 -0
- data/test/app_config.rb +30 -0
- data/test/app_cookies.rb +1 -1
- data/test/app_file.rb +3 -3
- data/test/app_goes_meta.rb +23 -0
- data/test/app_inception.rb +39 -0
- data/test/app_markup.rb +5 -20
- data/test/app_migrations.rb +16 -0
- data/test/app_partials.rb +1 -1
- data/test/app_prefixed.rb +88 -0
- data/test/app_reloader.rb +1 -2
- data/test/app_route_generating.rb +69 -2
- data/test/app_sessions.rb +24 -2
- data/test/app_simple.rb +18 -18
- data/test/apps/migrations.rb +82 -82
- data/test/apps/misc.rb +1 -1
- data/test/gear/gear_nancy.rb +129 -0
- data/test/test_helper.rb +69 -12
- metadata +152 -92
- data/CHANGELOG +0 -145
- data/book/51_upgrading.md +0 -110
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
module Camping
|
|
2
|
+
module CommandsHelpers
|
|
3
|
+
|
|
4
|
+
# transform app_name to snake case
|
|
5
|
+
def self.to_snake_case(string)
|
|
6
|
+
string = string.to_s if string.class == Symbol
|
|
7
|
+
string.gsub(/::/, '/').
|
|
8
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
|
9
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
|
10
|
+
tr("-", "_").
|
|
11
|
+
downcase
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
RouteCollection = Struct.new(:routes)
|
|
15
|
+
class RouteCollection
|
|
16
|
+
# Displays formatted routes from a route collection
|
|
17
|
+
# Assumes that Route structs are stored in :routes.
|
|
18
|
+
def display
|
|
19
|
+
current_app, current_controller, current_method = "", "", ""
|
|
20
|
+
puts "App VERB Route"
|
|
21
|
+
routes.each { |r|
|
|
22
|
+
if current_app != r.app.to_s
|
|
23
|
+
current_app = r.app.to_s
|
|
24
|
+
puts "-----------------------------------"
|
|
25
|
+
puts r.app_header
|
|
26
|
+
end
|
|
27
|
+
if current_controller != r.controller.to_s
|
|
28
|
+
current_controller = r.controller.to_s
|
|
29
|
+
puts r.controller_header
|
|
30
|
+
end
|
|
31
|
+
puts r.padded_message true
|
|
32
|
+
}
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Route Struct, for making and formatting a route.
|
|
38
|
+
Route = Struct.new(:http_method, :controller, :app, :url)
|
|
39
|
+
class Route
|
|
40
|
+
|
|
41
|
+
def to_s
|
|
42
|
+
"#{controller}: #{http_method}: #{url} - #{replace_reg url}"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# pad the controller name to be the right length, if we can.
|
|
46
|
+
def padded_message(with_method = false)
|
|
47
|
+
"#{pad}#{(with_method ? http_method.to_s.upcase.ljust(pad.length, " ") : pad)}#{replace_reg url}"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def app_header
|
|
51
|
+
"#{app.to_s}"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def controller_header
|
|
55
|
+
"#{pad}#{app.to_s}::#{controller.to_s}"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
protected
|
|
59
|
+
|
|
60
|
+
def http_methods
|
|
61
|
+
["get", "post", "put", "patch", "delete"]
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def replace_reg(pattern = "")
|
|
65
|
+
xstr = "([^/]+)"; nstr = "(\d+)"
|
|
66
|
+
pattern = pattern.gsub(xstr, ":string").gsub("(\\d+)", ":integer") unless pattern == "/"
|
|
67
|
+
pattern
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def pad
|
|
71
|
+
" "
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
class RoutesParser
|
|
77
|
+
def self.parse(app)
|
|
78
|
+
new(app).parse
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def initialize(app = Camping)
|
|
82
|
+
@parent_app, @routes = app, []
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def parse
|
|
86
|
+
routes = @parent_app.make_camp
|
|
87
|
+
collected_routes = []
|
|
88
|
+
|
|
89
|
+
make_routes = -> (a) {
|
|
90
|
+
|
|
91
|
+
a::X.all.map {|c|
|
|
92
|
+
k = a::X.const_get(c)
|
|
93
|
+
im = k.instance_methods(false).map!(&:to_s)
|
|
94
|
+
methods = im & ["get", "post", "put", "patch", "delete"]
|
|
95
|
+
if k.respond_to?:urls
|
|
96
|
+
methods.each { |m|
|
|
97
|
+
k.urls.each { |u|
|
|
98
|
+
collected_routes.append Camping::CommandsHelpers::Route.new(m,c,a.to_s,u)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
end
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if @parent_app == Camping
|
|
106
|
+
@parent_app::Apps.each {|a|
|
|
107
|
+
make_routes.(a)
|
|
108
|
+
}
|
|
109
|
+
else
|
|
110
|
+
make_routes.(@parent_app)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
routes_collection = Camping::CommandsHelpers::RouteCollection.new(collected_routes)
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
class Generators
|
|
120
|
+
class << self
|
|
121
|
+
|
|
122
|
+
# write a file
|
|
123
|
+
def write(file, content)
|
|
124
|
+
raise "Cannot write to nil file." unless file
|
|
125
|
+
folder = File.dirname(file)
|
|
126
|
+
`mkdir -p #{folder}` unless File.exist?(folder)
|
|
127
|
+
File.open(file, 'w') { |f| f.write content }
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# read a file
|
|
131
|
+
def read(file)
|
|
132
|
+
File.read(file)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def make_camp_file(app_name="Tent")
|
|
136
|
+
write "camp.rb", <<-RUBY
|
|
137
|
+
require 'camping'
|
|
138
|
+
|
|
139
|
+
Camping.goes :#{app_name}
|
|
140
|
+
|
|
141
|
+
module #{app_name}
|
|
142
|
+
module Models
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
module Controllers
|
|
146
|
+
class Index
|
|
147
|
+
def get
|
|
148
|
+
@title = "#{app_name}"
|
|
149
|
+
render :index
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
module Helpers
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
module Views
|
|
158
|
+
|
|
159
|
+
def layout
|
|
160
|
+
html do
|
|
161
|
+
head do
|
|
162
|
+
title '#{app_name}'
|
|
163
|
+
link :rel => 'stylesheet', :type => 'text/css',
|
|
164
|
+
:href => '/styles.css', :media => 'screen'
|
|
165
|
+
end
|
|
166
|
+
body do
|
|
167
|
+
h1 '#{app_name}'
|
|
168
|
+
|
|
169
|
+
div.wrapper! do
|
|
170
|
+
self << yield
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def index
|
|
177
|
+
h2 'Let\'s go Camping'
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
RUBY
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# makes a gitignore.
|
|
188
|
+
def make_gitignore
|
|
189
|
+
write '.gitignore', <<-GIT
|
|
190
|
+
.DS_Store
|
|
191
|
+
node_modules/
|
|
192
|
+
tmp/
|
|
193
|
+
db/camping.db
|
|
194
|
+
db/camping.sqlite3
|
|
195
|
+
db/camping.sqlite
|
|
196
|
+
GIT
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def make_ruby_version
|
|
200
|
+
write '.ruby-version', <<-RUBY
|
|
201
|
+
#{RUBY_VERSION}
|
|
202
|
+
RUBY
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# writes a rakefile
|
|
206
|
+
def make_rakefile
|
|
207
|
+
write 'Rakefile', <<-TXT
|
|
208
|
+
# Rakefile
|
|
209
|
+
require 'rake'
|
|
210
|
+
require 'rake/clean'
|
|
211
|
+
require 'rake/testtask'
|
|
212
|
+
require 'tempfile'
|
|
213
|
+
require 'open3'
|
|
214
|
+
|
|
215
|
+
task :default => :test
|
|
216
|
+
task :test => 'test:all'
|
|
217
|
+
|
|
218
|
+
namespace 'test' do
|
|
219
|
+
Rake::TestTask.new('all') do |t|
|
|
220
|
+
t.libs << 'test'
|
|
221
|
+
t.test_files = FileList['test/nuts_*.rb']
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
TXT
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# write a config.kdl
|
|
228
|
+
def make_configkdl
|
|
229
|
+
write 'config.kdl', <<-KDL
|
|
230
|
+
# config.kdl
|
|
231
|
+
hostname {
|
|
232
|
+
default "localhost"
|
|
233
|
+
}
|
|
234
|
+
KDL
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
# write a Gemfile
|
|
238
|
+
def make_gemfile
|
|
239
|
+
write 'Gemfile', <<-GEM
|
|
240
|
+
# frozen_string_literal: true
|
|
241
|
+
source 'https://rubygems.org'
|
|
242
|
+
|
|
243
|
+
gem 'camping'
|
|
244
|
+
gem 'puma'
|
|
245
|
+
gem 'rake'
|
|
246
|
+
|
|
247
|
+
group :production do
|
|
248
|
+
gem 'rack-ssl-enforcer'
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
group :development do
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
group :test do
|
|
255
|
+
gem 'minitest', '~> 5.0'
|
|
256
|
+
gem 'minitest-reporters'
|
|
257
|
+
gem 'rack-test'
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
GEM
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
# write a README.md
|
|
264
|
+
def make_readme
|
|
265
|
+
write 'README.md', <<-READ
|
|
266
|
+
# Camping
|
|
267
|
+
Camping is really fun and I hope you enjoy it.
|
|
268
|
+
|
|
269
|
+
Start camping by running: `camping` in the root directory.
|
|
270
|
+
|
|
271
|
+
READ
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def make_public_folder
|
|
275
|
+
Dir.mkdir("public") unless Dir.exist?("public")
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def make_test_folder
|
|
279
|
+
Dir.mkdir("test") unless Dir.exist?("test")
|
|
280
|
+
write 'test/test_helper.rb', <<-RUBY
|
|
281
|
+
$:.unshift File.dirname(__FILE__) + '/../'
|
|
282
|
+
# shift to act like we're in the regular degular directory
|
|
283
|
+
|
|
284
|
+
begin
|
|
285
|
+
require 'rubygems'
|
|
286
|
+
rescue LoadError
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
require 'camping'
|
|
290
|
+
require 'minitest/autorun'
|
|
291
|
+
require 'minitest'
|
|
292
|
+
require 'rack/test'
|
|
293
|
+
require "minitest/reporters"
|
|
294
|
+
Minitest::Reporters.use! [Minitest::Reporters::DefaultReporter.new(:color => true)]
|
|
295
|
+
|
|
296
|
+
class TestCase < MiniTest::Test
|
|
297
|
+
include Rack::Test::Methods
|
|
298
|
+
|
|
299
|
+
def self.inherited(mod)
|
|
300
|
+
mod.app = Object.const_get(mod.to_s[/\w+/])
|
|
301
|
+
super
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
class << self
|
|
305
|
+
attr_accessor :app
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def body() last_response.body end
|
|
309
|
+
def app() self.class.app end
|
|
310
|
+
|
|
311
|
+
def assert_reverse
|
|
312
|
+
begin
|
|
313
|
+
yield
|
|
314
|
+
rescue Exception
|
|
315
|
+
else
|
|
316
|
+
assert false, "Block didn't fail"
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
def assert_body(str)
|
|
321
|
+
case str
|
|
322
|
+
when Regexp
|
|
323
|
+
assert_match(str, last_response.body.strip)
|
|
324
|
+
else
|
|
325
|
+
assert_equal(str.to_s, last_response.body.strip)
|
|
326
|
+
end
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
def assert_status(code)
|
|
330
|
+
assert_equal(code, last_response.status)
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
def test_silly; end
|
|
334
|
+
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
RUBY
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
end
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
class Commands
|
|
344
|
+
|
|
345
|
+
# A helper method to spit out Routes for an application
|
|
346
|
+
def self.routes(theApp = Camping, silent = false)
|
|
347
|
+
routes = Camping::CommandsHelpers::RoutesParser.parse theApp
|
|
348
|
+
routes.display unless silent == true
|
|
349
|
+
return routes
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
def self.new_cmd(app_name=:Camp)
|
|
353
|
+
app_name = :Camp if app_name == nil
|
|
354
|
+
app_name = app_name.to_sym if app_name.class == String
|
|
355
|
+
|
|
356
|
+
snake_app_name = Camping::CommandsHelpers.to_snake_case(app_name)
|
|
357
|
+
|
|
358
|
+
# make a directory then move there.
|
|
359
|
+
# _original_dir = Dir.pwd
|
|
360
|
+
Dir.mkdir("#{snake_app_name}") unless Dir.exist?("#{snake_app_name}")
|
|
361
|
+
Dir.chdir("#{snake_app_name}")
|
|
362
|
+
|
|
363
|
+
# generate a new camping app in a directory named after it:
|
|
364
|
+
Generators::make_camp_file(app_name)
|
|
365
|
+
Generators::make_gitignore()
|
|
366
|
+
Generators::make_rakefile()
|
|
367
|
+
Generators::make_ruby_version()
|
|
368
|
+
Generators::make_configkdl()
|
|
369
|
+
Generators::make_gemfile()
|
|
370
|
+
Generators::make_readme()
|
|
371
|
+
Generators::make_public_folder()
|
|
372
|
+
Generators::make_test_folder()
|
|
373
|
+
|
|
374
|
+
# optionally add omnibus support
|
|
375
|
+
# add src/ folder
|
|
376
|
+
# add lib/ folder
|
|
377
|
+
# add views/ folder
|
|
378
|
+
|
|
379
|
+
# optionally add a local database too, through guidebook
|
|
380
|
+
# add db/ folder
|
|
381
|
+
# add db/migrate folder
|
|
382
|
+
# add db/config.kdl
|
|
383
|
+
# append migrations stuff to Rakefile.
|
|
384
|
+
`ls`
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
end
|
|
388
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# This gear is originally from filtering_camping gem by judofyr, and techarc.
|
|
2
|
+
module Gear
|
|
3
|
+
module Filters
|
|
4
|
+
module ClassMethods
|
|
5
|
+
def filters
|
|
6
|
+
@_filters ||= {:before => [], :after => []}
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def before(actions, &blk)
|
|
10
|
+
actions = [actions] unless actions.is_a?(Array)
|
|
11
|
+
actions.each do |action|
|
|
12
|
+
filters[:before] << [action, blk]
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def after(actions, &blk)
|
|
17
|
+
actions = [actions] unless actions.is_a?(Array)
|
|
18
|
+
actions.each do |action|
|
|
19
|
+
filters[:after] << [action, blk]
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.included(mod)
|
|
25
|
+
mod.extend(ClassMethods)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.setup(app, *a, &block) end
|
|
29
|
+
|
|
30
|
+
def run_filters(type)
|
|
31
|
+
o = self.class.to_s.split("::")
|
|
32
|
+
filters = Object.const_get(o.first).filters
|
|
33
|
+
filters[type].each do |filter|
|
|
34
|
+
if (filter[0].is_a?(Symbol) && (filter[0] == o.last.to_sym || filter[0] == :all)) ||
|
|
35
|
+
(filter[0].is_a?(String) && /^#{filter[0]}\/?$/ =~ @env.REQUEST_URI)
|
|
36
|
+
self.instance_eval(&filter[1])
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def service(*a)
|
|
42
|
+
run_filters(:before)
|
|
43
|
+
super(*a)
|
|
44
|
+
run_filters(:after)
|
|
45
|
+
self
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
|
|
2
|
+
# This gear adds inspection utilities to Camping
|
|
3
|
+
module Gear
|
|
4
|
+
module Inspection
|
|
5
|
+
|
|
6
|
+
# reserved module for Camping Class Methods we add because we're the best.
|
|
7
|
+
module ClassMethods
|
|
8
|
+
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
module ControllersClassMethods
|
|
12
|
+
# All Helper helps us inspect our Controllers from outside of the app.
|
|
13
|
+
# TODO: Move to CampTools for introspection.
|
|
14
|
+
def all
|
|
15
|
+
all = []
|
|
16
|
+
constants.map { |c|
|
|
17
|
+
all << c.name if !["I", "Camper"].include? c.to_s
|
|
18
|
+
}
|
|
19
|
+
all
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def self.included(mod)
|
|
24
|
+
mod.extend(ClassMethods)
|
|
25
|
+
mod::Controllers.extend(ControllersClassMethods)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# empty setup as determined by the Camping Gear Spec API.
|
|
29
|
+
def self.setup(app, *a, &block) end
|
|
30
|
+
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# lib/camping/config
|
|
3
|
+
# load and parse settings.
|
|
4
|
+
|
|
5
|
+
begin
|
|
6
|
+
require 'kdl'
|
|
7
|
+
rescue LoadError => e
|
|
8
|
+
raise "kdl could not be loaded (is it installed?): #{e.message}"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
module Gear
|
|
12
|
+
|
|
13
|
+
# Namespace to hide all of the KDL Configure stuff.
|
|
14
|
+
module Kuddly
|
|
15
|
+
WARNINGS = []
|
|
16
|
+
|
|
17
|
+
module ClassMethods
|
|
18
|
+
def configure(app)
|
|
19
|
+
config = Gear::Kuddly.get_config()
|
|
20
|
+
config.each do |k,v|
|
|
21
|
+
app.set(k.to_sym, v)
|
|
22
|
+
end unless config == nil
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class << self
|
|
27
|
+
|
|
28
|
+
def included(mod)
|
|
29
|
+
mod.extend(ClassMethods)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# required for compliance reasons
|
|
33
|
+
def setup(app, *a, &block) end
|
|
34
|
+
|
|
35
|
+
def kdl_error_message(kdl_string="",error_message="", error=nil)
|
|
36
|
+
# parse error message to get line number and column:
|
|
37
|
+
m = error_message.match( /\((\d)+:(\d)\)/ )
|
|
38
|
+
|
|
39
|
+
if m == nil
|
|
40
|
+
warn "kdl_error_message was called on a nil error message?"
|
|
41
|
+
warn "message: #{error_message}"
|
|
42
|
+
warn "kdl_string: #{kdl_string}"
|
|
43
|
+
warn "current dir: #{Dir.pwd}"
|
|
44
|
+
warn "#{error}"
|
|
45
|
+
return
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
line = m[1].to_i
|
|
49
|
+
lines = kdl_string.split( "\n" )
|
|
50
|
+
|
|
51
|
+
em = "\n"
|
|
52
|
+
em << "#{line-4}: #{lines[line-4]}\n" if (line-4) > 0 && (line-4) < lines.count
|
|
53
|
+
em << "#{line-3}: #{lines[line-3]}\n" if (line-3) > 0 && (line-3) < lines.count
|
|
54
|
+
em << "#{line-2}: #{lines[line-2]}\n" if (line-2) > 0 && (line-2) < lines.count
|
|
55
|
+
em << "#{line-1}: #{lines[line-1]}\n" if (line-1) > 0 && (line-1) < lines.count
|
|
56
|
+
em << "#{line}: #{lines[line]}\n" if (line)
|
|
57
|
+
em << "#{line+1}: #{lines[line+1]}\n" if (line+1) > 0 && (line+1) < lines.count
|
|
58
|
+
em << "#{line+2}: #{lines[line+2]}\n" if (line+2) > 0 && (line+2) < lines.count
|
|
59
|
+
em << "#{line+3}: #{lines[line+3]}\n" if (line+3) > 0 && (line+3) < lines.count
|
|
60
|
+
em << "#{line+4}: #{lines[line+4]}\n" if (line+4) > 0 && (line+4) < lines.count
|
|
61
|
+
# em << "\n"
|
|
62
|
+
WARNINGS << em
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
# parses a kdl file into a kdl document Object.
|
|
67
|
+
# returns nil if it's false. Also assumes that the file is exists.
|
|
68
|
+
# an optional silence_warnings parameter is set to false. This is used for
|
|
69
|
+
# testing.
|
|
70
|
+
def parse_kdl(config_file = nil, silence_warnings = false)
|
|
71
|
+
begin
|
|
72
|
+
kdl_string = File.open(config_file).read
|
|
73
|
+
rescue => error # Errno::ENOENT
|
|
74
|
+
puts ""
|
|
75
|
+
puts "Error trying to read a config file: \"#{error}.\""
|
|
76
|
+
puts " Attempted to open: #{config_file}"
|
|
77
|
+
puts " Current directory: #{Dir.pwd}"
|
|
78
|
+
puts " files in directory: #{Dir.glob('*')}"
|
|
79
|
+
puts ""
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
begin
|
|
83
|
+
kdl_doc = KDL.parse_document(kdl_string)
|
|
84
|
+
rescue => error
|
|
85
|
+
warn "#{error}"
|
|
86
|
+
# parse error message to get line number and column:
|
|
87
|
+
message = Kuddly.kdl_error_message(kdl_string, error.message, error)
|
|
88
|
+
m = error.message.match( /\((\d)+:(\d)\)/ )
|
|
89
|
+
|
|
90
|
+
line, column = m[1].to_i, m[2].to_i if m.respond_to? '[]'
|
|
91
|
+
|
|
92
|
+
warn("\nError parsing config: #{config_file}, on line: #{line}, at column: #{column}.", message, "#{error.message}", uplevel: 1) unless silence_warnings
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
kdl_doc
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Maps kdl settings. Settings Example:
|
|
99
|
+
# ```
|
|
100
|
+
# database {
|
|
101
|
+
# default adapter="sqlite3" database="#{database}" host="localhost" max_connections=5 timeout=5000
|
|
102
|
+
# development
|
|
103
|
+
# test
|
|
104
|
+
# production adapter="postgres" database="kow"
|
|
105
|
+
# }
|
|
106
|
+
# ```
|
|
107
|
+
def map_kdl(kdl_doc=nil)
|
|
108
|
+
configs = {}
|
|
109
|
+
|
|
110
|
+
if kdl_doc
|
|
111
|
+
|
|
112
|
+
# We have a kdl document, so that's good.
|
|
113
|
+
# iterate through each top level node to see what kind of data we have.
|
|
114
|
+
kdl_doc.nodes.each do |d|
|
|
115
|
+
config_name = d.name.to_sym
|
|
116
|
+
configs[config_name] = {}
|
|
117
|
+
|
|
118
|
+
if d.children.length > 0
|
|
119
|
+
# we've got kids!
|
|
120
|
+
# This node will have sub nodes with properties
|
|
121
|
+
d.children.each do |en|
|
|
122
|
+
env_name = en.name.to_sym
|
|
123
|
+
# parse the settings for each environment
|
|
124
|
+
configs[config_name][env_name] = {}
|
|
125
|
+
en.properties.each do |key, value|
|
|
126
|
+
configs[config_name][env_name][key.to_sym] = value.value
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
else
|
|
130
|
+
# we've got raw data, so place it into a default hash spot.
|
|
131
|
+
vals = []
|
|
132
|
+
if d.arguments.length > 1
|
|
133
|
+
d.arguments.each { |v| vals << v.value }
|
|
134
|
+
else
|
|
135
|
+
vals = d.arguments.first.value
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
configs[config_name]['default'] = vals
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
configs
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# get_config
|
|
147
|
+
# searches for any kdl document inside of the root folder
|
|
148
|
+
# Then parses it, and merges the data based on the current environment.
|
|
149
|
+
def get_config(provided_config_file = nil)
|
|
150
|
+
|
|
151
|
+
config_file, kdl_doc, merged_configs = provided_config_file, nil, {}
|
|
152
|
+
config_file = get_root_config_file() unless provided_config_file != nil
|
|
153
|
+
|
|
154
|
+
# If the config file is just nil then we probably don't have one.
|
|
155
|
+
return nil unless config_file != nil
|
|
156
|
+
|
|
157
|
+
# parses then maps the kdl
|
|
158
|
+
configs = map_kdl(parse_kdl(config_file))
|
|
159
|
+
env = ENV['environment'] ||= "development"
|
|
160
|
+
|
|
161
|
+
configs.each do |key, setting|
|
|
162
|
+
if setting.has_key? :default && env.to_sym
|
|
163
|
+
merged_configs[key] = setting[:default].merge(setting[env.to_sym])
|
|
164
|
+
else
|
|
165
|
+
merged_configs[key] = setting['default']
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
merged_configs
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# get kdl config file
|
|
173
|
+
def get_root_config_file(search_pattern = "config.kdl")
|
|
174
|
+
Dir.glob(search_pattern).first
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|