json_schema_tools 0.0.1 → 0.0.2
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/.travis.yml +5 -0
- data/CHANGELOG.md +6 -0
- data/README.md +69 -24
- data/lib/schema_tools/cleaner.rb +3 -2
- data/lib/schema_tools/modules/attributes.rb +40 -0
- data/lib/schema_tools/modules/hash.rb +15 -20
- data/lib/schema_tools/version.rb +1 -1
- data/lib/schema_tools.rb +2 -0
- data/spec/fixtures/contact.json +29 -0
- data/spec/schema_tools/cleaner_spec.rb +24 -0
- data/spec/schema_tools/hash_spec.rb +20 -0
- data/spec/schema_tools/modules/attributes_spec.rb +26 -0
- data/spec/spec_helper.rb +0 -5
- metadata +9 -3
data/CHANGELOG.md
ADDED
data/README.md
CHANGED
@@ -1,30 +1,29 @@
|
|
1
1
|
# JSON Schema Tools
|
2
2
|
|
3
|
-
|
3
|
+
[](https://travis-ci.org/salesking/json_schema_tools)
|
4
4
|
|
5
5
|
Set of tools to help working with JSON Schemata:
|
6
6
|
|
7
7
|
* read schema files into a ruby hash
|
8
8
|
* add schema properties to a class
|
9
|
-
* convert
|
9
|
+
* convert any object into it's schema json markup
|
10
10
|
* clean parameters according to a schema (e.g. in an api controller)
|
11
11
|
|
12
|
-
|
13
12
|
## Usage
|
14
13
|
|
15
14
|
Hook the gem into your app
|
16
15
|
|
17
16
|
gem 'json_schema_tools'
|
18
17
|
|
19
|
-
|
18
|
+
## Read Schema
|
20
19
|
|
21
|
-
Before the fun begins with any of the tools one or multiple JSON schema files
|
22
|
-
must be read
|
23
|
-
|
20
|
+
Before the fun begins, with any of the tools, one or multiple JSON schema files
|
21
|
+
must be available(read into a hash). So first provide a base path where the
|
22
|
+
schema.json files are located.
|
24
23
|
|
25
24
|
SchemaTools.schema_path = '/path/to/schema-json-files'
|
26
25
|
|
27
|
-
|
26
|
+
Now you can read a single or multiple schemas:
|
28
27
|
|
29
28
|
schema = SchemaTools::Reader.read :client
|
30
29
|
# read all *.json files in schema path
|
@@ -32,7 +31,7 @@ No you can read a single or multiple schemas:
|
|
32
31
|
# see schema cached in registry
|
33
32
|
SchemaTools::Reader.registry[:client]
|
34
33
|
|
35
|
-
Read files from
|
34
|
+
Read files from a custom path?
|
36
35
|
|
37
36
|
schema = SchemaTools::Reader.read :client, 'my/path/to/json-files'
|
38
37
|
schemata = SchemaTools::Reader.read_all 'my/path/to/json-files'
|
@@ -44,30 +43,76 @@ Don't like the global path and registry? Go local:
|
|
44
43
|
reader.registry
|
45
44
|
|
46
45
|
|
47
|
-
## Object to
|
46
|
+
## Object to Schema
|
48
47
|
|
49
|
-
A schema provides a (public) contract about an object definition.
|
50
|
-
|
51
|
-
|
52
|
-
|
48
|
+
A schema provides a (public) contract about an object definition. Therefore an
|
49
|
+
internal object is converted to it's schema version on delivery(API access).
|
50
|
+
First the object is converted to a hash containing only the properties(keys)
|
51
|
+
from its schema definition. Afterwards it is a breeze to convert this hash into
|
52
|
+
JSON, with your favorite generator.
|
53
53
|
|
54
|
-
Following uses client.json schema(same as
|
54
|
+
Following uses client.json schema(same as peter.class name) inside the global
|
55
55
|
schema_path and adds properties to the clients_hash simply calling
|
56
56
|
client.send('property-name'):
|
57
57
|
|
58
|
-
|
59
|
-
|
60
|
-
|
58
|
+
peter = Client.new name: 'Peter'
|
59
|
+
client_hash = SchemaTools::Hash.from_schema(peter)
|
60
|
+
#=> "client"=>{"id"=>12, "name"=> "Peter", "email"=>"",..} # whatever else you have as properties
|
61
|
+
# to_json is up to you .. or your rails controller
|
62
|
+
|
63
|
+
### Customise Schema Hash
|
64
|
+
|
65
|
+
Only use some fields e.g. to save bandwidth
|
66
|
+
|
67
|
+
client_hash = SchemaTools::Hash.from_schema(peter, fields:['id', 'name'])
|
68
|
+
#=> "client"=>{"id"=>12, "name"=> "Peter"}
|
69
|
+
|
70
|
+
Use a custom schema name e.g. to represent a client as contact. Assumes you also
|
71
|
+
have a schema named contact.json
|
72
|
+
|
73
|
+
client_hash = SchemaTools::Hash.from_schema(peter, class_name: 'contact')
|
74
|
+
#=> "contact"=>{"id"=>12, "name"=> "Peter"}
|
75
|
+
|
76
|
+
Use a custom schema path
|
77
|
+
|
78
|
+
client_hash = SchemaTools::Hash.from_schema(peter, path: 'path-to/json-files/')
|
79
|
+
#=> "client"=>{"id"=>12, "name"=> "Peter"}
|
61
80
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
81
|
+
## Parameter cleaning
|
82
|
+
|
83
|
+
Hate people spamming your api with wrong object fields? Use the Cleaner to
|
84
|
+
check incoming params.
|
85
|
+
|
86
|
+
For example in a client controller
|
87
|
+
|
88
|
+
def create
|
89
|
+
SchemaTools::Cleaner.clean_params!(:client, params[:client])
|
90
|
+
# params[:client] now only has keys defined as writable in client.json schema
|
91
|
+
#..create and save client
|
92
|
+
end
|
93
|
+
|
94
|
+
## Object attributes from Schema
|
95
|
+
|
96
|
+
The use-case here is to add methods, defined in schema properties, to an object.
|
97
|
+
Very usefull if you are building a API client and don't want to manually add
|
98
|
+
methods to you local classes .. like people NOT using JSON schema
|
99
|
+
|
100
|
+
class Contact
|
101
|
+
include SchemaTools::Modules::Attributes
|
102
|
+
has_schema_attrs :client
|
103
|
+
end
|
104
|
+
|
105
|
+
contact = Client.new
|
106
|
+
contact.last_name = 'Rambo'
|
107
|
+
# raw access
|
108
|
+
contact.schema_attrs
|
66
109
|
|
67
110
|
## Test
|
68
111
|
|
69
|
-
|
70
|
-
|
112
|
+
Only runs on Ruby 1.9
|
113
|
+
|
114
|
+
bundle install
|
115
|
+
bundle exec rake spec
|
71
116
|
|
72
117
|
|
73
118
|
Copyright 2012-1013, Georg Leciejewski, MIT License
|
data/lib/schema_tools/cleaner.rb
CHANGED
@@ -11,7 +11,7 @@ module SchemaTools
|
|
11
11
|
#
|
12
12
|
# @param [String|Symbol] obj_name of the object/schema
|
13
13
|
# @param [Hash{String|Symbol=>Mixed}] params properties for the object
|
14
|
-
# @param [
|
14
|
+
# @param [Hash] opts
|
15
15
|
# @options opts [Array<String|Symbol>] :keep properties not being kicked
|
16
16
|
# even if defined as readonly
|
17
17
|
def clean_params!(obj_name, params, opts={})
|
@@ -22,7 +22,8 @@ module SchemaTools
|
|
22
22
|
setters += opts[:keep] if opts[:keep] && opts[:keep].is_a?(Array)
|
23
23
|
# kick readonly
|
24
24
|
params.delete_if { |k,v| !setters.include?("#{k}") }
|
25
|
-
#convert to type in schema
|
25
|
+
#convert to type in schema,
|
26
|
+
# atm. only strings since number can vary float, int, BigDec
|
26
27
|
params.each do |k,v|
|
27
28
|
if schema[:properties]["#{k}"]['type'] == 'string' && !v.is_a?(String)
|
28
29
|
params[k] = "#{v}"
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
module SchemaTools
|
3
|
+
module Modules
|
4
|
+
# Add schema properties to a class by including this module and defining from
|
5
|
+
# which schema to inherit attributes.
|
6
|
+
module Attributes
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
def schema_attrs
|
10
|
+
@schema_attrs ||= {}
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
|
15
|
+
# @param [Symbol|String] schema name
|
16
|
+
# @param [Hash<Symbol|String>] opts
|
17
|
+
# @options opts [String] :path schema path
|
18
|
+
def has_schema_attrs(schema, opts={})
|
19
|
+
schema = SchemaTools::Reader.read(schema, opts[:path])
|
20
|
+
# make getter / setter
|
21
|
+
schema[:properties].each do |key, val|
|
22
|
+
# getter
|
23
|
+
define_method key do
|
24
|
+
schema_attrs[key]
|
25
|
+
end
|
26
|
+
#setter
|
27
|
+
unless val[:readonly]
|
28
|
+
define_method "#{key}=" do |value|
|
29
|
+
#TODO validations?
|
30
|
+
schema_attrs[key] = value
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end # ClassMethods
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -12,35 +12,30 @@ module SchemaTools
|
|
12
12
|
# object-to-api-markup workflow
|
13
13
|
#
|
14
14
|
# === Example
|
15
|
+
#
|
15
16
|
# obj = Invoice.new(:title =>'hello world', :number=>'4711')
|
16
17
|
#
|
17
|
-
# obj_hash = SchemaTools::Hash.from_schema(obj
|
18
|
+
# obj_hash = SchemaTools::Hash.from_schema(obj)
|
18
19
|
# => { 'invoice' =>{'title'=>'hello world', 'number'=>'4711' } }
|
19
20
|
#
|
20
|
-
# obj_hash = Schema.to_hash_from_schema(obj,
|
21
|
+
# obj_hash = Schema.to_hash_from_schema(obj, fields: ['title'])
|
21
22
|
# => { 'invoice' =>{'title'=>'hello world' } }
|
22
23
|
#
|
23
|
-
# obj_hash = Schema.to_hash_from_schema(obj,
|
24
|
+
# obj_hash = Schema.to_hash_from_schema(obj, class_name: :document)
|
24
25
|
# => { 'document' =>{'title'=>'hello world' } }
|
25
26
|
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
# opts<Hash{Symbol=>Mixed} >:: additional options
|
31
|
-
#
|
32
|
-
# ==== opts Parameter
|
33
|
-
# class_name<String|Symbol>:: Name of the class to use as hash key. Should be
|
34
|
-
# a lowered, underscored name and it MUST have an existing schema file.
|
27
|
+
# @param [Object] obj which is returned as hash
|
28
|
+
# @param [Hash{Symbol=>Mixed}] opts additional options
|
29
|
+
# @options opts [String|Symbol] :class_name used as hash key. Should be
|
30
|
+
# a lowercase underscored name and it MUST have an existing schema file.
|
35
31
|
# Use it to override the default, which is obj.class.name
|
36
|
-
#
|
37
|
-
#
|
32
|
+
# @options opts [Array<String>] :fields to return. If not set all schema
|
33
|
+
# properties are used.
|
34
|
+
# @options opts [String] :path of the schema files overriding global one
|
35
|
+
#
|
36
|
+
# @return [Hash{String=>{String=>Mixed}}] The object as hash:
|
37
|
+
# { 'invoice' => {'title'=>'hello world', 'number'=>'4711' } }
|
38
38
|
#
|
39
|
-
# === Return
|
40
|
-
# <Hash{String=>{String=>Mixed}}>:: The object as hash:
|
41
|
-
# { invoice =>{'title'=>'hello world', 'number'=>'4711' } }
|
42
|
-
# @param [Object] obj
|
43
|
-
# @param [Object] opts
|
44
39
|
def from_schema(obj, opts={})
|
45
40
|
fields = opts[:fields]
|
46
41
|
# get objects class name without inheritance
|
@@ -51,7 +46,7 @@ module SchemaTools
|
|
51
46
|
|
52
47
|
data = {}
|
53
48
|
# get schema
|
54
|
-
schema = SchemaTools::Reader.read(class_name)
|
49
|
+
schema = SchemaTools::Reader.read(class_name, opts[:path])
|
55
50
|
# iterate over the defined schema fields
|
56
51
|
schema['properties'].each do |field, prop|
|
57
52
|
next if fields && !fields.include?(field)
|
data/lib/schema_tools/version.rb
CHANGED
data/lib/schema_tools.rb
CHANGED
@@ -2,7 +2,9 @@ require 'json'
|
|
2
2
|
require 'schema_tools/version'
|
3
3
|
require 'schema_tools/modules/read'
|
4
4
|
require 'schema_tools/modules/hash'
|
5
|
+
require 'schema_tools/modules/attributes'
|
5
6
|
require 'schema_tools/reader'
|
7
|
+
require 'schema_tools/cleaner'
|
6
8
|
require 'schema_tools/hash'
|
7
9
|
|
8
10
|
|
@@ -0,0 +1,29 @@
|
|
1
|
+
{"type":"object",
|
2
|
+
"title": "Contact",
|
3
|
+
"name": "contact",
|
4
|
+
"description": "A simple contact",
|
5
|
+
"properties":{
|
6
|
+
"id":{
|
7
|
+
"description":"Unique identifier ",
|
8
|
+
"identity":true,
|
9
|
+
"readonly":true,
|
10
|
+
"type":"number"
|
11
|
+
},
|
12
|
+
"organisation":{
|
13
|
+
"description": "Name of a company. ",
|
14
|
+
"required" : true,
|
15
|
+
"type":"string",
|
16
|
+
"maxLength": 100
|
17
|
+
},
|
18
|
+
"last_name":{
|
19
|
+
"description": "Last name of a person. ",
|
20
|
+
"type":"string",
|
21
|
+
"maxLength": 50
|
22
|
+
},
|
23
|
+
"first_name":{
|
24
|
+
"description": "First name of a person.",
|
25
|
+
"type":"string",
|
26
|
+
"maxLength": 50
|
27
|
+
}
|
28
|
+
}
|
29
|
+
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SchemaTools::Cleaner do
|
4
|
+
|
5
|
+
context 'params cleaning' do
|
6
|
+
let(:params){
|
7
|
+
{ id: 'some id',
|
8
|
+
last_name: 'Clean',
|
9
|
+
first_name: 'Paul'
|
10
|
+
}
|
11
|
+
}
|
12
|
+
|
13
|
+
after :each do
|
14
|
+
SchemaTools::Reader.registry_reset
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should remove invalid keys from hash' do
|
18
|
+
SchemaTools::Cleaner.clean_params!(:client, params)
|
19
|
+
params[:last_name].should == 'Clean'
|
20
|
+
params[:id].should be_nil
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
@@ -11,6 +11,7 @@ describe SchemaTools::Hash do
|
|
11
11
|
before :each do
|
12
12
|
client.first_name = 'Peter'
|
13
13
|
client.last_name = 'Paul'
|
14
|
+
client.id = 'SomeID'
|
14
15
|
end
|
15
16
|
after :each do
|
16
17
|
SchemaTools::Reader.registry_reset
|
@@ -20,6 +21,25 @@ describe SchemaTools::Hash do
|
|
20
21
|
hash = SchemaTools::Hash.from_schema(client)
|
21
22
|
hash['client']['last_name'].should == 'Paul'
|
22
23
|
end
|
24
|
+
|
25
|
+
it 'should use custom schema path' do
|
26
|
+
custom_path = File.expand_path('../../fixtures', __FILE__)
|
27
|
+
hash = SchemaTools::Hash.from_schema(client, path: custom_path)
|
28
|
+
hash['client']['last_name'].should == 'Paul'
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should use custom schema' do
|
32
|
+
hash = SchemaTools::Hash.from_schema(client, class_name: :contact)
|
33
|
+
hash['contact']['last_name'].should == 'Paul'
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should use only give fields' do
|
37
|
+
hash = SchemaTools::Hash.from_schema(client, fields: ['id', 'last_name'])
|
38
|
+
hash['client'].keys.length.should == 2
|
39
|
+
hash['client']['last_name'].should == client.last_name
|
40
|
+
hash['client']['id'].should == client.id
|
41
|
+
hash['client']['first_name'].should be_nil
|
42
|
+
end
|
23
43
|
end
|
24
44
|
end
|
25
45
|
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class Contact
|
4
|
+
include SchemaTools::Modules::Attributes
|
5
|
+
has_schema_attrs :client
|
6
|
+
end
|
7
|
+
|
8
|
+
describe SchemaTools::Modules::Attributes do
|
9
|
+
|
10
|
+
context 'included' do
|
11
|
+
let(:contact){Contact.new}
|
12
|
+
|
13
|
+
it 'should add getter methods' do
|
14
|
+
contact.respond_to?(:last_name).should be_true
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should add setter methods' do
|
18
|
+
contact.respond_to?('first_name=').should be_true
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should not add setter for readonly properties' do
|
22
|
+
contact.respond_to?('id=').should be_false
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
data/spec/spec_helper.rb
CHANGED
@@ -13,11 +13,6 @@ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
13
13
|
require 'json_schema_tools'
|
14
14
|
|
15
15
|
RSpec.configure do |config|
|
16
|
-
#config.treat_symbols_as_metadata_keys_with_true_values = true
|
17
|
-
#config.run_all_when_everything_filtered = true
|
18
|
-
#config.filter_run :focus
|
19
|
-
#config.after(:all) do
|
20
|
-
#end
|
21
16
|
end
|
22
17
|
|
23
18
|
# set global json schema path for examples
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: json_schema_tools
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -101,6 +101,8 @@ extensions: []
|
|
101
101
|
extra_rdoc_files: []
|
102
102
|
files:
|
103
103
|
- .gitignore
|
104
|
+
- .travis.yml
|
105
|
+
- CHANGELOG.md
|
104
106
|
- Gemfile
|
105
107
|
- README.md
|
106
108
|
- Rakefile
|
@@ -109,14 +111,18 @@ files:
|
|
109
111
|
- lib/schema_tools.rb
|
110
112
|
- lib/schema_tools/cleaner.rb
|
111
113
|
- lib/schema_tools/hash.rb
|
114
|
+
- lib/schema_tools/modules/attributes.rb
|
112
115
|
- lib/schema_tools/modules/hash.rb
|
113
116
|
- lib/schema_tools/modules/read.rb
|
114
117
|
- lib/schema_tools/reader.rb
|
115
118
|
- lib/schema_tools/version.rb
|
116
119
|
- spec/fixtures/address.json
|
117
120
|
- spec/fixtures/client.json
|
121
|
+
- spec/fixtures/contact.json
|
118
122
|
- spec/fixtures/page.json
|
123
|
+
- spec/schema_tools/cleaner_spec.rb
|
119
124
|
- spec/schema_tools/hash_spec.rb
|
125
|
+
- spec/schema_tools/modules/attributes_spec.rb
|
120
126
|
- spec/schema_tools/reader_spec.rb
|
121
127
|
- spec/spec_helper.rb
|
122
128
|
homepage: http://www.salesking.eu/dev
|
@@ -133,7 +139,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
133
139
|
version: '0'
|
134
140
|
segments:
|
135
141
|
- 0
|
136
|
-
hash:
|
142
|
+
hash: -438392315177719693
|
137
143
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
138
144
|
none: false
|
139
145
|
requirements:
|
@@ -142,7 +148,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
142
148
|
version: '0'
|
143
149
|
segments:
|
144
150
|
- 0
|
145
|
-
hash:
|
151
|
+
hash: -438392315177719693
|
146
152
|
requirements: []
|
147
153
|
rubyforge_project:
|
148
154
|
rubygems_version: 1.8.24
|