json_schema_tools 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ rvm:
2
+ - 1.9.2
3
+ - 1.9.3
4
+ gemfile:
5
+ - Gemfile
data/CHANGELOG.md ADDED
@@ -0,0 +1,6 @@
1
+ # Changelog JSON Schema Tools
2
+
3
+
4
+ 12-2012
5
+
6
+ * initial version with reader, hasher, params cleaner, attributes module
data/README.md CHANGED
@@ -1,30 +1,29 @@
1
1
  # JSON Schema Tools
2
2
 
3
- {<img src="https://secure.travis-ci.org/salesking/json_schema_tools.png?branch=master" alt="Build Status" />}[http://travis-ci.org/salesking/json_schema_tools]
3
+ [![Build Status](https://travis-ci.org/salesking/json_schema_tools.png?branch=master)](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 a model(class instance) into it's schema markup
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
- ### Read Schema
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(into a hash). So first provide a base path where the .json files
23
- can be found:
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
- No you can read a single or multiple schemas:
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 another path?
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 schema markup
46
+ ## Object to Schema
48
47
 
49
- A schema provides a (public) contract about an object definition. It is
50
- therefore a common task to convert an internal object to its schema version.
51
- Before the object can be represented as a json string, it is converted to a
52
- hash containing only the properties(keys) from its schema definition:
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 client.class name) from global
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
- peter = Client.new name: 'Peter'
59
- client_hash = SchemaTools::Hash.from_schema(peter)
60
- # to_json is up to you .. or your rails controller
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
- TODO: explain Options for parsing:
63
- * custom class name
64
- * fields include/exclude
65
- * custom schema name
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
- bundle install
70
- bundle exec rake spec
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
@@ -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 [Object] opts
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, 'v1.0')
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, 'v1.0', :fields=>['title'])
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, 'v1.0', :class_name=>:document)
24
+ # obj_hash = Schema.to_hash_from_schema(obj, class_name: :document)
24
25
  # => { 'document' =>{'title'=>'hello world' } }
25
26
  #
26
- # === Parameter
27
- # obj<Object>:: An ruby object which is returned as hash
28
- # version<String>:: the schema version, must be a valid folder name see
29
- # #self.read
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
- # fields<Array[String]>:: Fields/properties to return. If not set all
37
- # schema's properties are used.
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)
@@ -1,3 +1,3 @@
1
1
  module SchemaBuilder
2
- VERSION = '0.0.1'
2
+ VERSION = '0.0.2'
3
3
  end
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.1
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: 3313090340920384455
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: 3313090340920384455
151
+ hash: -438392315177719693
146
152
  requirements: []
147
153
  rubyforge_project:
148
154
  rubygems_version: 1.8.24