building_sync_rails 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +32 -0
- data/README.rdoc +3 -0
- data/Rakefile +37 -0
- data/WARRANTY.txt +22 -0
- data/app/assets/config/manifest.js +3 -0
- data/bin/rails +12 -0
- data/config/initializers/BuildingSync_initializer.rb +11 -0
- data/config/initializers/soap4r_ns_fix.rb +55 -0
- data/config/initializers/soap4r_xsd_datatypes_fix.rb +28 -0
- data/config/routes.rb +2 -0
- data/lib/BuildingSync.rb +33688 -0
- data/lib/BuildingSync_mapper.rb +8 -0
- data/lib/BuildingSync_mapping_registry.rb +15362 -0
- data/lib/building_sync_rails/engine.rb +15 -0
- data/lib/building_sync_rails/version.rb +3 -0
- data/lib/building_sync_rails.rb +5 -0
- data/lib/building_sync_tk/factory.rb +186 -0
- data/lib/building_sync_tk/inflector.rb +27 -0
- data/lib/building_sync_tk/memoization.rb +50 -0
- data/lib/building_sync_tk/model.rb +37 -0
- data/lib/building_sync_tk/version.rb +3 -0
- data/lib/building_sync_tk.rb +12 -0
- data/lib/tasks/building_sync_rails_tasks.rake +157 -0
- data/public/BuildingSync.xsd +16859 -0
- data/public/GreenBuildingXML_Ver6.01.xsd +7113 -0
- data/test/building_sync_rails_test.rb +7 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/config/manifest.js +3 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +29 -0
- data/test/dummy/config/application.rb +25 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +41 -0
- data/test/dummy/config/environments/production.rb +79 -0
- data/test/dummy/config/environments/test.rb +42 -0
- data/test/dummy/config/initializers/assets.rb +11 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/to_time_preserves_timezone.rb +10 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +3 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/log/development.log +24 -0
- data/test/dummy/log/test.log +48 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/integration/navigation_test.rb +8 -0
- data/test/test_helper.rb +21 -0
- metadata +226 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
module BuildingSyncRails
|
2
|
+
class Engine < ::Rails::Engine
|
3
|
+
config.to_prepare do
|
4
|
+
require_relative "../../config/initializers/BuildingSync_initializer.rb"
|
5
|
+
require_relative "../../config/initializers/soap4r_ns_fix.rb"
|
6
|
+
require_relative "../../config/initializers/soap4r_xsd_datatypes_fix.rb"
|
7
|
+
|
8
|
+
require_relative "../../lib/building_sync_tk.rb"
|
9
|
+
end
|
10
|
+
|
11
|
+
# initializer "static" do |app|
|
12
|
+
# app.middleware.insert_before(::ActionDispatch::Static, ::ActionDispatch::Static, ::File.join(root, "public"))
|
13
|
+
# end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
require "isomorphic/factory"
|
2
|
+
|
3
|
+
module BuildingSyncTk
|
4
|
+
# An Isomorphic factory that is specialized for the {BuildingSync} base module.
|
5
|
+
class Factory < ::Isomorphic::Factory::AbstractFactory
|
6
|
+
# @!scope class
|
7
|
+
|
8
|
+
# @!method instance
|
9
|
+
# @return [BuildingSyncTk::Factory] the singleton instance
|
10
|
+
include ::Singleton
|
11
|
+
|
12
|
+
# @!scope instance
|
13
|
+
|
14
|
+
# Private constructor.
|
15
|
+
def initialize
|
16
|
+
super(::BuildingSync)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Get +<auc:UserDefinedFields>+ for the given object.
|
20
|
+
#
|
21
|
+
# @param object [#userDefinedFields] the object
|
22
|
+
# @return [Hash<String, Array<String>>, nil] the key-value pairs as a hash or +nil+ if the given object is invalid
|
23
|
+
#
|
24
|
+
# @note The return value is a hash of arrays (not a hash) because +<auc:FieldName>+ elements are not guaranteed unique within the +<auc:UserDefinedFields>+ element.
|
25
|
+
def get_user_defined_fields(object)
|
26
|
+
object.try(:userDefinedFields).try { |building_sync_user_defined_fields|
|
27
|
+
if building_sync_user_defined_fields.is_a?(::BuildingSync::UserDefinedFields)
|
28
|
+
building_sync_user_defined_fields.inject({}) { |acc, building_sync_user_defined_fields_user_defined_field|
|
29
|
+
if building_sync_user_defined_fields_user_defined_field.is_a?(::BuildingSync::UserDefinedFields::UserDefinedField)
|
30
|
+
building_sync_user_defined_fields_user_defined_field.send(:fieldName).try(:to_s).try { |key|
|
31
|
+
building_sync_user_defined_fields_user_defined_field.send(:fieldValue).try(:to_s).try { |value|
|
32
|
+
acc[key] ||= []
|
33
|
+
acc[key] << value
|
34
|
+
}
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
acc
|
39
|
+
}
|
40
|
+
else
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
# Build an instance of the given class that represents a "link" to the given target.
|
47
|
+
#
|
48
|
+
# In BuildingSync XML, a "link" is an element with an +@IDref+ attribute. The value of the +@IDref+ attribute is the value of the +@ID+ attribute of another element.
|
49
|
+
#
|
50
|
+
# @param instance_class [Class] the class for the "link"
|
51
|
+
# @param target_instance [#xmlattr_ID] the target instance
|
52
|
+
# @param options [Hash<#to_sym, Object>] the options
|
53
|
+
# @option options [Hash<#to_sym, Object>] :attributes ({}) the attributes for the "link"
|
54
|
+
# @option options [Hash<#to_sym, #to_s>] :xmlattrs ({}) the XML attributes for the "link"
|
55
|
+
# @yieldparam instance [Object] the "link"
|
56
|
+
# @yieldreturn [void]
|
57
|
+
# @return [Object] the "link"
|
58
|
+
# @raise [Isomorphic::InvalidFactoryClass] if the given class is invalid
|
59
|
+
def link(instance_class, target_instance, **options, &block)
|
60
|
+
send(:for, instance_class, **options.merge({
|
61
|
+
attributes: (options[:attributes] || {}).merge({
|
62
|
+
xmlattr_IDref: target_instance.send(:xmlattr_ID),
|
63
|
+
}),
|
64
|
+
}), &block)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Build an instance of the given class that represents a "link" from the given source to the given target, and then assign the "link" to the source using the given method name.
|
68
|
+
#
|
69
|
+
# @param instance_method_name [#to_s] the method name
|
70
|
+
# @param instance_class [Class] the class for the "link"
|
71
|
+
# @param source_instance [#xmlattr_ID] the source instance
|
72
|
+
# @param target_instance [#xmlattr_ID] the target instance
|
73
|
+
# @param options [Hash<#to_sym, Object>] the options
|
74
|
+
# @option options [Hash<#to_sym, Object>] :attributes ({}) the attributes for the "link"
|
75
|
+
# @option options [Hash<#to_sym, #to_s>] :xmlattrs ({}) the XML attributes for the "link"
|
76
|
+
# @yieldparam instance [Object] the "link"
|
77
|
+
# @yieldreturn [void]
|
78
|
+
# @return [Object] the "link"
|
79
|
+
# @raise [Isomorphic::InvalidFactoryClass] if the given class is invalid
|
80
|
+
def link_to(instance_method_name, instance_class, source_instance, target_instance, **options, &block)
|
81
|
+
source_instance.send(:"#{instance_method_name}=", send(:link, instance_class, target_instance, **options, &block))
|
82
|
+
end
|
83
|
+
|
84
|
+
# Build an instance of the given class that represents a "link" from the given source to the given target, and then append the "link" to the "collection of links" for the source using the given method name.
|
85
|
+
#
|
86
|
+
# @param collection_method_name [#to_s] the method name
|
87
|
+
# @param collection_class [Class] the class for the "link"
|
88
|
+
# @param instance_class [Class] the class for the "link"
|
89
|
+
# @param source_instance [#xmlattr_ID] the source instance
|
90
|
+
# @param target_instance [#xmlattr_ID] the target instance
|
91
|
+
# @param options [Hash<#to_sym, Object>] the options
|
92
|
+
# @option options [Hash<#to_sym, Object>] :attributes ({}) the attributes for the "link"
|
93
|
+
# @option options [Hash<#to_sym, #to_s>] :xmlattrs ({}) the XML attributes for the "link"
|
94
|
+
# @yieldparam instance [Object] the "link"
|
95
|
+
# @yieldreturn [void]
|
96
|
+
# @return [Object] the "link"
|
97
|
+
# @raise [Isomorphic::InvalidFactoryClass] if the given class is invalid
|
98
|
+
def link_to_collection(collection_method_name, collection_class, instance_class, source_instance, target_instance, **options, &block)
|
99
|
+
collection = source_instance.send(collection_method_name) || source_instance.send(:"#{collection_method_name}=", send(:for, collection_class))
|
100
|
+
|
101
|
+
unless (instance = collection.select { |instance| instance.send(:xmlattr_IDref) == target_instance.send(:xmlattr_ID) }.first).nil?
|
102
|
+
instance
|
103
|
+
else
|
104
|
+
instance = send(:link, instance_class, target_instance, **options, &block)
|
105
|
+
|
106
|
+
collection << instance
|
107
|
+
|
108
|
+
instance
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Set +<auc:UserDefinedFields>+ for the given object.
|
113
|
+
#
|
114
|
+
# @param object [#userDefinedFields] the object
|
115
|
+
# @param hash [Hash<String, String>, nil] the key-value pairs
|
116
|
+
# @return [BuildingSync::UserDefinedFields] the +<auc:UserDefinedFields>+ instance
|
117
|
+
def set_user_defined_fields(object, hash = {})
|
118
|
+
hash.each do |key, value|
|
119
|
+
unless user_defined_field?(object, key, value)
|
120
|
+
send(:path, object, :userDefinedFields) << send(:for, ::BuildingSync::UserDefinedFields::UserDefinedField, attributes: {
|
121
|
+
fieldName: key.to_s,
|
122
|
+
fieldValue: value.to_s
|
123
|
+
})
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
object.send(:userDefinedFields)
|
128
|
+
end
|
129
|
+
|
130
|
+
# Is a +<auc:UserDefinedField>+ present with the given key-value pair?
|
131
|
+
#
|
132
|
+
# @param object [#userDefinedFields] the object
|
133
|
+
# @param key [#to_s] the key
|
134
|
+
# @param value [#to_s] the value
|
135
|
+
# @return [Boolean] +true+ if the given key-value pair is present; otherwise, +false+
|
136
|
+
def user_defined_field?(object, key, value)
|
137
|
+
return false if key.nil? || value.nil?
|
138
|
+
|
139
|
+
send(:path, object, :userDefinedFields, try: true).try(:any?) { |building_sync_user_defined_fields_user_defined_field|
|
140
|
+
building_sync_user_defined_fields_user_defined_field.is_a?(::BuildingSync::UserDefinedFields::UserDefinedField) && building_sync_user_defined_fields_user_defined_field.send(:fieldName).try(:to_s).try(:==, key.to_s) && building_sync_user_defined_fields_user_defined_field.send(:fieldValue).try(:to_s).try(:==, value.to_s)
|
141
|
+
}
|
142
|
+
end
|
143
|
+
|
144
|
+
# The XML attribute names.
|
145
|
+
#
|
146
|
+
# @return [Array<#to_sym>] the XML attribute names
|
147
|
+
#
|
148
|
+
# @note In BuildingSync XML, elements may have an +@ID+ attribute.
|
149
|
+
# @see #xmlattr_ID_for
|
150
|
+
def xmlattrs
|
151
|
+
%w(ID)
|
152
|
+
end
|
153
|
+
|
154
|
+
protected
|
155
|
+
|
156
|
+
# Checks for a constant with the given name in the base module.
|
157
|
+
#
|
158
|
+
# @param base [Module] the base module
|
159
|
+
# @param klass [Class] the class
|
160
|
+
# @param const_name [#to_sym] the constant name
|
161
|
+
# @return [Class, Module, nil] the constant with the given name or +nil+ if not defined
|
162
|
+
#
|
163
|
+
# @note In BuildingSync XML, the constant may be of the given class, of the base module, or of the base module with the "Type" suffix.
|
164
|
+
def const_get(base, klass, const_name)
|
165
|
+
if klass.const_defined?(const_name)
|
166
|
+
klass.const_get(const_name)
|
167
|
+
elsif base.const_defined?(const_name)
|
168
|
+
base.const_get(const_name)
|
169
|
+
elsif base.const_defined?(:"#{const_name}Type")
|
170
|
+
base.const_get(:"#{const_name}Type")
|
171
|
+
else
|
172
|
+
nil
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# Builds the value of the +@ID+ attribute for the given object.
|
177
|
+
#
|
178
|
+
# @param object [Object] the object
|
179
|
+
# @return [String] the value of the +@ID+ attribute
|
180
|
+
#
|
181
|
+
# @note Using the {Object#object_id} ensures that the return value is unique.
|
182
|
+
def xmlattr_ID_for(object)
|
183
|
+
"#{object.class.name.split("::")[-1]}-#{object.object_id}"
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "isomorphic/inflector"
|
2
|
+
|
3
|
+
module BuildingSyncTk
|
4
|
+
# An Isomorphic inflector that is specialized for the {BuildingSync} base module.
|
5
|
+
class Inflector < ::Isomorphic::Inflector::AbstractInflector
|
6
|
+
# @!scope class
|
7
|
+
|
8
|
+
# @!method instance
|
9
|
+
# @return [BuildingSyncTk::Inflector] the singleton instance
|
10
|
+
include ::Singleton
|
11
|
+
|
12
|
+
# @!scope instance
|
13
|
+
|
14
|
+
# Private constructor.
|
15
|
+
def initialize
|
16
|
+
super(::BuildingSync)
|
17
|
+
end
|
18
|
+
|
19
|
+
# @!method building_sync
|
20
|
+
# Inflect upon the given terms. Alias for {#isomorphism}.
|
21
|
+
#
|
22
|
+
# @param terms [Array<Object>] the inflectable terms
|
23
|
+
# @return [String] the inflection
|
24
|
+
# @raise [Isomorphic::InflectorError] if an inflectable term is invalid
|
25
|
+
alias_method :building_sync, :isomorphism
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require "building_sync_tk/inflector"
|
2
|
+
|
3
|
+
require "isomorphic/memoization"
|
4
|
+
|
5
|
+
module BuildingSyncTk
|
6
|
+
# @see Isomorphic::Memoization
|
7
|
+
module Memoization
|
8
|
+
extend ::ActiveSupport::Concern
|
9
|
+
|
10
|
+
included do
|
11
|
+
include ::Isomorphic::Memoization
|
12
|
+
end
|
13
|
+
|
14
|
+
class_methods do
|
15
|
+
# @!scope class
|
16
|
+
|
17
|
+
# Defines finder methods and instance variables for the Active Record associations given by name.
|
18
|
+
#
|
19
|
+
# @param terms [Array<Object>] the inflectable terms
|
20
|
+
# @param association_names [Array<#to_s>] the association names
|
21
|
+
# @param options [Hash<Symbol, Object>] the options
|
22
|
+
# @option options [Array<#to_s>] :xmlattrs ([]) the XML attribute names
|
23
|
+
# @return [void]
|
24
|
+
# @raise [Isomorphic::InflectorError] if an inflectable term is invalid
|
25
|
+
def memo_building_sync_for(*args)
|
26
|
+
memo_isomorphism_for(BuildingSyncTk::Inflector.instance, *args, xmlattrs: BuildingSyncTk::Factory.instance.xmlattrs)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns the memo-cahe.
|
30
|
+
#
|
31
|
+
# @return [Hash<Module, ActiveSupport::HashWithIndifferentAccess>] the memo-cache
|
32
|
+
def memo_building_sync_method_names_by_association_name
|
33
|
+
memo_isomorphism_method_names_by_association_name_for(BuildingSyncTk::Inflector.instance.base)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# @!scope instance
|
38
|
+
|
39
|
+
# Find all memoized instances for the given Active Record record by XML attribute name.
|
40
|
+
#
|
41
|
+
# @param record [ActiveRecord::Base] the Active Record record
|
42
|
+
# @param options [Hash<Symbol, Object>] the options
|
43
|
+
# @option options [Array<#to_s>] :xmlattrs ([]) the XML attribute names
|
44
|
+
# @return [ActiveSupport::HashWithIndifferentAccess] the memoized instances by XML attribute name
|
45
|
+
# @raise [Isomorphic::InflectorError] if an inflectable term is invalid
|
46
|
+
def find_all_with_memo_building_sync_for(*args)
|
47
|
+
find_all_with_memo_isomorphism_for(BuildingSyncTk::Inflector.instance, *args, xmlattrs: BuildingSyncTk::Factory.instance.xmlattrs)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "active_support/concern"
|
2
|
+
|
3
|
+
require "building_sync_tk/factory"
|
4
|
+
require "building_sync_tk/inflector"
|
5
|
+
|
6
|
+
require "isomorphic/model"
|
7
|
+
|
8
|
+
module BuildingSyncTk
|
9
|
+
# @see Isomorphic::Model
|
10
|
+
module Model
|
11
|
+
extend ::ActiveSupport::Concern
|
12
|
+
|
13
|
+
included do
|
14
|
+
include ::Isomorphic::Model
|
15
|
+
end
|
16
|
+
|
17
|
+
class_methods do
|
18
|
+
# @!scope class
|
19
|
+
|
20
|
+
# Define an isomorphism for the given class and optional alias name.
|
21
|
+
#
|
22
|
+
# @param isomorphism_class [Class] the class for the isomorphism
|
23
|
+
# @param method_suffix [#to_s] the optional alias name for the isomorphism
|
24
|
+
# @param options [Hash<Symbol, Object>] the options
|
25
|
+
# @option options [Boolean] :allow_blank (false) +true+ if the root node should always return a non-+nil+ target
|
26
|
+
# @option options [Hash<Symbol, Object>] :attributes ({}) default attributes for the target
|
27
|
+
# @option options [Boolean] :collection (false) +true+ if the target is a collection
|
28
|
+
# @yieldparam node [Isomorphic::Node::Root] the root node
|
29
|
+
# @yieldreturn [void]
|
30
|
+
# @return [void]
|
31
|
+
# @raise [Isomorphic::InflectorError] if an inflectable term is invalid
|
32
|
+
def building_sync_for(*args, &block)
|
33
|
+
isomorphism_for(BuildingSyncTk::Factory.instance, BuildingSyncTk::Inflector.instance, *args, &block)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require "active_support/dependencies/autoload"
|
2
|
+
|
3
|
+
require "building_sync_tk/version"
|
4
|
+
|
5
|
+
module BuildingSyncTk
|
6
|
+
extend ::ActiveSupport::Autoload
|
7
|
+
|
8
|
+
autoload :Factory, "building_sync_tk/factory"
|
9
|
+
autoload :Inflector, "building_sync_tk/inflector"
|
10
|
+
autoload :Memoization, "building_sync_tk/memoization"
|
11
|
+
autoload :Model, "building_sync_tk/model"
|
12
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
require "open-uri"
|
3
|
+
require "set"
|
4
|
+
|
5
|
+
# @return [String] the format string for an XML Schema Definition (XSD) import element
|
6
|
+
FORMAT_XSD_IMPORT_ = '<%s:import namespace="%s" schemaLocation="%s"/>'.freeze
|
7
|
+
|
8
|
+
# @return [Regexp] the regular expression for an XML Schema Definition (XSD) import element
|
9
|
+
REGEXP_XSD_IMPORT_ = ::Regexp.new([
|
10
|
+
::Regexp.escape('<'),
|
11
|
+
'([^:]+)',
|
12
|
+
::Regexp.escape(':import'),
|
13
|
+
'\s+',
|
14
|
+
::Regexp.escape('namespace="'),
|
15
|
+
'([^"]+)',
|
16
|
+
::Regexp.escape('"'),
|
17
|
+
'\s+',
|
18
|
+
::Regexp.escape('schemaLocation="'),
|
19
|
+
'([^"]+)',
|
20
|
+
::Regexp.escape('"'),
|
21
|
+
'\s*',
|
22
|
+
::Regexp.escape('/>'),
|
23
|
+
].join).freeze
|
24
|
+
|
25
|
+
# Download an XML Schema Definition (XSD) file and recursively download its dependencies.
|
26
|
+
#
|
27
|
+
# @param url [String] the URL of the XML Schema Definition (XSD) file to download
|
28
|
+
# @param verbose [Boolean] specifies the verbosity level
|
29
|
+
# @param cached_urls [Set<String>] the cache of URLs that have been downloaded
|
30
|
+
# @return [void]
|
31
|
+
def download_schema_recursive(url, verbose = true, cached_urls = ::Set.new)
|
32
|
+
if cached_urls.include?(url)
|
33
|
+
return
|
34
|
+
else
|
35
|
+
cached_urls << url
|
36
|
+
end
|
37
|
+
|
38
|
+
$stderr.puts(::Kernel.sprintf("** Download %s", url)) if verbose
|
39
|
+
|
40
|
+
s = ::URI.parse(url).open do |io|
|
41
|
+
io.read.gsub(REGEXP_XSD_IMPORT_) { |match_s|
|
42
|
+
prefix = ::Regexp.last_match[1]
|
43
|
+
namespace = ::Regexp.last_match[2]
|
44
|
+
schema_location = ::Regexp.last_match[3]
|
45
|
+
|
46
|
+
download_schema_recursive(schema_location, verbose, cached_urls)
|
47
|
+
|
48
|
+
# @note Replace the URL with the path on the local disk.
|
49
|
+
::Kernel.sprintf(FORMAT_XSD_IMPORT_, prefix, namespace, schema_location.split(::File::SEPARATOR)[-1])
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
# @note Open the new file in binary mode to avoid character encoding issues.
|
54
|
+
::File.open(::File.join("public", url.split(::File::SEPARATOR)[-1]), "wb") do |io|
|
55
|
+
io.puts(s)
|
56
|
+
end
|
57
|
+
|
58
|
+
return
|
59
|
+
end
|
60
|
+
|
61
|
+
namespace :building_sync_rails do
|
62
|
+
desc "Use BuildingSync XSD file to generate Ruby code via `xsd2ruby.rb` script."
|
63
|
+
task :xsd2ruby => :environment do
|
64
|
+
# @!attribute [r] uri_xsd_remote
|
65
|
+
# @return [String] the location of the BuildingSync XSD file on the remote nework
|
66
|
+
uri_xsd_remote = "https://github.com/BuildingSync/schema/raw/develop-v2/BuildingSync.xsd"
|
67
|
+
|
68
|
+
# @!attribute [r] options_by_local_name
|
69
|
+
# @return [Hash<String, Hash<Symbol, Array<Hash<Symbol, Object>>>>] the options by the local name of each Ruby source file
|
70
|
+
# @note Ruby source files are auto-generated by the "soap4r" gem. This data structure contains the information that is used to sanitize the auto-generated code, making it suitable for revision management.
|
71
|
+
options_by_local_name = {
|
72
|
+
"BuildingSync.rb" => {
|
73
|
+
delete_at: [
|
74
|
+
{
|
75
|
+
index: 4,
|
76
|
+
count: 2,
|
77
|
+
},
|
78
|
+
{
|
79
|
+
index: -2,
|
80
|
+
count: 2,
|
81
|
+
},
|
82
|
+
],
|
83
|
+
indent_at: [
|
84
|
+
{
|
85
|
+
first_index: 4,
|
86
|
+
last_index: -2,
|
87
|
+
count: 1,
|
88
|
+
separator: ' ',
|
89
|
+
},
|
90
|
+
],
|
91
|
+
},
|
92
|
+
"BuildingSync_mapper.rb" => {
|
93
|
+
delete_at: [
|
94
|
+
{
|
95
|
+
index: 3,
|
96
|
+
count: 2,
|
97
|
+
},
|
98
|
+
{
|
99
|
+
index: -2,
|
100
|
+
count: 2,
|
101
|
+
},
|
102
|
+
],
|
103
|
+
indent_at: [],
|
104
|
+
},
|
105
|
+
"BuildingSync_mapping_registry.rb" => {
|
106
|
+
delete_at: [
|
107
|
+
{
|
108
|
+
index: 3,
|
109
|
+
count: 2,
|
110
|
+
},
|
111
|
+
{
|
112
|
+
index: -2,
|
113
|
+
count: 2,
|
114
|
+
},
|
115
|
+
],
|
116
|
+
indent_at: [],
|
117
|
+
},
|
118
|
+
}
|
119
|
+
|
120
|
+
# @note Download the BuildingSync XSD file from the remote network and copy to the local disk.
|
121
|
+
download_schema_recursive(uri_xsd_remote, verbose)
|
122
|
+
|
123
|
+
# @note Execute the "xsd2ruby.rb" binary that is installed by the "soap4r" gem. The Ruby source files are created in the "/" directory.
|
124
|
+
::Bundler.with_clean_env do
|
125
|
+
`xsd2ruby.rb --xsd #{::File.join("public", uri_xsd_remote.split(::File::SEPARATOR)[-1])} --module_path "BuildingSync" --classdef "BuildingSync" --mapping_registry --mapper --force --quiet`
|
126
|
+
end
|
127
|
+
|
128
|
+
# @note Sanitize the contents of each Ruby source file.
|
129
|
+
options_by_local_name.each do |local_name, options|
|
130
|
+
s = ::File.open(local_name, "r") do |file|
|
131
|
+
array = file.read.split($/)
|
132
|
+
|
133
|
+
options[:delete_at].each do |hash|
|
134
|
+
hash[:count].times { array.delete_at(hash[:index]) }
|
135
|
+
end
|
136
|
+
|
137
|
+
options[:indent_at].each do |hash|
|
138
|
+
array[::Range.new(hash[:first_index], hash[:last_index], false)].each do |s|
|
139
|
+
s.gsub!(::Regexp.new("^(.*?)$"), ::Kernel.sprintf('%s\1', ::Array.new(hash[:count], hash[:separator]).join("")))
|
140
|
+
s.rstrip!
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
array.join($/)
|
145
|
+
end
|
146
|
+
|
147
|
+
::File.open(local_name, "w") do |file|
|
148
|
+
file.puts(s)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# @note Move the Ruby source files to the "lib/" directory.
|
153
|
+
options_by_local_name.keys.each do |local_name|
|
154
|
+
::FileUtils.mv(local_name, ::File.join("lib", local_name)) if ::File.exist?(local_name)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|