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 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