diff --git a/.ruby-version b/.ruby-version index 8bbe6cf..ecd7ee5 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.2 +2.5.8 diff --git a/lib/frodata/schema.rb b/lib/frodata/schema.rb index 4c6cb44..0b34000 100644 --- a/lib/frodata/schema.rb +++ b/lib/frodata/schema.rb @@ -137,7 +137,7 @@ def process_property_from_xml(property_xml) property_type, value_type = property_type.split(/\(|\)/) if property_type == 'Collection' klass = ::FrOData::Properties::Collection - property_options.merge(value_type: value_type) + property_options.merge!(value_type: value_type) else klass = ::FrOData::PropertyRegistry[property_type] end diff --git a/lib/frodata/schema/enum_type.rb b/lib/frodata/schema/enum_type.rb index c3151c3..641028e 100644 --- a/lib/frodata/schema/enum_type.rb +++ b/lib/frodata/schema/enum_type.rb @@ -46,18 +46,23 @@ def namespace # @return [Hash] def members @members ||= collect_members + end + + def annotated_members + @annotated_members ||= collect_annotated_members end # Returns the property class that implements this `EnumType`. # @return [Class < FrOData::Properties::Enum] def property_class - @property_class ||= lambda { |type, members, is_flags| + @property_class ||= lambda { |type, members, annotated_members, is_flags| klass = Class.new ::FrOData::Properties::Enum klass.send(:define_method, :type) { type } klass.send(:define_method, :members) { members } + klass.send(:define_method, :annotated_members) { annotated_members } klass.send(:define_method, :is_flags?) { is_flags } klass - }.call(type, members, is_flags?) + }.call(type, members, annotated_members, is_flags?) end # Returns the value of the requested member. @@ -89,6 +94,18 @@ def collect_members member_value = member_xml.attributes['Value'].andand.value.andand.to_i [member_value || index, member_name] end] + end + + def collect_annotated_members + Hash[type_definition.xpath('./Member').map.with_index do |member_xml, index| + member_name = member_xml.attributes['Name'].value + member_value = member_xml.attributes['Value'].andand.value.andand.to_i + annotation = nil + if member_xml.element_children.count > 0 + annotation = member_xml.element_children.last.attribute('String').value + end + [member_value || index, {name: member_name, annotation: annotation}] + end] end end end diff --git a/spec/fixtures/files/metadata.xml b/spec/fixtures/files/metadata.xml index 25d9e10..0329e24 100644 --- a/spec/fixtures/files/metadata.xml +++ b/spec/fixtures/files/metadata.xml @@ -9,6 +9,8 @@ + + @@ -18,6 +20,22 @@ + + + + + + + + + + + + + + + + diff --git a/spec/frodata/entity/shared_examples.rb b/spec/frodata/entity/shared_examples.rb index 0f9b24c..92f9b91 100644 --- a/spec/frodata/entity/shared_examples.rb +++ b/spec/frodata/entity/shared_examples.rb @@ -15,7 +15,7 @@ it { expect(subject.get_property('ReleaseDate')).to be_a(FrOData::Properties::DateTimeOffset) } it { expect(subject.get_property('DiscontinuedDate')).to be_a(FrOData::Properties::DateTimeOffset) } it { expect(subject.get_property('Rating')).to be_a(FrOData::Properties::Integer) } - it { expect(subject.get_property('Price')).to be_a(FrOData::Properties::Double) } + it { expect(subject.get_property('Price')).to be_a(FrOData::Properties::Float) } # Navigation property proxies it { expect(subject.get_property('Categories')).to be_a(FrOData::NavigationProperty::Proxy)} diff --git a/spec/frodata/property_collection_spec.rb b/spec/frodata/property_collection_spec.rb new file mode 100644 index 0000000..80149f4 --- /dev/null +++ b/spec/frodata/property_collection_spec.rb @@ -0,0 +1,18 @@ +require 'spec_helper' + +describe FrOData::Property do + let(:service) do + FrOData::Service.new('http://services.odata.org/V4/OData/OData.svc', metadata_file: metadata_file) + end + let(:metadata_file) { 'spec/fixtures/files/metadata.xml' } + + describe '#type' do + it 'returns the right type' do + t = service.schemas['ODataDemo'].properties_for_entity('Product')['ProductStatus'].type + expect(t).to eq('ODataDemo.ProductStatus') + + t = service.schemas['ODataDemo'].properties_for_entity('Product')['EthicalAttributes'].type + expect(t).to eq('Collection(ODataDemo.EthicalAttribute)') + end + end +end diff --git a/spec/frodata/schema/annotated_enum_type_spec.rb b/spec/frodata/schema/annotated_enum_type_spec.rb new file mode 100644 index 0000000..967a123 --- /dev/null +++ b/spec/frodata/schema/annotated_enum_type_spec.rb @@ -0,0 +1,37 @@ +require 'spec_helper' + +describe FrOData::Schema::EnumType, vcr: {cassette_name: 'schema/enum_type_specs'} do + before(:example) do + FrOData::Service.new('http://services.odata.org/V4/OData/OData.svc', name: 'ODataDemo', metadata_file: metadata_file) + end + + let(:metadata_file) { 'spec/fixtures/files/metadata.xml' } + let(:service) { FrOData::ServiceRegistry['ODataDemo'] } + + let(:enum_type) { service.enum_types['ODataDemo.Vertical'] } + let(:subject) { enum_type.property_class.new('Vertical', nil) } + + describe 'is properly parsed from service metadata' do + it { expect(enum_type.name).to eq('Vertical') } + it { expect(enum_type.namespace).to eq('ODataDemo') } + it { expect(enum_type.type).to eq('ODataDemo.Vertical') } + it { expect(enum_type.is_flags?).to eq(false) } + it { expect(enum_type.underlying_type).to eq('Edm.Int64') } + it { expect(enum_type.members.values).to eq(%w{OutdoorsAndNature HomeAndOffice}) } + it { + expect(enum_type.annotated_members).to eq({ + 1 => { name: 'OutdoorsAndNature', annotation: 'Outdoor and Nature Products' }, + 2 => { name: 'HomeAndOffice', annotation: 'Home and Office Products' } + }) + } + end + + # Check property instance inheritance hierarchy + it { expect(subject).to be_a(FrOData::Property) } + it { expect(subject).to be_a(FrOData::Properties::Enum) } + + it { expect(subject).to respond_to(:name) } + it { expect(subject).to respond_to(:type) } + it { expect(subject).to respond_to(:members) } + +end diff --git a/spec/frodata/schema_spec.rb b/spec/frodata/schema_spec.rb index 6f592ed..8eac1ab 100644 --- a/spec/frodata/schema_spec.rb +++ b/spec/frodata/schema_spec.rb @@ -10,7 +10,7 @@ let(:entity_types) { %w{Product FeaturedProduct ProductDetail Category Supplier Person Customer Employee PersonDetail Advertisement} } let(:complex_types) { %w{Address} } - let(:enum_types) { %w{ProductStatus} } + let(:enum_types) { %w{Vertical EthicalAttribute ProductStatus} } describe '#namespace' do it { expect(subject).to respond_to(:namespace) } @@ -43,7 +43,7 @@ describe '#enum_types' do it { expect(subject).to respond_to(:enum_types) } - it { expect(subject.enum_types.size).to eq(1) } + it { expect(subject.enum_types.size).to eq(3) } it { expect(subject.enum_types.keys).to eq(enum_types)} end diff --git a/spec/frodata/service_spec.rb b/spec/frodata/service_spec.rb index c6a294d..7de7f6e 100644 --- a/spec/frodata/service_spec.rb +++ b/spec/frodata/service_spec.rb @@ -159,8 +159,8 @@ describe '#enum_types' do it { expect(subject).to respond_to(:enum_types) } - it { expect(subject.enum_types.size).to eq(1) } - it { expect(subject.enum_types.keys).to eq(['ODataDemo.ProductStatus'])} + it { expect(subject.enum_types.size).to eq(3) } + it { expect(subject.enum_types.keys).to eq(['ODataDemo.Vertical', 'ODataDemo.EthicalAttribute', 'ODataDemo.ProductStatus'])} end describe '#namespace' do @@ -190,6 +190,8 @@ ID Name Description + Vertical + EthicalAttributes ReleaseDate DiscontinuedDate Rating