logical_model 0.4.10 → 0.5.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.
- data/README.rdoc +17 -2
- data/VERSION +1 -1
- data/client.rb +10 -4
- data/lib/logical_model.rb +23 -481
- data/lib/logical_model/api_key.rb +41 -0
- data/lib/logical_model/attributes.rb +57 -0
- data/lib/logical_model/has_many_keys.rb +53 -47
- data/lib/logical_model/rest_actions.rb +410 -0
- data/lib/logical_model/safe_log.rb +61 -0
- data/lib/logical_model/url_helper.rb +78 -0
- data/logical_model.gemspec +7 -4
- data/spec/client_spec.rb +129 -39
- metadata +8 -5
- data/lib/safe_log.rb +0 -11
- data/lib/ssl_support.rb +0 -39
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
class LogicalModel
|
4
|
+
module SafeLog
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.send(:include, InstanceMethods)
|
8
|
+
base.send(:extend, ClassMethods)
|
9
|
+
end
|
10
|
+
|
11
|
+
module InstanceMethods
|
12
|
+
def log_ok(response)
|
13
|
+
self.class.log_ok(response)
|
14
|
+
end
|
15
|
+
|
16
|
+
def log_failed(response)
|
17
|
+
self.class.log_failed(response)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
module ClassMethods
|
23
|
+
attr_accessor :log_path
|
24
|
+
|
25
|
+
def log_path
|
26
|
+
@log_path ||= "log/logical_model.log"
|
27
|
+
end
|
28
|
+
|
29
|
+
def log_ok(response)
|
30
|
+
self.logger.info("LogicalModel Log: #{response.code} #{mask_api_key(response.effective_url)} in #{response.time}s")
|
31
|
+
self.logger.debug("LogicalModel Log RESPONSE: #{response.body}")
|
32
|
+
end
|
33
|
+
|
34
|
+
def log_failed(response)
|
35
|
+
begin
|
36
|
+
error_message = ActiveSupport::JSON.decode(response.body)["message"]
|
37
|
+
rescue => e
|
38
|
+
error_message = "error"
|
39
|
+
end
|
40
|
+
msg = "LogicalModel Log: #{response.code} #{mask_api_key(response.effective_url)} in #{response.time}s FAILED: #{error_message}"
|
41
|
+
self.logger.warn(msg)
|
42
|
+
self.logger.debug("LogicalModel Log RESPONSE: #{response.body}")
|
43
|
+
end
|
44
|
+
|
45
|
+
def logger
|
46
|
+
Logger.new(self.log_path || "log/logical_model.log")
|
47
|
+
end
|
48
|
+
|
49
|
+
# Filters api_key
|
50
|
+
# @return [String]
|
51
|
+
def mask_api_key(str)
|
52
|
+
if use_api_key && str
|
53
|
+
str = str.gsub(api_key,'[SECRET]')
|
54
|
+
end
|
55
|
+
str
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
class LogicalModel
|
2
|
+
module UrlHelper
|
3
|
+
|
4
|
+
def self.included(base)
|
5
|
+
base.send(:extend, ClassMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
# adds following setters
|
9
|
+
# - force_ssl
|
10
|
+
# - set_resource_host
|
11
|
+
# - set_resource_path
|
12
|
+
#
|
13
|
+
# add reader
|
14
|
+
# - resource_uri
|
15
|
+
module ClassMethods
|
16
|
+
|
17
|
+
attr_accessor :host,
|
18
|
+
:resource_path,
|
19
|
+
:use_ssl
|
20
|
+
|
21
|
+
# Will return path to resource
|
22
|
+
# @param id [String] (nil)
|
23
|
+
def resource_uri(id=nil)
|
24
|
+
sufix = (id.nil?)? "" : "/#{id}"
|
25
|
+
"#{url_protocol_prefix}#{host}#{resource_path}#{sufix}"
|
26
|
+
end
|
27
|
+
|
28
|
+
# If called in class, will make al request through SSL.
|
29
|
+
# @example
|
30
|
+
# class Client < LogicalModel
|
31
|
+
# force_ssl
|
32
|
+
# ...
|
33
|
+
# end
|
34
|
+
def force_ssl
|
35
|
+
@use_ssl = true
|
36
|
+
end
|
37
|
+
|
38
|
+
# @param new_host [String] resource host. Should NOT include protocol (http)
|
39
|
+
# @param new_path [String] resource path in host
|
40
|
+
def set_resource_url(new_host,new_path)
|
41
|
+
@host = new_host
|
42
|
+
@resource_path = new_path
|
43
|
+
end
|
44
|
+
|
45
|
+
def set_resource_host(new_host)
|
46
|
+
@host = new_host
|
47
|
+
end
|
48
|
+
|
49
|
+
def set_resource_path(new_path)
|
50
|
+
@resource_path = new_path
|
51
|
+
end
|
52
|
+
|
53
|
+
##
|
54
|
+
# Default use_ssl to ssl_recommend?
|
55
|
+
# @return [Boolean]
|
56
|
+
def use_ssl?
|
57
|
+
@use_ssl ||= ssl_recommended?
|
58
|
+
end
|
59
|
+
|
60
|
+
# @return [String]
|
61
|
+
def url_protocol_prefix
|
62
|
+
(use_ssl?)? "https://" : "http://"
|
63
|
+
end
|
64
|
+
|
65
|
+
# Returns true if ssl is recommended according to environment.
|
66
|
+
#
|
67
|
+
# - production, staging -> true
|
68
|
+
# - other -> false
|
69
|
+
#
|
70
|
+
# @return [Boolean]
|
71
|
+
def ssl_recommended?
|
72
|
+
ssl_recommended_environments = %W(production staging)
|
73
|
+
ssl_recommended_environments.include?(defined?(Rails)? Rails.env : ENV['RACK_ENV'] )
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
data/logical_model.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "logical_model"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.5.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Dwayne Macgowan"]
|
12
|
-
s.date = "2013-
|
12
|
+
s.date = "2013-05-01"
|
13
13
|
s.description = "LogicalModel allows to use a resource as a model. It is based on web presentation http://www.slideshare.net/ihower/serviceoriented-design-and-implement-with-rails3"
|
14
14
|
s.email = "dwaynemac@gmail.com"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -32,9 +32,12 @@ Gem::Specification.new do |s|
|
|
32
32
|
"db/development.sqlite3",
|
33
33
|
"db/migrate/001_create_users.rb",
|
34
34
|
"lib/logical_model.rb",
|
35
|
+
"lib/logical_model/api_key.rb",
|
36
|
+
"lib/logical_model/attributes.rb",
|
35
37
|
"lib/logical_model/has_many_keys.rb",
|
36
|
-
"lib/
|
37
|
-
"lib/
|
38
|
+
"lib/logical_model/rest_actions.rb",
|
39
|
+
"lib/logical_model/safe_log.rb",
|
40
|
+
"lib/logical_model/url_helper.rb",
|
38
41
|
"lib/typhoeus_fix/array_decoder.rb",
|
39
42
|
"logical_model.gemspec",
|
40
43
|
"models/user.rb",
|
data/spec/client_spec.rb
CHANGED
@@ -5,6 +5,135 @@ include TyphoeusMocks
|
|
5
5
|
|
6
6
|
describe "LogicalModel User client" do
|
7
7
|
|
8
|
+
subject{User}
|
9
|
+
|
10
|
+
describe "Attributes" do
|
11
|
+
subject{User.new}
|
12
|
+
%W(id name email password bio).each do |attribute|
|
13
|
+
it { should respond_to attribute }
|
14
|
+
it { should respond_to "#{attribute}="}
|
15
|
+
end
|
16
|
+
describe "attribute definer" do
|
17
|
+
it "should add attribute" do
|
18
|
+
User.new.attributes.should_not include :this_is_a_new_attribute
|
19
|
+
User.new.attributes.should_not include :another_new_attribute
|
20
|
+
class User < LogicalModel
|
21
|
+
attribute :this_is_a_new_attribute
|
22
|
+
attribute :another_new_attribute
|
23
|
+
end
|
24
|
+
User.new.attributes.should include :this_is_a_new_attribute
|
25
|
+
User.new.attributes.should include :another_new_attribute
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "RESTActions" do
|
31
|
+
%W(find async_find paginate async_paginate delete delete_multiple).each do |class_action|
|
32
|
+
it { should respond_to class_action }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "has_many_keys" do
|
37
|
+
it { should respond_to 'has_many_keys=' }
|
38
|
+
it { should respond_to 'has_many_keys'}
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "url_helper" do
|
42
|
+
it { should respond_to 'use_ssl=' }
|
43
|
+
it { should respond_to 'use_ssl?' }
|
44
|
+
it { should respond_to 'url_protocol_prefix' }
|
45
|
+
it { should respond_to 'ssl_recommended?' }
|
46
|
+
describe "force_ssl" do
|
47
|
+
it { should respond_to 'force_ssl' }
|
48
|
+
it "sets use_ssl to true" do
|
49
|
+
User.use_ssl?.should be_false
|
50
|
+
class User; force_ssl; end;
|
51
|
+
User.use_ssl?.should be_true
|
52
|
+
end
|
53
|
+
end
|
54
|
+
describe "set_resource_host" do
|
55
|
+
it { should respond_to 'set_resource_host' }
|
56
|
+
it "sets resource_path" do
|
57
|
+
User.resource_path.should == "/api/v1/users"
|
58
|
+
class User; set_resource_path("new_path"); end;
|
59
|
+
User.resource_path.should == "new_path"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
describe "set_resource_path" do
|
63
|
+
it { should respond_to 'set_resource_path'}
|
64
|
+
it "sets resource_host" do
|
65
|
+
User.host.should == "localhost:3000"
|
66
|
+
class User; set_resource_host("new_host"); end;
|
67
|
+
User.host.should == "new_host"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "safe_log" do
|
73
|
+
it { should respond_to 'log_ok' }
|
74
|
+
it { should respond_to 'log_failed' }
|
75
|
+
it { should respond_to 'logger' }
|
76
|
+
it { should respond_to 'mask_api_key' }
|
77
|
+
describe ".log_path" do
|
78
|
+
it { should respond_to 'log_path' }
|
79
|
+
its(:log_path){ should == "logs/development.log"}
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "api_key" do
|
84
|
+
describe "set_api_key" do
|
85
|
+
it { should respond_to 'set_api_key'}
|
86
|
+
it "sets api_key" do
|
87
|
+
class User < LogicalModel
|
88
|
+
set_api_key(:key_name, 'secret_api_key')
|
89
|
+
end
|
90
|
+
User.use_api_key.should be_true
|
91
|
+
User.api_key.should == 'secret_api_key'
|
92
|
+
User.api_key_name.should == :key_name
|
93
|
+
end
|
94
|
+
end
|
95
|
+
describe "use_api_key" do
|
96
|
+
it { should respond_to 'use_api_key' }
|
97
|
+
context "when true" do
|
98
|
+
before(:each) do
|
99
|
+
class User < LogicalModel; self.use_api_key=true; self.api_key_name='keyname'; self.api_key="secret_api_key"; end
|
100
|
+
end
|
101
|
+
it "should send api key in requests" do
|
102
|
+
Typhoeus::Request.should_receive(:new).with(User.resource_uri(1),{:params=>{'keyname'=>'secret_api_key'}})
|
103
|
+
begin
|
104
|
+
User.find(1)
|
105
|
+
rescue
|
106
|
+
end
|
107
|
+
end
|
108
|
+
it "should mask api key in logs" do
|
109
|
+
response = mock(
|
110
|
+
code: 200,
|
111
|
+
body: {}.to_json,
|
112
|
+
effective_url: "server?keyname=secret_api_key",
|
113
|
+
time: 1234
|
114
|
+
)
|
115
|
+
Logger.any_instance.should_receive(:info).with(/\[SECRET\]/)
|
116
|
+
User.log_ok(response)
|
117
|
+
Logger.any_instance.should_receive(:warn).with(/\[SECRET\]/)
|
118
|
+
User.log_failed(response)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
context "when false" do
|
122
|
+
before(:each) do
|
123
|
+
class User < LogicalModel; self.use_api_key=false; self.api_key_name='keyname'; self.api_key="secret_api_key"; end
|
124
|
+
end
|
125
|
+
it "should not send api key in requests" do
|
126
|
+
Typhoeus::Request.should_not_receive(:new).with(User.resource_uri(1),{:params=>{'keyname'=>'secret_api_key'}})
|
127
|
+
begin
|
128
|
+
User.find(1)
|
129
|
+
rescue
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
it { should respond_to 'merge_key'}
|
135
|
+
end
|
136
|
+
|
8
137
|
describe "#create" do
|
9
138
|
context "with valid attributes" do
|
10
139
|
context "if response is code 201" do
|
@@ -131,45 +260,6 @@ describe "LogicalModel User client" do
|
|
131
260
|
end
|
132
261
|
end
|
133
262
|
|
134
|
-
describe "use_api_key" do
|
135
|
-
context "when true" do
|
136
|
-
before(:each) do
|
137
|
-
class User < LogicalModel; self.use_api_key=true; self.api_key_name='keyname'; self.api_key="secret_api_key"; end
|
138
|
-
end
|
139
|
-
it "should send api key in requests" do
|
140
|
-
Typhoeus::Request.should_receive(:new).with(User.resource_uri(1),{:params=>{'keyname'=>'secret_api_key'}})
|
141
|
-
begin
|
142
|
-
User.find(1)
|
143
|
-
rescue
|
144
|
-
end
|
145
|
-
end
|
146
|
-
it "should mask api key in logs" do
|
147
|
-
response = mock(
|
148
|
-
code: 200,
|
149
|
-
body: {}.to_json,
|
150
|
-
effective_url: "server?keyname=secret_api_key",
|
151
|
-
time: 1234
|
152
|
-
)
|
153
|
-
Logger.any_instance.should_receive(:info).with(/\[SECRET\]/)
|
154
|
-
User.log_ok(response)
|
155
|
-
Logger.any_instance.should_receive(:warn).with(/\[SECRET\]/)
|
156
|
-
User.log_failed(response)
|
157
|
-
end
|
158
|
-
end
|
159
|
-
context "when false" do
|
160
|
-
before(:each) do
|
161
|
-
class User < LogicalModel; self.use_api_key=false; self.api_key_name='keyname'; self.api_key="secret_api_key"; end
|
162
|
-
end
|
163
|
-
it "should not send api key in requests" do
|
164
|
-
Typhoeus::Request.should_not_receive(:new).with(User.resource_uri(1),{:params=>{'keyname'=>'secret_api_key'}})
|
165
|
-
begin
|
166
|
-
User.find(1)
|
167
|
-
rescue
|
168
|
-
end
|
169
|
-
end
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
263
|
describe "#https" do
|
174
264
|
context "when use_ssl is tue" do
|
175
265
|
before(:each) do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logical_model
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-05-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activemodel
|
@@ -323,9 +323,12 @@ files:
|
|
323
323
|
- db/development.sqlite3
|
324
324
|
- db/migrate/001_create_users.rb
|
325
325
|
- lib/logical_model.rb
|
326
|
+
- lib/logical_model/api_key.rb
|
327
|
+
- lib/logical_model/attributes.rb
|
326
328
|
- lib/logical_model/has_many_keys.rb
|
327
|
-
- lib/
|
328
|
-
- lib/
|
329
|
+
- lib/logical_model/rest_actions.rb
|
330
|
+
- lib/logical_model/safe_log.rb
|
331
|
+
- lib/logical_model/url_helper.rb
|
329
332
|
- lib/typhoeus_fix/array_decoder.rb
|
330
333
|
- logical_model.gemspec
|
331
334
|
- models/user.rb
|
@@ -348,7 +351,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
348
351
|
version: '0'
|
349
352
|
segments:
|
350
353
|
- 0
|
351
|
-
hash:
|
354
|
+
hash: 863618749
|
352
355
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
353
356
|
none: false
|
354
357
|
requirements:
|
data/lib/safe_log.rb
DELETED
data/lib/ssl_support.rb
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
module SslSupport
|
2
|
-
|
3
|
-
def self.included(base)
|
4
|
-
base.class.send(:attr_accessor, :use_ssl)
|
5
|
-
base.send(:include, InstanceMethods)
|
6
|
-
base.send(:extend, ClassMethods)
|
7
|
-
end
|
8
|
-
|
9
|
-
module InstanceMethods
|
10
|
-
|
11
|
-
end
|
12
|
-
|
13
|
-
module ClassMethods
|
14
|
-
##
|
15
|
-
# Default use_ssl to ssl_recommend?
|
16
|
-
# @return [Boolean]
|
17
|
-
def use_ssl?
|
18
|
-
@use_ssl ||= ssl_recommended?
|
19
|
-
end
|
20
|
-
|
21
|
-
# @return [String]
|
22
|
-
def url_protocol_prefix
|
23
|
-
(use_ssl?)? "https://" : "http://"
|
24
|
-
end
|
25
|
-
|
26
|
-
# Returns true if ssl is recommended according to environment.
|
27
|
-
#
|
28
|
-
# - production, staging -> true
|
29
|
-
# - other -> false
|
30
|
-
#
|
31
|
-
# @return [Boolean]
|
32
|
-
def ssl_recommended?
|
33
|
-
ssl_recommended_environments = %W(production staging)
|
34
|
-
ssl_recommended_environments.include?(defined?(Rails)? Rails.env : ENV['RACK_ENV'] )
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
|
39
|
-
end
|