rory 0.5.3 → 0.6.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 +4 -4
- data/lib/rory.rb +1 -4
- data/lib/rory/application.rb +41 -16
- data/lib/rory/parameter_filter.rb +64 -0
- data/lib/rory/request_parameter_logger.rb +58 -0
- data/lib/rory/version.rb +1 -1
- data/rory.gemspec +8 -6
- data/spec/fixture_app/config/application.rb +1 -0
- data/spec/fixture_app/log/test.log +0 -0
- data/spec/lib/rory/application_spec.rb +120 -47
- data/spec/lib/rory/controller_spec.rb +1 -1
- data/spec/lib/rory/parameter_filter_spec.rb +50 -0
- data/spec/lib/rory/renderer_spec.rb +11 -9
- data/spec/lib/rory/request_parameter_logger_spec.rb +95 -0
- data/spec/lib/rory_spec.rb +4 -2
- data/spec/spec_helper.rb +1 -1
- metadata +57 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 40ba6de912d0a2eff585bacee9ac6e17583bf70c
|
4
|
+
data.tar.gz: de1a192df73c293d81945d0f015173c3e338484e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 864bb31119f46b7f067df7dcb60779844b53efd383f8a40de18376054abb36263694a19b9f40fc0414fcf7ce36577a83a59d55e7f03cedf23e170309a409a2c1
|
7
|
+
data.tar.gz: 23e76ae90efc1de98ecd4cd629ca64624eccc09576156d7cc7a647de7ab07a05326890b9fea1b54304e81138e997c86c51e347a7613a4b8f00e578ca017a08a0
|
data/lib/rory.rb
CHANGED
@@ -1,11 +1,8 @@
|
|
1
1
|
ENV['RORY_ENV'] ||= ENV['RACK_ENV'] || 'development'
|
2
2
|
|
3
|
-
if ENV['RORY_STAGE']
|
4
|
-
raise "Use of 'RORY_STAGE' no longer supported. Use 'RORY_ENV' instead."
|
5
|
-
end
|
6
|
-
|
7
3
|
require 'yaml'
|
8
4
|
require 'sequel'
|
5
|
+
require 'rack/contrib'
|
9
6
|
require 'rory/application'
|
10
7
|
require 'rory/dispatcher'
|
11
8
|
require 'rory/route'
|
data/lib/rory/application.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
require 'pathname'
|
2
2
|
require 'logger'
|
3
3
|
require 'rory/route_mapper'
|
4
|
+
require 'rack/commonlogger'
|
5
|
+
require_relative 'request_parameter_logger'
|
6
|
+
|
4
7
|
|
5
8
|
module Rory
|
6
9
|
# Main application superclass. Applications should subclass this class,
|
@@ -17,9 +20,9 @@ module Rory
|
|
17
20
|
private :new
|
18
21
|
attr_reader :root
|
19
22
|
|
20
|
-
def inherited(
|
23
|
+
def inherited(subclass)
|
21
24
|
super
|
22
|
-
Rory.application =
|
25
|
+
Rory.application = subclass.instance
|
23
26
|
end
|
24
27
|
|
25
28
|
def method_missing(*args, &block)
|
@@ -59,9 +62,11 @@ module Rory
|
|
59
62
|
end
|
60
63
|
|
61
64
|
def config_path
|
62
|
-
@config_path ||=
|
63
|
-
|
64
|
-
|
65
|
+
@config_path ||= root_path.join('config')
|
66
|
+
end
|
67
|
+
|
68
|
+
def log_path
|
69
|
+
@log_path ||= root_path.join('log')
|
65
70
|
end
|
66
71
|
|
67
72
|
def set_routes(&block)
|
@@ -96,6 +101,7 @@ module Rory
|
|
96
101
|
end
|
97
102
|
|
98
103
|
def use_middleware(*args, &block)
|
104
|
+
@stack = nil
|
99
105
|
middleware << [args, block]
|
100
106
|
end
|
101
107
|
|
@@ -107,25 +113,44 @@ module Rory
|
|
107
113
|
Rory::Dispatcher.rack_app(self)
|
108
114
|
end
|
109
115
|
|
110
|
-
def
|
111
|
-
|
112
|
-
|
113
|
-
|
116
|
+
def request_logging_on?
|
117
|
+
@request_logging != false
|
118
|
+
end
|
119
|
+
|
120
|
+
def turn_off_request_logging!
|
121
|
+
@stack = nil
|
122
|
+
@request_logging = false
|
123
|
+
end
|
124
|
+
|
125
|
+
def use_default_middleware
|
126
|
+
if request_logging_on?
|
127
|
+
use_middleware Rack::PostBodyContentTypeParser
|
128
|
+
use_middleware Rack::CommonLogger, logger
|
129
|
+
use_middleware Rory::RequestParameterLogger, logger
|
114
130
|
end
|
115
|
-
|
116
|
-
|
131
|
+
end
|
132
|
+
|
133
|
+
def stack
|
134
|
+
@stack ||= Rack::Builder.new.tap { |builder|
|
135
|
+
use_default_middleware
|
136
|
+
middleware.each do |args, block|
|
137
|
+
builder.use *args, &block
|
138
|
+
end
|
139
|
+
builder.run dispatcher
|
140
|
+
}
|
117
141
|
end
|
118
142
|
|
119
143
|
def call(env)
|
120
144
|
stack.call(env)
|
121
145
|
end
|
122
146
|
|
147
|
+
def log_file
|
148
|
+
Dir.mkdir(log_path) unless File.exists?(log_path)
|
149
|
+
File.open(log_path.join("#{ENV['RORY_ENV']}.log"), 'a').tap { |file| file.sync = true }
|
150
|
+
end
|
151
|
+
|
123
152
|
def logger
|
124
|
-
@logger ||=
|
125
|
-
Dir.mkdir('log') unless File.exists?('log')
|
126
|
-
file = File.open(File.join('log', "#{ENV['RORY_ENV']}.log"), 'a')
|
127
|
-
Logger.new(file)
|
128
|
-
end
|
153
|
+
@logger ||= Logger.new(log_file)
|
129
154
|
end
|
130
155
|
end
|
131
156
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Rory
|
2
|
+
class ParameterFilter
|
3
|
+
FILTERED = '[FILTERED]'.freeze
|
4
|
+
|
5
|
+
def initialize(filters = [])
|
6
|
+
@filters = filters
|
7
|
+
end
|
8
|
+
|
9
|
+
def filter(params)
|
10
|
+
compiled_filter.call(params)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def compiled_filter
|
16
|
+
@compiled_filter ||= CompiledFilter.compile(@filters)
|
17
|
+
end
|
18
|
+
|
19
|
+
class CompiledFilter
|
20
|
+
def self.compile(filters)
|
21
|
+
return lambda { |params| params.dup } if filters.empty?
|
22
|
+
|
23
|
+
strings, regexps, blocks = [], [], []
|
24
|
+
|
25
|
+
filters.each do |item|
|
26
|
+
case item
|
27
|
+
when Regexp
|
28
|
+
regexps << item
|
29
|
+
else
|
30
|
+
strings << item.to_s
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
regexps << Regexp.new(strings.join('|'), true) unless strings.empty?
|
35
|
+
new regexps, blocks
|
36
|
+
end
|
37
|
+
|
38
|
+
attr_reader :regexps, :blocks
|
39
|
+
|
40
|
+
def initialize(regexps, blocks)
|
41
|
+
@regexps = regexps
|
42
|
+
@blocks = blocks
|
43
|
+
end
|
44
|
+
|
45
|
+
def call(original_params)
|
46
|
+
filtered_params = {}
|
47
|
+
|
48
|
+
original_params.each do |key, value|
|
49
|
+
if regexps.any? { |r| key =~ r }
|
50
|
+
value = FILTERED
|
51
|
+
elsif value.is_a?(Hash)
|
52
|
+
value = call(value)
|
53
|
+
elsif value.is_a?(Array)
|
54
|
+
value = value.map { |v| v.is_a?(Hash) ? call(v) : v }
|
55
|
+
end
|
56
|
+
|
57
|
+
filtered_params[key] = value
|
58
|
+
end
|
59
|
+
|
60
|
+
filtered_params
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require_relative 'parameter_filter'
|
2
|
+
|
3
|
+
module Rory
|
4
|
+
class RequestParameterLogger
|
5
|
+
|
6
|
+
def initialize(app, logger=nil, filters=[:password])
|
7
|
+
@app = app
|
8
|
+
@logger = logger
|
9
|
+
@filters = filters
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
@env = env
|
14
|
+
@env['rack.input'].rewind
|
15
|
+
log_request
|
16
|
+
@app.call(@env)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def log_request
|
22
|
+
log_message(request_signature)
|
23
|
+
log_message("Parameters: #{filtered_params}")
|
24
|
+
end
|
25
|
+
|
26
|
+
def logger
|
27
|
+
@logger || @env['rack.errors']
|
28
|
+
end
|
29
|
+
|
30
|
+
def log_message(message)
|
31
|
+
if logger.respond_to?(:write)
|
32
|
+
logger.write(message + "\n")
|
33
|
+
else
|
34
|
+
logger.info(message)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def parameter_filter
|
39
|
+
Rory::ParameterFilter.new(@filters)
|
40
|
+
end
|
41
|
+
|
42
|
+
def filtered_params
|
43
|
+
parameter_filter.filter(unfiltered_params)
|
44
|
+
end
|
45
|
+
|
46
|
+
def request
|
47
|
+
Rack::Request.new(@env)
|
48
|
+
end
|
49
|
+
|
50
|
+
def unfiltered_params
|
51
|
+
request.params
|
52
|
+
end
|
53
|
+
|
54
|
+
def request_signature
|
55
|
+
%{Started #{@env['REQUEST_METHOD']} "#{@env['PATH_INFO']}" for #{@env['REMOTE_ADDR']} at #{Time.now}}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/rory/version.rb
CHANGED
data/rory.gemspec
CHANGED
@@ -28,16 +28,18 @@ EOF
|
|
28
28
|
s.licenses = ["MIT"]
|
29
29
|
s.require_paths = ["lib"]
|
30
30
|
|
31
|
-
s.add_runtime_dependency 'rack', '
|
31
|
+
s.add_runtime_dependency 'rack', '~> 1.0'
|
32
|
+
s.add_runtime_dependency 'rack-contrib', '~> 1.2'
|
32
33
|
s.add_runtime_dependency 'sequel', '~> 4.0'
|
33
34
|
s.add_runtime_dependency 'thin', '~> 1.0'
|
34
35
|
|
35
|
-
s.add_development_dependency 'rake'
|
36
|
+
s.add_development_dependency 'rake', '~> 10.4'
|
36
37
|
s.add_development_dependency 'rspec', '~> 3'
|
37
|
-
s.add_development_dependency 'capybara'
|
38
|
-
s.add_development_dependency 'yard'
|
39
|
-
s.add_development_dependency 'reek'
|
40
|
-
s.add_development_dependency 'simplecov'
|
38
|
+
s.add_development_dependency 'capybara', '~> 2.4'
|
39
|
+
s.add_development_dependency 'yard', '~> 0.8'
|
40
|
+
s.add_development_dependency 'reek', '~> 2.2'
|
41
|
+
s.add_development_dependency 'simplecov', '~> 0.10'
|
41
42
|
s.add_development_dependency 'bundler', '~> 1.0'
|
43
|
+
s.add_development_dependency 'pry', '~> 0.10'
|
42
44
|
end
|
43
45
|
|
File without changes
|
@@ -1,16 +1,23 @@
|
|
1
1
|
describe Rory::Application do
|
2
|
+
let(:subject) {
|
3
|
+
Class.new(Rory::Application).tap { |app|
|
4
|
+
app.root = "whatever"
|
5
|
+
app.turn_off_request_logging!
|
6
|
+
}
|
7
|
+
}
|
8
|
+
|
2
9
|
describe ".configure" do
|
3
10
|
it 'yields the given block to self' do
|
4
|
-
|
5
|
-
expect(c).to eq(
|
11
|
+
subject.configure do |c|
|
12
|
+
expect(c).to eq(subject.instance)
|
6
13
|
end
|
7
14
|
end
|
8
15
|
end
|
9
16
|
|
10
17
|
describe '.config_path' do
|
11
18
|
it 'is set to {root}/config by default' do
|
12
|
-
expect(
|
13
|
-
Pathname.new(
|
19
|
+
expect(subject.config_path).to eq(
|
20
|
+
Pathname.new(subject.root).join('config')
|
14
21
|
)
|
15
22
|
end
|
16
23
|
|
@@ -20,64 +27,112 @@ describe Rory::Application do
|
|
20
27
|
expect {
|
21
28
|
RootlessApp.config_path
|
22
29
|
}.to raise_error(RootlessApp::RootNotConfigured)
|
23
|
-
Rory.application =
|
30
|
+
Rory.application = subject.instance
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '.log_path' do
|
35
|
+
it 'is set to {root}/config by default' do
|
36
|
+
expect(subject.log_path).to eq(
|
37
|
+
Pathname.new(subject.root).join('log')
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'raises exception if root not set' do
|
42
|
+
Rory.application = nil
|
43
|
+
class RootlessApp < Rory::Application; end
|
44
|
+
expect {
|
45
|
+
RootlessApp.config_path
|
46
|
+
}.to raise_error(RootlessApp::RootNotConfigured)
|
47
|
+
Rory.application = subject.instance
|
24
48
|
end
|
25
49
|
end
|
26
50
|
|
27
51
|
describe ".respond_to?" do
|
28
52
|
it 'returns true if the instance said so' do
|
29
|
-
expect(
|
30
|
-
expect(
|
53
|
+
expect(subject.instance).to receive(:respond_to?).with(:goat).and_return(true)
|
54
|
+
expect(subject.respond_to?(:goat)).to be_truthy
|
31
55
|
end
|
32
56
|
|
33
57
|
it 'does the usual thing if instance says no' do
|
34
|
-
expect(
|
35
|
-
expect(
|
36
|
-
expect(
|
58
|
+
expect(subject.instance).to receive(:respond_to?).twice.and_return(false)
|
59
|
+
expect(subject.respond_to?(:to_s)).to be_truthy
|
60
|
+
expect(subject.respond_to?(:obviously_not_a_real_method)).to be_falsey
|
37
61
|
end
|
38
62
|
end
|
39
63
|
|
40
64
|
describe ".call" do
|
41
65
|
it "forwards arg to new dispatcher, and calls dispatch" do
|
42
66
|
dispatcher = double(:dispatch => :expected)
|
43
|
-
rack_request = double
|
44
|
-
|
45
|
-
|
46
|
-
expect(
|
67
|
+
rack_request = double(:media_type => 'application/json')
|
68
|
+
env = { "rack.input" => double(:read => {}) }
|
69
|
+
allow(Rack::Request).to receive(:new).with(env).and_return(rack_request)
|
70
|
+
expect(Rory::Dispatcher).to receive(:new).with(rack_request, subject.instance).and_return(dispatcher)
|
71
|
+
expect(subject.call(env)).to eq(:expected)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe ".log_file" do
|
76
|
+
it "creates the log file directory if it does not exist" do
|
77
|
+
file = double(:sync= => true)
|
78
|
+
allow(File).to receive(:exists?).and_return(false)
|
79
|
+
allow(Dir).to receive(:mkdir).and_return(true)
|
80
|
+
allow(File).to receive(:open).and_return(file)
|
81
|
+
expect(subject.log_file).to eq(file)
|
82
|
+
end
|
83
|
+
|
84
|
+
it "returns the file and does not create the log file directory if it does not exist" do
|
85
|
+
file = double(:sync= => true)
|
86
|
+
allow(File).to receive(:exists?).and_return(true)
|
87
|
+
allow(File).to receive(:open).and_return(file)
|
88
|
+
expect(subject.log_file).to eq(file)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe ".logger" do
|
93
|
+
it "reutrns a logger" do
|
94
|
+
logger = double
|
95
|
+
allow_any_instance_of(subject).to receive(:log_file)
|
96
|
+
allow(Logger).to receive(:new).and_return(logger)
|
97
|
+
expect(subject.logger).to eq(logger)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe ".use_default_middleware" do
|
102
|
+
it "adds middleware when request logging is on" do
|
103
|
+
allow(subject.instance).to receive(:request_logging_on?).and_return(true)
|
104
|
+
allow(subject.instance).to receive(:logger).and_return(:the_logger)
|
105
|
+
subject.use_default_middleware
|
106
|
+
expect(subject.middleware.count).to_not eq(0)
|
107
|
+
end
|
108
|
+
|
109
|
+
it "does not add middleware when request logging is off" do
|
110
|
+
allow(subject.instance).to receive(:request_logging_on?).and_return(false)
|
111
|
+
allow(subject.instance).to receive(:logger).and_return(:the_logger)
|
112
|
+
subject.use_default_middleware
|
113
|
+
expect(subject.middleware.count).to eq(0)
|
47
114
|
end
|
48
115
|
end
|
49
116
|
|
50
117
|
describe ".load_config_data" do
|
51
118
|
it "returns parsed yaml file with given name from directory at config_path" do
|
52
|
-
allow_any_instance_of(
|
119
|
+
allow_any_instance_of(subject).to receive(:config_path).and_return('Africa the Great')
|
53
120
|
allow(YAML).to receive(:load_file).with(
|
54
121
|
File.expand_path(File.join('Africa the Great', 'foo_type.yml'))).
|
55
122
|
and_return(:oscar_the_grouch_takes_a_nap)
|
56
|
-
expect(
|
123
|
+
expect(subject.load_config_data(:foo_type)).to eq(:oscar_the_grouch_takes_a_nap)
|
57
124
|
end
|
58
125
|
end
|
59
126
|
|
60
127
|
describe ".connect_db" do
|
61
128
|
it "sets up sequel connection to DB from YAML file" do
|
62
129
|
config = { 'development' => :expected }
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
describe ".routes" do
|
70
|
-
it "generates a collection of routing objects from route configuration" do
|
71
|
-
expect(Fixture::Application.routes).to eq [
|
72
|
-
Rory::Route.new('foo/:id/bar', :to => 'foo#bar', :methods => [:get, :post]),
|
73
|
-
Rory::Route.new('this/:path/is/:very_awesome', :to => 'awesome#rad'),
|
74
|
-
Rory::Route.new('lumpies/:lump', :to => 'lumpies#show', :methods => [:get], :module => 'goose'),
|
75
|
-
Rory::Route.new('rabbits/:chew', :to => 'rabbits#chew', :methods => [:get], :module => 'goose/wombat'),
|
76
|
-
Rory::Route.new('', :to => 'root#vegetable', :methods => [:get]),
|
77
|
-
Rory::Route.new('', :to => 'root#no_vegetable', :methods => [:delete]),
|
78
|
-
Rory::Route.new('for_reals/switching', :to => 'for_reals#switching', :methods => [:get]),
|
79
|
-
Rory::Route.new('for_reals/:parbles', :to => 'for_reals#srsly', :methods => [:get])
|
80
|
-
]
|
130
|
+
logger_array = []
|
131
|
+
allow(subject.instance).to receive(:logger).and_return(:the_logger)
|
132
|
+
allow(subject.instance).to receive(:load_config_data).with(:database).and_return(config)
|
133
|
+
expect(Sequel).to receive(:connect).with(:expected).and_return(double(:loggers => logger_array))
|
134
|
+
subject.connect_db('development')
|
135
|
+
expect(logger_array).to match_array([:the_logger])
|
81
136
|
end
|
82
137
|
end
|
83
138
|
|
@@ -90,43 +145,61 @@ describe Rory::Application do
|
|
90
145
|
|
91
146
|
describe '.auto_require_paths' do
|
92
147
|
after(:each) do
|
93
|
-
|
148
|
+
subject.instance.instance_variable_set(:@auto_require_paths, nil)
|
94
149
|
end
|
95
150
|
|
96
151
|
it 'includes models, controllers, and helpers by default' do
|
97
|
-
expect(
|
152
|
+
expect(subject.auto_require_paths).to eq(['models', 'controllers', 'helpers'])
|
98
153
|
end
|
99
154
|
|
100
155
|
it 'accepts new paths' do
|
101
|
-
|
102
|
-
expect(
|
156
|
+
subject.auto_require_paths << 'chocolates'
|
157
|
+
expect(subject.auto_require_paths).to eq(['models', 'controllers', 'helpers', 'chocolates'])
|
103
158
|
end
|
104
159
|
end
|
105
160
|
|
106
161
|
describe '.require_all_files' do
|
107
162
|
it 'requires all files in auto_require_paths' do
|
108
|
-
allow_any_instance_of(
|
163
|
+
allow_any_instance_of(subject).to receive(:auto_require_paths).and_return(['goats', 'rhubarbs'])
|
109
164
|
[:goats, :rhubarbs].each do |folder|
|
110
165
|
expect(Rory::Support).to receive(:require_all_files_in_directory).
|
111
|
-
with(Pathname.new(
|
166
|
+
with(Pathname.new(subject.root).join("#{folder}"))
|
112
167
|
end
|
113
|
-
|
168
|
+
subject.require_all_files
|
114
169
|
end
|
115
170
|
end
|
116
171
|
|
117
172
|
describe '.use_middleware' do
|
118
173
|
it 'adds the given middleware to the stack, retaining args and block' do
|
119
|
-
|
120
|
-
|
174
|
+
require_relative '../../fixture_app/lib/dummy_middleware'
|
175
|
+
subject.use_middleware DummyMiddleware, :puppy do |dm|
|
121
176
|
dm.prefix = 'a salubrious'
|
122
177
|
end
|
123
178
|
|
124
|
-
expect(
|
179
|
+
expect(subject.instance).to receive(:dispatcher).
|
125
180
|
and_return(dispatch_stack_mock = double)
|
126
181
|
expect(dispatch_stack_mock).to receive(:call).
|
127
182
|
with('a salubrious puppy')
|
128
|
-
|
129
|
-
|
183
|
+
subject.call({})
|
184
|
+
subject.middleware.clear
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
context "with fixture application" do
|
189
|
+
subject { Fixture::Application }
|
190
|
+
describe ".routes" do
|
191
|
+
it "generates a collection of routing objects from route configuration" do
|
192
|
+
expect(subject.routes).to eq [
|
193
|
+
Rory::Route.new('foo/:id/bar', :to => 'foo#bar', :methods => [:get, :post]),
|
194
|
+
Rory::Route.new('this/:path/is/:very_awesome', :to => 'awesome#rad'),
|
195
|
+
Rory::Route.new('lumpies/:lump', :to => 'lumpies#show', :methods => [:get], :module => 'goose'),
|
196
|
+
Rory::Route.new('rabbits/:chew', :to => 'rabbits#chew', :methods => [:get], :module => 'goose/wombat'),
|
197
|
+
Rory::Route.new('', :to => 'root#vegetable', :methods => [:get]),
|
198
|
+
Rory::Route.new('', :to => 'root#no_vegetable', :methods => [:delete]),
|
199
|
+
Rory::Route.new('for_reals/switching', :to => 'for_reals#switching', :methods => [:get]),
|
200
|
+
Rory::Route.new('for_reals/:parbles', :to => 'for_reals#srsly', :methods => [:get])
|
201
|
+
]
|
202
|
+
end
|
130
203
|
end
|
131
204
|
end
|
132
|
-
end
|
205
|
+
end
|
@@ -215,7 +215,7 @@ describe Rory::Controller do
|
|
215
215
|
|
216
216
|
describe "#generate_body_from_template" do
|
217
217
|
it "returns rendered template with given name" do
|
218
|
-
expect(subject.generate_body_from_template('test/letsgo')).to eq("Let's go content")
|
218
|
+
expect(subject.generate_body_from_template('test/letsgo', :app => Fixture::Application)).to eq("Let's go content")
|
219
219
|
end
|
220
220
|
|
221
221
|
it "returns renderer output" do
|
@@ -0,0 +1,50 @@
|
|
1
|
+
describe Rory::ParameterFilter do
|
2
|
+
|
3
|
+
describe '#initialize' do
|
4
|
+
it 'sets the filters' do
|
5
|
+
expect(subject.instance_variable_get(:@filters)).to eq []
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '#filter' do
|
10
|
+
it 'returns params unchanged' do
|
11
|
+
unfiltered_params = {"address"=>"11802 MCDONALD ST, Los Angeles, CA 90230",
|
12
|
+
"owners"=>[{"first_name"=>"GOLD", "last_name"=>"PATH", "ssn"=>"000-02-9999"}],
|
13
|
+
"overrides"=>{"ofac_7403"=>"clear"}}
|
14
|
+
|
15
|
+
expect(subject.filter(unfiltered_params)).to eq unfiltered_params
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'returns params filtered by' do
|
19
|
+
subject = described_class.new([:ssn])
|
20
|
+
unfiltered_params = {"address"=>"11802 MCDONALD ST, Los Angeles, CA 90230",
|
21
|
+
"owners"=>[{"first_name"=>"GOLD", "last_name"=>"PATH", "ssn"=>"000-02-9999"}],
|
22
|
+
"overrides"=>{"ofac_7403"=>"clear"}}
|
23
|
+
|
24
|
+
filtered_params = {"address"=>"11802 MCDONALD ST, Los Angeles, CA 90230",
|
25
|
+
"owners"=>[{"first_name"=>"GOLD", "last_name"=>"PATH", "ssn"=>"[FILTERED]"}],
|
26
|
+
"overrides"=>{"ofac_7403"=>"clear"}}
|
27
|
+
|
28
|
+
|
29
|
+
expect(subject.filter(unfiltered_params)).to eq filtered_params
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'filters based upon regex' do
|
33
|
+
|
34
|
+
filter_words = []
|
35
|
+
filter_words << /ofac*/
|
36
|
+
|
37
|
+
subject = described_class.new(filter_words)
|
38
|
+
|
39
|
+
unfiltered_params = {:address=>"11802 MCDONALD ST, Los Angeles, CA 90230",
|
40
|
+
"owners"=>[{"first_name"=>"GOLD", "last_name"=>"PATH", "ssn"=>"000-02-9999"}],
|
41
|
+
"overrides"=>{"ofac_7403"=>"clear"}}
|
42
|
+
|
43
|
+
filtered_params = {:address=>"11802 MCDONALD ST, Los Angeles, CA 90230",
|
44
|
+
"owners"=>[{"first_name"=>"GOLD", "last_name"=>"PATH", "ssn"=>"000-02-9999"}],
|
45
|
+
"overrides"=>{"ofac_7403"=>"[FILTERED]"}}
|
46
|
+
|
47
|
+
expect(subject.filter(unfiltered_params)).to eq filtered_params
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -1,34 +1,36 @@
|
|
1
|
-
describe Rory::Renderer do
|
1
|
+
describe Rory::Renderer do
|
2
2
|
describe "#render" do
|
3
|
+
let(:app) { Fixture::Application }
|
4
|
+
|
3
5
|
it "returns text of template" do
|
4
|
-
renderer = Rory::Renderer.new('test/static')
|
6
|
+
renderer = Rory::Renderer.new('test/static', :app => app)
|
5
7
|
expect(renderer.render).to eq('Static content')
|
6
8
|
end
|
7
9
|
|
8
10
|
it "returns text of template in given layout" do
|
9
|
-
controller = Rory::Renderer.new('test/static', :layout => 'surround')
|
11
|
+
controller = Rory::Renderer.new('test/static', :layout => 'surround', :app => app)
|
10
12
|
expect(controller.render).to eq('Surrounding Static content is fun')
|
11
13
|
end
|
12
14
|
|
13
15
|
it "handles symbolized layout name" do
|
14
|
-
controller = Rory::Renderer.new('test/static', :layout => :surround)
|
16
|
+
controller = Rory::Renderer.new('test/static', :layout => :surround, :app => app)
|
15
17
|
expect(controller.render).to eq('Surrounding Static content is fun')
|
16
18
|
end
|
17
19
|
|
18
20
|
it "exposes locals to template" do
|
19
|
-
controller = Rory::Renderer.new('test/dynamic', :locals => { :word => 'hockey' })
|
21
|
+
controller = Rory::Renderer.new('test/dynamic', :locals => { :word => 'hockey' }, :app => app)
|
20
22
|
expect(controller.render).to eq('Word: hockey')
|
21
23
|
end
|
22
24
|
|
23
25
|
it "can render nested templates" do
|
24
|
-
controller = Rory::Renderer.new('test/double_nested', :locals => { :word => 'hockey' })
|
26
|
+
controller = Rory::Renderer.new('test/double_nested', :locals => { :word => 'hockey' }, :app => app)
|
25
27
|
expect(controller.render).to eq(
|
26
28
|
"Don't Say A Bad Word: Poop!"
|
27
29
|
)
|
28
30
|
end
|
29
31
|
|
30
32
|
it "exposes base_path to template" do
|
31
|
-
controller = Rory::Renderer.new('test/a_link', :base_path => 'spoo')
|
33
|
+
controller = Rory::Renderer.new('test/a_link', :base_path => 'spoo', :app => app)
|
32
34
|
expect(controller.render).to eq('You came from spoo.')
|
33
35
|
end
|
34
36
|
end
|
@@ -41,8 +43,8 @@ describe Rory::Renderer do
|
|
41
43
|
end
|
42
44
|
|
43
45
|
it 'uses Rory.root if no app specified' do
|
44
|
-
renderer = Rory::Renderer.new('goose')
|
45
|
-
expect(renderer.view_path).to eq(File.join(
|
46
|
+
renderer = Rory::Renderer.new('goose', :app => double(:root => "horse"))
|
47
|
+
expect(renderer.view_path).to eq(File.expand_path(File.join('views', 'goose.html.erb'), "horse"))
|
46
48
|
end
|
47
49
|
end
|
48
50
|
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
describe Rory::RequestParameterLogger do
|
2
|
+
|
3
|
+
let(:logger) { double(:write) }
|
4
|
+
let(:app) { double(:call) }
|
5
|
+
subject { described_class.new(app, logger, :filters) }
|
6
|
+
|
7
|
+
describe '#initialize' do
|
8
|
+
it 'returns a new RequestParameterLogger' do
|
9
|
+
expect(subject).to be_an_instance_of(Rory::RequestParameterLogger)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'returns a new RequestParameterLogger with parameters' do
|
13
|
+
expect(subject.instance_variable_get(:@app)).to eq(app)
|
14
|
+
expect(subject.instance_variable_get(:@logger)).to eq(logger)
|
15
|
+
expect(subject.instance_variable_get(:@filters)).to eq(:filters)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#log_request' do
|
20
|
+
|
21
|
+
context 'when logger responds to write' do
|
22
|
+
it 'writes the request to the logger' do
|
23
|
+
allow(subject).to receive(:request_signature).and_return('request_signature')
|
24
|
+
allow(subject).to receive(:filtered_params).and_return('filtered_params')
|
25
|
+
expect(logger).to receive(:write).exactly(2).times
|
26
|
+
subject.send(:log_request)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when logger does not respond to write' do
|
31
|
+
let(:logger) { double(:info) }
|
32
|
+
it 'writes the request to the logger' do
|
33
|
+
allow(subject).to receive(:request_signature).and_return('request_signature')
|
34
|
+
allow(subject).to receive(:filtered_params).and_return('filtered_params')
|
35
|
+
expect(logger).to receive(:info).exactly(2).times
|
36
|
+
subject.send(:log_request)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '#logger' do
|
42
|
+
it 'returns @logger' do
|
43
|
+
expect(subject.send(:logger)).to eq(logger)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'returns rack.errors ' do
|
47
|
+
subject = described_class.new(:app)
|
48
|
+
subject.instance_variable_set(:@env, {'rack.errors' => 'cocoa'})
|
49
|
+
expect(subject.send(:logger)).to eq('cocoa')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '#filtered_params' do
|
54
|
+
it 'filters the params' do
|
55
|
+
expect(Rory::ParameterFilter).to receive(:new).and_return(double(:filter => nil))
|
56
|
+
expect(subject).to receive(:unfiltered_params)
|
57
|
+
subject.send(:filtered_params)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '#unfiltered_params' do
|
62
|
+
it 'returns unfiltered params' do
|
63
|
+
expect(Rack::Request).to receive(:new).and_return(double(:params => nil))
|
64
|
+
subject.send(:unfiltered_params)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe '#request_signature' do
|
69
|
+
it 'returns a request signature formatted string' do
|
70
|
+
env = {
|
71
|
+
'REQUEST_METHOD' => "POST",
|
72
|
+
'PATH_INFO' => "/mushy_mushy",
|
73
|
+
'REMOTE_ADDR' => "127.0.0.1"
|
74
|
+
}
|
75
|
+
|
76
|
+
allow(Time).to receive(:now).and_return("2015-06-08 15:16:42 -0700")
|
77
|
+
subject.instance_variable_set(:@env, env)
|
78
|
+
expect(subject.send(:request_signature)).to eq('Started POST "/mushy_mushy" for 127.0.0.1 at 2015-06-08 15:16:42 -0700')
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
describe '#call' do
|
84
|
+
it 'writes the request and parameters to the log file' do
|
85
|
+
env = {
|
86
|
+
'rack.input' => double(:rewind => nil)
|
87
|
+
}
|
88
|
+
expect(app).to receive(:call).with(env)
|
89
|
+
expect(subject).to receive(:log_request)
|
90
|
+
|
91
|
+
subject.call(env)
|
92
|
+
expect(subject.instance_variable_get(:@env)).to eq(env)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
data/spec/lib/rory_spec.rb
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
describe Rory do
|
2
|
+
let!(:new_app) { Class.new(Rory::Application) }
|
3
|
+
|
2
4
|
describe '.application' do
|
3
5
|
it 'is by default set to the Rory::Application instance' do
|
4
|
-
expect(Rory.application).to eq(
|
6
|
+
expect(Rory.application).to eq(new_app.instance)
|
5
7
|
end
|
6
8
|
end
|
7
9
|
|
8
10
|
describe '.root' do
|
9
11
|
it 'returns root of application' do
|
10
|
-
expect(Rory.root).to eq(
|
12
|
+
expect(Rory.root).to eq(new_app.root)
|
11
13
|
end
|
12
14
|
end
|
13
15
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,29 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rory
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ravi Gadad
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-06-
|
11
|
+
date: 2015-06-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '1.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rack-contrib
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.2'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.2'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: sequel
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -56,16 +70,16 @@ dependencies:
|
|
56
70
|
name: rake
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
58
72
|
requirements:
|
59
|
-
- - "
|
73
|
+
- - "~>"
|
60
74
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
75
|
+
version: '10.4'
|
62
76
|
type: :development
|
63
77
|
prerelease: false
|
64
78
|
version_requirements: !ruby/object:Gem::Requirement
|
65
79
|
requirements:
|
66
|
-
- - "
|
80
|
+
- - "~>"
|
67
81
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
82
|
+
version: '10.4'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: rspec
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -84,58 +98,58 @@ dependencies:
|
|
84
98
|
name: capybara
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
86
100
|
requirements:
|
87
|
-
- - "
|
101
|
+
- - "~>"
|
88
102
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
103
|
+
version: '2.4'
|
90
104
|
type: :development
|
91
105
|
prerelease: false
|
92
106
|
version_requirements: !ruby/object:Gem::Requirement
|
93
107
|
requirements:
|
94
|
-
- - "
|
108
|
+
- - "~>"
|
95
109
|
- !ruby/object:Gem::Version
|
96
|
-
version: '
|
110
|
+
version: '2.4'
|
97
111
|
- !ruby/object:Gem::Dependency
|
98
112
|
name: yard
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
100
114
|
requirements:
|
101
|
-
- - "
|
115
|
+
- - "~>"
|
102
116
|
- !ruby/object:Gem::Version
|
103
|
-
version: '0'
|
117
|
+
version: '0.8'
|
104
118
|
type: :development
|
105
119
|
prerelease: false
|
106
120
|
version_requirements: !ruby/object:Gem::Requirement
|
107
121
|
requirements:
|
108
|
-
- - "
|
122
|
+
- - "~>"
|
109
123
|
- !ruby/object:Gem::Version
|
110
|
-
version: '0'
|
124
|
+
version: '0.8'
|
111
125
|
- !ruby/object:Gem::Dependency
|
112
126
|
name: reek
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
114
128
|
requirements:
|
115
|
-
- - "
|
129
|
+
- - "~>"
|
116
130
|
- !ruby/object:Gem::Version
|
117
|
-
version: '
|
131
|
+
version: '2.2'
|
118
132
|
type: :development
|
119
133
|
prerelease: false
|
120
134
|
version_requirements: !ruby/object:Gem::Requirement
|
121
135
|
requirements:
|
122
|
-
- - "
|
136
|
+
- - "~>"
|
123
137
|
- !ruby/object:Gem::Version
|
124
|
-
version: '
|
138
|
+
version: '2.2'
|
125
139
|
- !ruby/object:Gem::Dependency
|
126
140
|
name: simplecov
|
127
141
|
requirement: !ruby/object:Gem::Requirement
|
128
142
|
requirements:
|
129
|
-
- - "
|
143
|
+
- - "~>"
|
130
144
|
- !ruby/object:Gem::Version
|
131
|
-
version: '0'
|
145
|
+
version: '0.10'
|
132
146
|
type: :development
|
133
147
|
prerelease: false
|
134
148
|
version_requirements: !ruby/object:Gem::Requirement
|
135
149
|
requirements:
|
136
|
-
- - "
|
150
|
+
- - "~>"
|
137
151
|
- !ruby/object:Gem::Version
|
138
|
-
version: '0'
|
152
|
+
version: '0.10'
|
139
153
|
- !ruby/object:Gem::Dependency
|
140
154
|
name: bundler
|
141
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -150,6 +164,20 @@ dependencies:
|
|
150
164
|
- - "~>"
|
151
165
|
- !ruby/object:Gem::Version
|
152
166
|
version: '1.0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: pry
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - "~>"
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0.10'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - "~>"
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0.10'
|
153
181
|
description: |
|
154
182
|
An exercise: Untangle the collusion of Rails idioms
|
155
183
|
from my Ruby knowledge, while trying to understand some
|
@@ -171,9 +199,11 @@ files:
|
|
171
199
|
- lib/rory/application.rb
|
172
200
|
- lib/rory/controller.rb
|
173
201
|
- lib/rory/dispatcher.rb
|
202
|
+
- lib/rory/parameter_filter.rb
|
174
203
|
- lib/rory/path_generation.rb
|
175
204
|
- lib/rory/renderer.rb
|
176
205
|
- lib/rory/renderer/context.rb
|
206
|
+
- lib/rory/request_parameter_logger.rb
|
177
207
|
- lib/rory/route.rb
|
178
208
|
- lib/rory/route_mapper.rb
|
179
209
|
- lib/rory/support.rb
|
@@ -191,6 +221,7 @@ files:
|
|
191
221
|
- spec/fixture_app/controllers/goose/wombat/rabbits_controller.rb
|
192
222
|
- spec/fixture_app/controllers/stub_controller.rb
|
193
223
|
- spec/fixture_app/lib/dummy_middleware.rb
|
224
|
+
- spec/fixture_app/log/test.log
|
194
225
|
- spec/fixture_app/views/for_reals/but_wait.html.erb
|
195
226
|
- spec/fixture_app/views/for_reals/custom.html.erb
|
196
227
|
- spec/fixture_app/views/for_reals/srsly.html.erb
|
@@ -204,8 +235,10 @@ files:
|
|
204
235
|
- spec/lib/rory/application_spec.rb
|
205
236
|
- spec/lib/rory/controller_spec.rb
|
206
237
|
- spec/lib/rory/dispatcher_spec.rb
|
238
|
+
- spec/lib/rory/parameter_filter_spec.rb
|
207
239
|
- spec/lib/rory/renderer/context_spec.rb
|
208
240
|
- spec/lib/rory/renderer_spec.rb
|
241
|
+
- spec/lib/rory/request_parameter_logger_spec.rb
|
209
242
|
- spec/lib/rory/route_spec.rb
|
210
243
|
- spec/lib/rory/support_spec.rb
|
211
244
|
- spec/lib/rory_spec.rb
|