schematic 0.0.1

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.
@@ -0,0 +1,9 @@
1
+ *.gem
2
+ *~
3
+ .DS_Store
4
+ .bundle
5
+ .idea
6
+ Gemfile.lock
7
+ doc
8
+ pkg/*
9
+ tags
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm 1.9.2-p136@schematic
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in schematic.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2010-11 Case Commons, LLC
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,3 @@
1
+ = Schematic
2
+
3
+ Automatic schema generation.
@@ -0,0 +1,12 @@
1
+ require 'rake'
2
+ require 'rspec/core'
3
+ require 'rspec/core/rake_task'
4
+
5
+ require 'bundler'
6
+ Bundler::GemHelper.install_tasks
7
+
8
+ task :default => :spec
9
+
10
+ desc "Run all specs in spec directory (excluding plugin specs)"
11
+ RSpec::Core::RakeTask.new(:spec)
12
+
@@ -0,0 +1,15 @@
1
+ module Schematic
2
+ class InvalidClass < Exception
3
+ def message
4
+ "This class does not include ActiveModel. You cannot generate an XSD from it."
5
+ end
6
+ end
7
+ end
8
+
9
+ require "builder"
10
+
11
+ require 'active_support/inflector/inflections'
12
+ require 'active_support/inflections'
13
+ require "schematic/serializers/xsd"
14
+
15
+ ActiveRecord::Base.send(:extend, Schematic::Serializers::Xsd)
@@ -0,0 +1,115 @@
1
+ module Schematic
2
+ module Serializers
3
+ module Xsd
4
+ class << self
5
+ def extended(klass)
6
+ raise InvalidClass unless klass.ancestors.include?(ActiveRecord::Base)
7
+ end
8
+ end
9
+
10
+ def to_xsd(options = {}, builder = nil)
11
+ if builder.nil?
12
+ output = ""
13
+ builder = Builder::XmlMarkup.new(:target => output)
14
+ builder.instruct!
15
+ builder.xs :schema, "xmlns:xs" => "http://www.w3.org/2001/XMLSchema" do |schema|
16
+ schema.xs :element, "name" => xsd_element_collection_name, "type" => xsd_type_collection_name
17
+ self.to_xsd(options, schema)
18
+ end
19
+ output
20
+ else
21
+ xsd_nested_attributes.each do |nested_attribute|
22
+ nested_attribute.klass.to_xsd(options, builder)
23
+ end
24
+ builder.xs :complexType, "name" => xsd_type_collection_name do |complex_type|
25
+ complex_type.xs :sequence do |sequence|
26
+ sequence.xs :element, "name" => xsd_element_name, "type" => xsd_type_name, "minOccurs" => "0", "maxOccurs" => "unbounded"
27
+ end
28
+ complex_type.xs :attribute, "name" => "type", "type" => "xs:string", "fixed" => "array"
29
+ end
30
+ builder.xs :complexType, "name" => xsd_type_name do |complex_type|
31
+ additional_methods = xsd_methods.merge(options[:methods] || {})
32
+ complex_type.xs :all do |all|
33
+ xsd_columns.each do |column|
34
+ next if additional_methods.keys.map(&:to_s).include?(column.name)
35
+
36
+ all.xs :element, "name" => column.name.dasherize, "minOccurs" => "0", "maxOccurs" => "1" do |field|
37
+ field.xs :complexType do |complex_type|
38
+ complex_type.xs :simpleContent do |simple_content|
39
+ simple_content.xs :extension, "base" => map_column_type_to_xsd_type(column) do |extension|
40
+ extension.xs :attribute, "name" => "type", "type" => "xs:string", "use" => "optional"
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ xsd_nested_attributes.each do |nested_attribute|
47
+ all.xs :element, "name" => "#{nested_attribute.name.to_s.dasherize}-attributes", "type" => nested_attribute.klass.xsd_type_collection_name, "minOccurs" => "0", "maxOccurs" => "1"
48
+ end
49
+ additional_methods.each do |method_name, values|
50
+ method_xsd_name = method_name.to_s.dasherize
51
+ if values.present?
52
+ all.xs :element, "name" => method_xsd_name, "minOccurs" => "0", "maxOccurs" => "1" do |element|
53
+ element.xs :complexType do |complex_type|
54
+ complex_type.xs :all do |nested_all|
55
+ values.each do |value|
56
+ nested_all.xs :element, "name" => value.to_s.dasherize, "minOccurs" => "0"
57
+ end
58
+ end
59
+ complex_type.xs :attribute, "name" => "type", "type" => "xs:string", "fixed" => "array", "use" => "optional"
60
+ end
61
+ end
62
+ else
63
+ all.xs :element, "name" => method_xsd_name, "minOccurs" => "0", "maxOccurs" => "1"
64
+ end
65
+ end
66
+ end
67
+ end
68
+ builder
69
+ end
70
+ end
71
+
72
+ def xsd_methods
73
+ {}
74
+ end
75
+
76
+ def xsd_nested_attributes
77
+ self.reflect_on_all_associations.select do |association|
78
+ self.instance_methods.include?("#{association.name}_attributes=".to_sym) && association.options[:polymorphic] != true
79
+ end
80
+ end
81
+
82
+ def xsd_columns
83
+ self.columns
84
+ end
85
+
86
+ def map_column_type_to_xsd_type(column)
87
+ {
88
+ :integer => "xs:integer",
89
+ :float => "xs:float",
90
+ :string => "xs:string",
91
+ :text => "xs:string",
92
+ :datetime => "xs:dateTime",
93
+ :date => "xs:date",
94
+ :boolean => "xs:boolean"
95
+ }[column.type]
96
+ end
97
+
98
+ def xsd_type_name
99
+ self.name
100
+ end
101
+
102
+ def xsd_type_collection_name
103
+ xsd_type_name.pluralize
104
+ end
105
+
106
+ def xsd_element_name
107
+ self.name.underscore.dasherize
108
+ end
109
+
110
+ def xsd_element_collection_name
111
+ xsd_element_name.pluralize
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,3 @@
1
+ module Schematic
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "schematic/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "schematic"
7
+ s.version = Schematic::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Case Commons, LLC"]
10
+ s.email = ["casecommons-dev@googlegroups.com"]
11
+ s.homepage = "https://github.com/Casecommons/schematic"
12
+ s.summary = %q{Automatic XSD generation from ActiveRecord models}
13
+ s.description = %q{Automatic XSD generation from ActiveRecord models}
14
+
15
+ s.rubyforge_project = "schematic"
16
+
17
+ s.add_dependency('activerecord', '>= 3.0.0')
18
+ s.add_dependency('builder')
19
+ s.add_development_dependency('rspec-rails', '>= 2.1')
20
+ s.add_development_dependency('with_model')
21
+ s.add_development_dependency('nokogiri')
22
+ s.add_development_dependency('sqlite3')
23
+
24
+ s.files = `git ls-files`.split("\n")
25
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
26
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
27
+ s.require_paths = ["lib"]
28
+ end
@@ -0,0 +1,172 @@
1
+ require "spec_helper"
2
+
3
+ describe Schematic::Serializers::Xsd do
4
+ before do
5
+ class EmptyModel < ActiveRecord::Base
6
+
7
+ def self.columns
8
+ []
9
+ end
10
+ end
11
+ end
12
+
13
+ describe ".extend" do
14
+ context "when the model inherits ActiveRecord::Base" do
15
+ subject { EmptyModel }
16
+
17
+ it "should allow the model to be extended" do
18
+ lambda {
19
+ subject.class_eval do
20
+ extend Schematic::Serializers::Xsd
21
+ end
22
+ }.should_not raise_error
23
+ end
24
+ end
25
+
26
+ context "when the model does not inherit ActiveRecord::Base" do
27
+ subject { Object }
28
+
29
+ it "should raise an exception" do
30
+ lambda {
31
+ subject.class_eval do
32
+ extend Schematic::Serializers::Xsd
33
+ end
34
+ }.should raise_error(Schematic::InvalidClass)
35
+ end
36
+ end
37
+ end
38
+
39
+ describe ".to_xsd" do
40
+ context "for an empty model with no attributes or validations" do
41
+ subject { EmptyModel.to_xsd }
42
+
43
+ it "should return an xsd for an array of the model" do
44
+ xsd = <<-XML
45
+ <?xml version="1.0" encoding="UTF-8"?>
46
+ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
47
+ <xs:element name="empty-models" type="EmptyModels"/>
48
+ <xs:complexType name="EmptyModels">
49
+ <xs:sequence>
50
+ <xs:element name="empty-model" type="EmptyModel" minOccurs="0" maxOccurs="unbounded"/>
51
+ </xs:sequence>
52
+ <xs:attribute name="type" type="xs:string" fixed="array"/>
53
+ </xs:complexType>
54
+ <xs:complexType name="EmptyModel">
55
+ <xs:all>
56
+ </xs:all>
57
+ </xs:complexType>
58
+ </xs:schema>
59
+ XML
60
+ subject.should == sanitize_xml(xsd)
61
+ end
62
+
63
+ end
64
+
65
+ context "for a model with attributes" do
66
+
67
+ subject { SomeModel.to_xsd }
68
+
69
+ context "for a any attribute" do
70
+ with_model :some_model do
71
+ table :id => false do |t|
72
+ t.float 'some_float'
73
+ end
74
+ end
75
+
76
+ it "should define the correct xsd element" do
77
+ xsd = generate_xsd_for_model(SomeModel) do
78
+ <<-XML
79
+ <xs:element name="some-float" minOccurs="0" maxOccurs="1">
80
+ <xs:complexType>
81
+ <xs:simpleContent>
82
+ <xs:extension base="xs:float">
83
+ <xs:attribute name="type" type="xs:string" use="optional"/>
84
+ </xs:extension>
85
+ </xs:simpleContent>
86
+ </xs:complexType>
87
+ </xs:element>
88
+ XML
89
+ end
90
+
91
+ subject.should == sanitize_xml(xsd)
92
+ end
93
+
94
+ end
95
+
96
+ describe "additional methods" do
97
+ with_model :some_model do
98
+ table {}
99
+ end
100
+
101
+ it "should include the additional method" do
102
+ xsd = generate_xsd_for_model(SomeModel) do
103
+ <<-XML
104
+ <xs:element name="id" minOccurs="0" maxOccurs="1">
105
+ <xs:complexType>
106
+ <xs:simpleContent>
107
+ <xs:extension base="xs:integer">
108
+ <xs:attribute name="type" type="xs:string" use="optional"/>
109
+ </xs:extension>
110
+ </xs:simpleContent>
111
+ </xs:complexType>
112
+ </xs:element>
113
+ <xs:element name="foo-bar" minOccurs="0" maxOccurs="1"/>
114
+ XML
115
+ end
116
+
117
+ SomeModel.to_xsd(:methods => {:foo_bar => nil}).should == sanitize_xml(xsd)
118
+ end
119
+ end
120
+
121
+ describe "nested attributes" do
122
+
123
+ end
124
+
125
+ end
126
+
127
+ context "with a model with validations" do
128
+ context "presence of validation" do
129
+ context "when allow blank is true" do
130
+
131
+ end
132
+
133
+ context "when allow blank is false" do
134
+ end
135
+ end
136
+
137
+ describe "length validation" do
138
+
139
+ end
140
+
141
+ describe "inclusion validation" do
142
+
143
+ end
144
+ end
145
+ end
146
+
147
+ private
148
+
149
+ def sanitize_xml(xml)
150
+ xml.split("\n").map(&:strip).join("")
151
+ end
152
+
153
+ def generate_xsd_for_model(model)
154
+ <<-XML
155
+ <?xml version="1.0" encoding="UTF-8"?>
156
+ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
157
+ <xs:element name="#{model.xsd_element_collection_name}" type="#{model.xsd_type_collection_name}"/>
158
+ <xs:complexType name="#{model.xsd_type_collection_name}">
159
+ <xs:sequence>
160
+ <xs:element name="#{model.xsd_element_name}" type="#{model.xsd_type_name}" minOccurs="0" maxOccurs="unbounded"/>
161
+ </xs:sequence>
162
+ <xs:attribute name="type" type="xs:string" fixed="array"/>
163
+ </xs:complexType>
164
+ <xs:complexType name="#{model.xsd_type_name}">
165
+ <xs:all>
166
+ #{yield}
167
+ </xs:all>
168
+ </xs:complexType>
169
+ </xs:schema>
170
+ XML
171
+ end
172
+ end
@@ -0,0 +1,9 @@
1
+ require "active_record"
2
+ require "with_model"
3
+ require "schematic"
4
+
5
+ RSpec.configure do |config|
6
+ config.extend WithModel
7
+ end
8
+
9
+ ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ":memory:")
metadata ADDED
@@ -0,0 +1,134 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: schematic
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Case Commons, LLC
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-04-01 00:00:00 -04:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: activerecord
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: 3.0.0
25
+ type: :runtime
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: builder
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: "0"
36
+ type: :runtime
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: rspec-rails
40
+ prerelease: false
41
+ requirement: &id003 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "2.1"
47
+ type: :development
48
+ version_requirements: *id003
49
+ - !ruby/object:Gem::Dependency
50
+ name: with_model
51
+ prerelease: false
52
+ requirement: &id004 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ type: :development
59
+ version_requirements: *id004
60
+ - !ruby/object:Gem::Dependency
61
+ name: nokogiri
62
+ prerelease: false
63
+ requirement: &id005 !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: "0"
69
+ type: :development
70
+ version_requirements: *id005
71
+ - !ruby/object:Gem::Dependency
72
+ name: sqlite3
73
+ prerelease: false
74
+ requirement: &id006 !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: "0"
80
+ type: :development
81
+ version_requirements: *id006
82
+ description: Automatic XSD generation from ActiveRecord models
83
+ email:
84
+ - casecommons-dev@googlegroups.com
85
+ executables: []
86
+
87
+ extensions: []
88
+
89
+ extra_rdoc_files: []
90
+
91
+ files:
92
+ - .gitignore
93
+ - .rvmrc
94
+ - Gemfile
95
+ - LICENSE
96
+ - README.rdoc
97
+ - Rakefile
98
+ - lib/schematic.rb
99
+ - lib/schematic/serializers/xsd.rb
100
+ - lib/schematic/version.rb
101
+ - schematic.gemspec
102
+ - spec/schematic_serializers_xsd_spec.rb
103
+ - spec/spec_helper.rb
104
+ has_rdoc: true
105
+ homepage: https://github.com/Casecommons/schematic
106
+ licenses: []
107
+
108
+ post_install_message:
109
+ rdoc_options: []
110
+
111
+ require_paths:
112
+ - lib
113
+ required_ruby_version: !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: "0"
119
+ required_rubygems_version: !ruby/object:Gem::Requirement
120
+ none: false
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: "0"
125
+ requirements: []
126
+
127
+ rubyforge_project: schematic
128
+ rubygems_version: 1.6.2
129
+ signing_key:
130
+ specification_version: 3
131
+ summary: Automatic XSD generation from ActiveRecord models
132
+ test_files:
133
+ - spec/schematic_serializers_xsd_spec.rb
134
+ - spec/spec_helper.rb