Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Applying all recent changes

  • Loading branch information...
commit c3c3e24fcdbb6eb0aab6d9c48c5758972e80e03c 1 parent 6faca91
DanielVartanov authored
View
0  .gitmodules
No changes.
View
4 README.textile
@@ -196,5 +196,5 @@ Then,
<i>without any changes in the controller code!</i>
-Copyright 2010 Sage
-acts_as_sdata is licensed by Sage under the "Apache License, Version 2.0":http://www.apache.org/licenses/LICENSE-2.0.html
+Copyright Sage 2009
+Released under the MIT license
View
27 Rakefile
@@ -3,21 +3,18 @@ require 'rake'
begin
require 'jeweler'
- PKG_FILES = FileList[ '[a-zA-Z]*', 'lib/**/*', 'spec/**/*' ]
- Jeweler::Tasks.new do |s|
- s.name = "acts_as_sdata"
- s.version = "0.0.1"
- s.authors = ["Daniel Vartanov"]
- s.email = "dan@vartanov.net"
- s.homepage = "http://sdata.sage.com/"
- s.platform = Gem::Platform::RUBY
- s.description = s.summary = "Ruby implementation of SData (Sage Data) protocol"
- s.files = PKG_FILES.to_a
- s.require_path = "lib"
- s.has_rdoc = false
- s.extra_rdoc_files = ["README.textile"]
+ Jeweler::Tasks.new do |gemspec|
+ gemspec.name = "acts_as_sdata"
+ gemspec.version = '1.0.0'
+ gemspec.authors = ["Daniel Vartanov", "Eugene Gilburg", "Michael Johnston"].sort
+ gemspec.email = "dan@vartanov.net"
+ gemspec.homepage = "http://sdata.sage.com/"
+ gemspec.summary = gemspec.description = "Ruby implementation of SData (Sage Data) protocol"
+ gemspec.has_rdoc = false
+ gemspec.extra_rdoc_files = ["README.textile"]
end
- Jeweler::GemcutterTasks.new
+
+ Jeweler::GemcutterTasks.new
rescue LoadError
- puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
+ puts "Jeweler not available. Install it with: gem install jeweler"
end
View
2  VERSION
@@ -1 +1 @@
-1.0.0
+0.0.1
View
93 lib/active_record_mixin.rb
@@ -1,93 +0,0 @@
-module SData
- module ActiveRecordMixin
- def acts_as_sdata(options={})
- cattr_accessor :sdata_options
- self.sdata_options = options
- self.__send__ :include, InstanceMethods
- end
-
- def find_by_sdata_instance_id(value)
- attribute = self.sdata_options[:instance_id]
-
- attribute.nil? ?
- self.find(value.to_i) :
- self.first(:conditions => { attribute => value })
- end
-
- module InstanceMethods
- def to_atom(params=nil)
- params ||= {}
- maximum_precedence = (!params[:precedence].blank? ? params[:precedence].to_i : 100)
- included = params[:include].to_s.split(',')
- selected = params[:select].to_s.split(',') + ['_root']
- expand = (included.include?('$children') ? :all_children : :immediate_children)
- returning Atom::Entry.new do |entry|
- entry.id = self.sdata_resource_url
- entry.title = entry_title
- entry.updated = self.updated_at
- entry.authors << Atom::Person.new(:name => self.respond_to?('author') ? self.author : sdata_default_author)
- entry.links << Atom::Link.new(:rel => 'self',
- :href => self.sdata_resource_url,
- :type => 'applicaton/atom+xml; type=entry',
- :title => 'Refresh')
- entry.categories << Atom::Category.new(:scheme => 'http://schemas.sage.com/sdata/categories',
- :term => 'resource',
- :label => 'Resource')
- if maximum_precedence > 0
- begin
- entry.payload = Atom::Content::Payload.new(Payload.generate(self.sdata_node_name, self, expand, included, selected, 1, maximum_precedence, nil))
- rescue Exception => e
- entry.diagnosis = Atom::Content::Diagnosis.new(ApplicationDiagnosis.new(:exception => e).to_xml(:entry))
- end
- end
- entry.content = sdata_content
- end
- end
-
- def sdata_node_name(entity=self.class)
- entity.to_s.demodulize.camelize(:lower)
- end
-
- def resource_header_attributes(resource, included)
- hash = {}
- hash.merge!({"xlmns:sdata:key" => resource.id, "xlmns:sdata:url" => resource.sdata_resource_url}) if resource.id
- hash.merge!("xlmns:sdata:descriptor" => resource.entry_content) if included.include?("$descriptor")
- hash.merge!("xlmns:sdata:uuid" => resource.uuid.to_s) if resource.respond_to?("uuid") && !resource.uuid.blank?
- hash
- end
-
- def sdata_resource_url
- $APPLICATION_URL + $SDATA_STORE_PATH + sdata_node_name.pluralize + "('#{self.id}')"
- end
-
- protected
-
- def sdata_default_author
- "Billing Boss"
- end
-
- def entry_title
- title_proc = self.class.sdata_options[:title]
- title_proc ? instance_eval(&title_proc) : default_entity_title
- end
-
- def default_entity_title
- "#{self.class.name.demodulize.titleize} #{id}"
- end
-
- def entry_content
- content_proc = self.class.sdata_options[:content]
- content_proc ? instance_eval(&content_proc) : default_entry_content
- end
-
- def default_entry_content
- self.class.name
- end
-
- end
- end
-end
-# Extension of ActiveRecord removed due to refactoring. Now VirtualBase is extended instead.
-# Not sure yet if there is a case where we DO need to extend ActiveRecord directly.
-# Might considering merging those two classes otherwise.
-# RADAR: Tested refactoring, but it could still be buggy if I missed something! Watch out.
View
20 lib/atom_content_mixin.rb
@@ -1,20 +0,0 @@
-module SData
- module AtomContentMixin
- class Payload < Atom::Content::Base
- attribute :type, :'xml:lang'
- def to_xml(*params)
- node = XML::Node.new("sdata:payload")
- p = XML::Parser.string(to_s)
- content = p.parse.root.copy(true)
- node << content
- node
- end
- end
- class Diagnosis < Payload
- def to_xml(*params)
- self[0] #magic done in diagnosis.rb
- end
- end
- end
-end
-Atom::Content.__send__ :include, SData::AtomContentMixin
View
20 lib/atom_entry_mixin.rb
@@ -1,20 +0,0 @@
-
-module SData
- module AtomEntryMixin
- Atom::Entry.element :payload, :class => Atom::Content
- Atom::Entry.element :diagnosis, :class => Atom::Content
- def self.included(base)
- base.send :attr_accessor
- end
-
- def to_attributes
- attributes = {}
- self['http://sdata.sage.com/schemes/attributes'].each_pair do |name, values|
- attributes[name] = values.first
- end
- attributes
- end
- end
-end
-
-Atom::Entry.__send__ :include, SData::AtomEntryMixin
View
59 lib/conditions_builder.rb
@@ -1,59 +0,0 @@
-module SData
- class ConditionsBuilder
- SQL_RELATIONS_MAP = {
- :binary => {
- :eq => '%s = ?',
- :ne => '%s <> ?',
- :lt => '%s < ?',
- :lteq => '%s <= ?',
- :gt => '%s > ?',
- :gteq => '%s >= ?'
- },
-
- :ternary => {
- :between => '%s BETWEEN ? AND ?'
- }
- }
-
- attr_accessor :field, :relation, :values
-
- def self.build_conditions(field, relation, *values)
- self.new(field, relation, *values).conditions
- end
-
- def initialize(field, relation, *values)
- @field = field
- @relation = relation
- @values = values
- end
-
- def conditions
- arguments_invalid? ?
- {} :
- [template_with_field_name] + values
- end
-
- protected
-
- def arguments_invalid?
- field.nil? or relation.nil? or values.nil? or template.nil?
- end
-
- def template_with_field_name
- template % quoted_field_name
- end
-
- def quoted_field_name
- ActiveRecord::Base.connection.quote_column_name(@field)
- end
-
- def template
- case values.size
- when 1:
- SQL_RELATIONS_MAP[:binary][relation]
- when 2:
- SQL_RELATIONS_MAP[:ternary][relation]
- end
- end
- end
-end
View
203 lib/controller_mixin.rb
@@ -1,203 +0,0 @@
-module SData
- module ControllerMixin
- def acts_as_sdata(options)
- cattr_accessor :sdata_options
- self.sdata_options = options
-
- self.__send__ :include, InstanceMethods
-
- end
-
- module InstanceMethods
- module Actions
- def sdata_collection
- begin
- errors = []
- collection = build_sdata_feed
- atom_entries = []
- sdata_scope.each do |entry|
- begin
- collection.entries << entry.to_atom(params)
- rescue Exception => e
- errors << ApplicationDiagnosis.new(:exception => e).to_xml(:feed)
- end
- end
- #TODO: syntactic sugar if possible (such as diagnosing_errors(&block) which does the dirty work)
- errors.each do |error|
- collection[SData::Namespace::sdata_schemas['sdata'], 'diagnosis'] << error
- end
- populate_open_search_for(collection)
- build_feed_links_for(collection)
- render :xml => collection, :content_type => "application/atom+xml; type=feed"
-
- rescue Exception => e
- render :xml => ApplicationDiagnosis.new(:exception => e).to_xml(:root)
- end
- end
-
- def sdata_show_instance
- instance = model_class.find_by_sdata_instance_id(Predicate.strip_quotes(params[:instance_id]))
- render :xml => instance.to_atom(params), :content_type => "application/atom+xml; type=entry"
- end
-
- def sdata_create_instance
- new_instance = model_class.new(params[:entry].to_attributes)
- if new_instance.save
- render :xml => new_instance.to_atom(params).to_xml, :status => :created, :content_type => "application/atom+xml; type=entry"
- else
- render :xml => new_instance.errors.to_xml, :status => :bad_request
- end
- end
-
- def sdata_update_instance
- instance = model_class.find_by_sdata_instance_id(Predicate.strip_quotes(params[:instance_id]))
- response.etag = [instance]
- if request.fresh?(response)
- if instance.update_attributes(params[:entry].to_attributes)
- response.etag = [instance]
- render :xml => instance.to_atom(params).to_xml, :content_type => "application/atom+xml; type=entry"
- else
- render :xml => instance.errors.to_xml, :status => :bad_request
- end
- else
- render :text => nil, :status => :precondition_failed
- end
- end
- end
-
- module AuxilliaryMethods
- protected
-
- def model_class
- self.class.sdata_options[:model]
- end
-
- def resource_address
- request.protocol + request.host_with_port + request.path
- end
-
- def build_feed_links_for(feed)
- feed.links << Atom::Link.new(
- :rel => 'self',
- :href => (resource_address + "?#{request.query_parameters.to_param}".chomp('?')),
- :type => 'applicaton/atom+xml; type=feed',
- :title => 'Refresh')
- if (records_to_return > 0) && (@total_results > records_to_return)
- feed.links << Atom::Link.new(
- :rel => 'first',
- :href => (resource_address + "?#{request.query_parameters.merge(:startIndex => '1').to_param}"),
- :type => 'applicaton/atom+xml; type=feed',
- :title => 'First Page')
- #L = (T-1)-((T-1)%P)+1 = (T-1)/P*P+1, L=start index of last page, T=total results, P=results per page
- feed.links << Atom::Link.new(
- :rel => 'last',
- :href => (resource_address + "?#{request.query_parameters.merge(:startIndex => [1,(@last=(((@total_results-zero_based_start_index - 1) / records_to_return * records_to_return) + zero_based_start_index + 1))].max).to_param}"),
- :type => 'applicaton/atom+xml; type=feed',
- :title => 'Last Page')
- if (one_based_start_index+records_to_return) <= @total_results
- feed.links << Atom::Link.new(
- :rel => 'next',
- :href => (resource_address + "?#{request.query_parameters.merge(:startIndex => [1,[@last, (one_based_start_index+records_to_return)].min].max.to_s).to_param}"),
- :type => 'applicaton/atom+xml; type=feed',
- :title => 'Next Page')
- end
- if (one_based_start_index > 1)
- feed.links << Atom::Link.new(
- :rel => 'previous',
- :href => (resource_address + "?#{request.query_parameters.merge(:startIndex => [1,[@last, (one_based_start_index-records_to_return)].min].max.to_s).to_param}"),
- :type => 'applicaton/atom+xml; type=feed',
- :title => 'Previous Page')
- end
- end
- end
-
- def build_sdata_feed
- Namespace.add_feed_extension_namespaces(%w{crmErp sdata http opensearch sle xsi})
- Atom::Feed.new do |f|
- f.title = sdata_options[:feed][:title]
- f.updated = Time.now
- f.authors << Atom::Person.new(:name => sdata_options[:feed][:author])
- f.id = resource_address
- f.categories << Atom::Category.new(:scheme => 'http://schemas.sage.com/sdata/categories',
- :term => 'collection',
- :label => 'Resource Collection')
- # FIXME: the sequence for generating namespace prefixes is abysmal,
- # but only way I got atom to accept it. it's like taking an english sentence, translating it to
- # french through an online translator, then to spanish, then back to english, and then using the
- # resulting english translation instead of your original english sentence... -eugene
- # see namespace_definitions.rb lines 26+ for the other half of this hack
- end
- end
-
- def records_to_return
- default_items_per_page = sdata_options[:feed][:default_items_per_page] || 10
- maximum_items_per_page = sdata_options[:feed][:maximum_items_per_page] || 100
- #check whether the count param is castable into integer
- return default_items_per_page if params[:count].blank? or (params[:count].to_i.to_s != params[:count])
- items_per_page = [params[:count].to_i, maximum_items_per_page].min
- items_per_page = default_items_per_page if (items_per_page < 0)
- items_per_page
- end
-
- #according to sdata spec startIndex is provided 1-based (not 0-based),
- #while ruby arrays are 0-based
- #i'm assuming that if user gives us 0 it should stay 0 rather than become -1 and cause problems
- #also we should tell user we started at 0 if he gives us something wrong (e.g. -50 or 'asdf')
- def one_based_start_index
- [(params[:startIndex].to_i), 1].max
- end
-
- def zero_based_start_index
- [(one_based_start_index - 1), 0].max
- end
-
- #(name eq 'asdf') -> options[:conditions] = ['"name" eq ?', 'asdf']
- def sdata_scope
- options = {}
-
- if params.key? :predicate
- predicate = SData::Predicate.parse(CGI::unescape(params[:predicate]))
- options[:conditions] = predicate.to_conditions
- end
-
- if sdata_options[:scoping]
- options[:conditions] ||= []
- sdata_options[:scoping].each do |scope|
- options[:conditions][0] = [options[:conditions].to_a[0], scope].compact.join(' and ')
- options[:conditions] << current_user.id.to_s
- end
- end
-
- if params.key? :condition
- options[:conditions] ||= []
- if params[:condition] == "$linked" && sdata_options[:model].sdata_options[:link]
- condition = "#{sdata_options[:model].sdata_options[:link]} is not null"
- options[:conditions][0] = [options[:conditions].to_a[0], condition].compact.join(' and ')
- end
- end
-
- #FIXME: this is an unoptimized solution that may be a bottleneck for large number of matches
- #if user has hundreds of records but requests first 10, we shouldnt load them all into memory
- #but use sql query to count how many exist in total, and then load the first 10 only
-
- #FIXME: do not return records deleted through acts_as_paranoid!
- results = sdata_options[:model].all(options)
- @total_results = results.count
- paginated_results = results[zero_based_start_index,records_to_return]
- paginated_results.to_a
- end
-
- def populate_open_search_for(feed)
- feed[SData::Namespace::sdata_schemas['opensearch'], 'totalResults'] << @total_results
- feed[SData::Namespace::sdata_schemas['opensearch'], 'startIndex'] << one_based_start_index
- feed[SData::Namespace::sdata_schemas['opensearch'], 'itemsPerPage'] << records_to_return
- end
- end
-
- include Actions
- include AuxilliaryMethods
- end
- end
-end
-
-ActionController::Base.extend SData::ControllerMixin
View
171 lib/diagnosis.rb
@@ -1,171 +0,0 @@
-module SData
-
- class Diagnosis
-
- @@sdata_attributes = [:severity, :sdata_code, :application_code, :message, :stack_trace, :payload_path, :exception, :http_status_code]
- @@sdata_attributes.each {|attr| attr_accessor attr}
-
- def initialize(params={})
- raise "SData::Diagnosis is an abstract class; instantiate a subclass instead" if self.class == SData::Diagnosis
- params.each_pair do |key,value|
- if @@sdata_attributes.include?(key)
- self.send("#{key}=", value)
- end
- end
- self.message ||= self.exception.message if self.exception && !['production', 'staging'].include?(ENV['RAILS_ENV'])
- self.sdata_code ||= self.class.to_s.demodulize
- self.severity ||= "error"
- end
-
- def to_xml(mode=:root)
- case mode
- when :root
- return Diagnosis.construct_header_for(self.diagnosis_payload)
- when :feed
- return self.diagnosis_payload[0]
- when :entry
- return self.diagnosis_payload
- end
- end
-
- #Can be called from outside to build a single header for multiple diagnoses, each of which has been
- #constructed with (header=false) option. Useful when generating multiple diagnoses inside a single Feed.
- #Currently won't work inside a signle Entry due to parsing problems in rAtom.
- #Solving this problem is complex, so won't try to implement unless we confirm it's required. -Eugene
- def self.construct_header_for(diagnosis_payloads)
- document = XML::Document.new
- root_node = XML::Node.new("sdata:diagnoses")
- #TODO FIXME: SData spec says root node must be just 'xmlns=' and not 'xmlns:sdata', but this fails W3
- #XML validation. Confirm which way is correct -- if former, change below line to root_node['xmlns']...
- root_node['xmlns:sdata'] = "#{Namespace.sdata_schemas['sdata']}"
- diagnosis_payloads.each do |diagnosis_payload|
- root_node << diagnosis_payload
- end
- document.root = root_node
- document
- end
-
- protected
-
- def diagnosis_payload
- node = XML::Node.new("sdata:diagnosis")
- @@sdata_attributes.each do |attribute|
- value = self.send(attribute) unless [:http_status_code].include?(attribute)
- if value
- if value.is_a?(Exception)
- node << (XML::Node.new("sdata:stackTrace") << value.backtrace.join("\n") ) if !['production', 'staging'].include?(ENV['RAILS_ENV'])
- else
- node << (XML::Node.new("sdata:#{attribute.to_s.camelize(:lower)}") << value)
- end
- end
- end
- #nesting node in [] because of strange quirk in Atom::Content's mixin in atom_content_mixin,
- #in which .self becomes the return value of this method, but doesn't escape properly in the Atom Entry
- #making .self be [node] and then calling self[0] works fine.
- [node]
- end
-
- end
-
- #potential TODO: write a static class-generating method which diagnoses exception and decides what kind of
- #error payload class to return (caller will then instantiate it)
-
- #customize as needed
- class BadUrlSyntax < Diagnosis
- def initialize(params={})
- self.http_status_code = '400'
- super(params)
- end
- end
- class BadQueryParameter < Diagnosis
- def initialize(params={})
- self.http_status_code = '400'
- super(params)
- end
- end
- class ApplicationNotFound < Diagnosis
- def initialize(params={})
- self.http_status_code = '404'
- super(params)
- end
- end
- class ApplicationUnavailable < Diagnosis
- def initialize(params={})
- self.http_status_code = '503'
- super(params)
- end
- end
- class DatasetNotFound < Diagnosis
- def initialize(params={})
- self.http_status_code = '404'
- super(params)
- end
- end
- class ContractNotFound < Diagnosis
- def initialize(params={})
- self.http_status_code = '404'
- super(params)
- end
- end
- class ResourceKindNotFound < Diagnosis
- def initialize(params={})
- self.http_status_code = '404'
- super(params)
- end
- end
- class BadWhereSyntax < Diagnosis
- def initialize(params={})
- self.http_status_code = '400'
- super(params)
- end
- end
- class ApplicationDiagnosis < Diagnosis
- def initialize(params={})
- self.http_status_code = '500'
- super(params)
- end
- end
-
-end
-
-#TODO: write unit/cucumber tests for all those cases!
-module SData
- module ApplicationControllerMixin
- def sdata_rescue_support
- self.__send__ :include, SDataRescue
- end
-
- module SDataRescue
- #TODO: rescue_action_in_public won't work for some reason here. When merging with real Billing Boss app,
- #investigate. Need to preserve stack traces for dev env for non-simply requests.
- def sdata_global_rescue(exception, request_path)
- error_payload = case exception.class.to_s.demodulize
- when 'NoMethodError'
- if request_path.match /^\/sdata\/#{$SDATA_HIERARCHY[0]}\/#{$SDATA_HIERARCHY[1]}\/#{$SDATA_HIERARCHY[2]}\/[A-z]+\/.*/
- SData::ApplicationDiagnosis.new(:exception => exception, :http_status_code => '500')
- elsif request_path.match /^\/sdata\/#{$SDATA_HIERARCHY[0]}\/#{$SDATA_HIERARCHY[1]}\/#{$SDATA_HIERARCHY[2]}\/[A-z]+/
- SData::ResourceKindNotFound.new(:exception => exception, :http_status_code => '404')
- elsif request_path.match /^\/sdata\/#{$SDATA_HIERARCHY[0]}\/#{$SDATA_HIERARCHY[1]}\/#{$SDATA_HIERARCHY[2]}$/
- SData::ApplicationDiagnosis.new(:exception => exception, :http_status_code => '501')
- elsif request_path.match /^\/sdata\/#{$SDATA_HIERARCHY[0]}\/#{$SDATA_HIERARCHY[1]}.+/
- SData::ContractNotFound.new(:exception => exception, :http_status_code => '404')
- elsif request_path.match /^\/sdata\/#{$SDATA_HIERARCHY[0]}\/#{$SDATA_HIERARCHY[1]}$/
- SData::ApplicationDiagnosis.new(:exception => exception, :http_status_code => '501')
- elsif request_path.match /^\/sdata\/#{$SDATA_HIERARCHY[0]}.+/
- SData::DatasetNotFound.new(:exception => exception, :http_status_code => '404')
- elsif request_path.match /^\/sdata\/#{$SDATA_HIERARCHY[0]}$/
- SData::ApplicationDiagnosis.new(:exception => exception, :http_status_code => '501')
- else
- SData::ApplicationNotFound.new(:exception => exception, :http_status_code => '404')
- end
- when 'AccessDeniedException'
- SData::ApplicationDiagnosis.new(:exception => exception, :http_status_code => '403')
- else
- SData::ApplicationDiagnosis.new(:exception => exception, :http_status_code => '500')
- end
- render :xml => error_payload.to_xml(:root), :status => (error_payload.send('http_status_code') || '500')
- end
- end
- end
-end
-ActionController::Base.extend SData::ApplicationControllerMixin
View
33 lib/namespace_definitions.rb
@@ -1,33 +0,0 @@
-module SData
- class Namespace
- def self.sdata_schemas
- $SDATA_SCHEMAS
- end
-
- def self.add_feed_extension_namespaces(namespaces)
- namespaces.each do |namespace|
- Atom::Feed.add_extension_namespace(namespace.to_s, self.sdata_schemas[namespace.to_s])
- end
- end
-
- end
-end
-
-#some experimenting I was doing to try and get the Atom::Xml::NamespaceMap to be populated with our values
-#couldn't get it to work right anyways... Daniel, maybe you'll have better luck
-module SData
- module NamespaceMapMixin
- def self.included(base)
- base.class_eval do
- alias_method :initialize, :initialize_with_map
- end
- end
-
- def initialize_with_map(default=Atom::NAMESPACE)
- @default = default
- @i = 0
- @map = SData::Namespace.sdata_schemas.invert
- end
- end
-end
-Atom::Xml::NamespaceMap.__send__ :include, SData::NamespaceMapMixin
View
111 lib/payload.rb
@@ -1,111 +0,0 @@
-class Payload
-
- # FIXME: temporary
- # is_sync? should be passed as param to generate, and should be true if feed is a synch feed.
- # In this case, ?include will show only links and not embedded data for associations,
- # while ?include=$children will be implied
- def self.is_sync?
- false
- end
-
- def self.generate(*params)
- node_name, node_value, expand, included, selected, element_precedence, maximum_precedence, resource_collection = *params
- expand = :all_children if is_sync?
- return "" if element_precedence > maximum_precedence
- return "" if self.excluded_in_select?(node_name, selected)
- builder = Builder::XmlMarkup.new
- if node_value.respond_to?('payload_map')
- self.construct_from_sdata_model(*params)
- elsif node_value.is_a?(Array)
- self.construct_from_array(*params)
- elsif node_value.is_a?(Hash)
- self.construct_from_hash(*params)
- else
- self.construct_from_string(*params)
- end
- end
-
- def self.construct_from_sdata_model(node_name, node_value, expand, included, selected, element_precedence, maximum_precedence, resource_collection=nil)
- builder = Builder::XmlMarkup.new
- builder.__send__(self.xmlns_qualifier_for(node_name), node_value.resource_header_attributes(node_value, included)) do |element|
- if (expand != :none) || included.include?(node_name.to_s.camelize(:lower))
- expand = :none if (expand == :immediate_children)
- node_value.payload_map.each_pair do |child_node_name, child_node_data|
- if child_node_data[:type] == :association
- child_expand = :none
- else
- child_expand = expand
- end
- element << self.generate(child_node_name.to_s.camelize(:lower), child_node_data[:value], child_expand, included, selected, child_node_data[:precedence], maximum_precedence, child_node_data[:resource_collection])
- end
- end
- end
- end
-
- def self.construct_from_array(*params)
- builder = Builder::XmlMarkup.new
- if params[7] #resource_collection
- self.construct_from_sdata_array(*params)
- else
- self.construct_from_non_sdata_array(*params)
- end
- end
-
- def self.construct_from_sdata_array(node_name, node_value, expand, included, selected, element_precedence, maximum_precedence, resource_collection)
- builder = Builder::XmlMarkup.new
- scoped_children_collection = self.sdata_collection_url(resource_collection[:parent], resource_collection[:url])
- builder.__send__(self.xmlns_qualifier_for(node_name), {"xlmns:sdata:url" => scoped_children_collection}) do |element|
- if (expand != :none || included.include?(node_name.to_s.camelize(:lower)))
- expand = :immediate_children if (expand == :none && included.include?(node_name.to_s.camelize(:lower))) && !is_sync?
- node_value.each do |item|
- element << self.generate(item.sdata_node_name, item, expand, included, selected, element_precedence, maximum_precedence, nil)
- end
- end
- end
- end
-
- def self.construct_from_non_sdata_array(node_name, node_value, expand, included, selected, element_precedence, maximum_precedence, resource_collection)
- builder = Builder::XmlMarkup.new
- builder.__send__(xmlns_qualifier_for(node_name)) do |element|
- expand = :immediate_children if expand == :none
- node_value.each do |item|
- element << self.generate(node_name.to_s.singularize, item, expand, included, selected, element_precedence, maximum_precedence, (item.is_a?(Hash) ? item[:resource_collection] : nil))
- end
- end
- end
-
- def self.construct_from_hash(node_name, node_value, expand, included, selected, element_precedence, maximum_precedence, resource_collection)
- builder = Builder::XmlMarkup.new
- builder.__send__(xmlns_qualifier_for(node_name)) do |element|
- expand = :none if (expand == :immediate_children)
- node_value.each_pair do |child_node_name, child_node_data|
- element << self.generate(child_node_name.to_s.camelize(:lower), child_node_data, expand, included, selected, element_precedence, maximum_precedence, (child_node_data.is_a?(Hash) ? child_node_data[:resource_collection] : nil))
- end
- end
- end
-
- def self.construct_from_string(node_name, node_value, expand, included, selected, element_precedence, maximum_precedence, resource_collection)
- builder = Builder::XmlMarkup.new
- builder.__send__(self.xmlns_qualifier_for(node_name.to_s.camelize(:lower)), (node_value ? node_value.to_s : {'xlmns:xsi:nil' => "true"}))
- end
-
- def self.xmlns_qualifier_for(element)
- "xmlns:crmErp:#{element}"
- end
-
- def self.sdata_collection_url(parent, child)
- $APPLICATION_URL + $SDATA_STORE_PATH + parent.sdata_node_name + "('#{parent.id}')/" + child
- end
-
- def self.excluded_in_select?(node_name, selected)
- if selected.empty?
- return false
- elsif selected.include?('_root')
- selected.delete '_root'
- return false
- else
- return !selected.include?(node_name.to_s.camelize(:lower))
- end
- end
-
-end
View
44 lib/payload_map.rb
@@ -1,44 +0,0 @@
-module SData
- module PayloadMap
- def define_payload_map(map)
- cattr_accessor :payload_map
- cattr_accessor :payload
-
- self.payload_map = map
- self.payload = payload_fields_proxy
- end
-
- protected
-
- module PayloadFieldsProxy
- module ClassMethods
- def define_readers(readers)
- readers.each { |reader| attr_reader reader }
- end
- end
-
- module InstanceMethods
- def set_values(values)
- values.each_pair do |key, value|
- ivar_sym = "@#{key.to_s}".to_sym
- instance_variable_set ivar_sym, value
- end
- end
- end
- end
-
- def payload_fields_proxy
- proxy_class = Class.new
- proxy_class.extend PayloadFieldsProxy::ClassMethods
- proxy_class.__send__ :include, PayloadFieldsProxy::InstanceMethods
- proxy_class.define_readers(self.payload_map.keys)
-
- returning proxy_class.new do |proxy|
- field_values = self.payload_map.merge(self.payload_map) { |key, value| value[:static_value] }
- proxy.set_values(field_values)
- end
- end
- end
-end
-
-VirtualBase.extend SData::PayloadMap
View
24 lib/predicate.rb
@@ -1,24 +0,0 @@
-module SData
- class Predicate < Struct.new(:field, :relation, :value)
- def self.parse(predicate_string)
-
- match_data = predicate_string.match(/(\w+)\s(gt|lt|eq)\s('?.+'?|'')/) || []
- self.new match_data[1], match_data[2], strip_quotes(match_data[3])
- end
-
- def self.strip_quotes(value)
- return value unless value.is_a?(String)
- value = value.gsub("%27", "'")
- return value unless value =~ /'.*?'/
- return value[1,value.length-2]
- end
-
- def to_conditions
- if field && relation && value
- ConditionsBuilder.build_conditions field, relation.to_sym, value
- else
- {}
- end
- end
- end
-end
View
104 lib/route_mapper.rb
@@ -1,104 +0,0 @@
-module SData
- class RouteMapper < Struct.new(:router, :resource_name, :options)
- def map_sdata_routes!
- #RADAR: the order of the below statements makes a difference
- map_sdata_collection
- map_sdata_collection_with_condition_and_predicate
- map_sdata_collection_with_predicate
- map_sdata_collection_with_condition
- map_sdata_show_instance_with_condition
- map_sdata_show_instance
-
- map_sdata_create_instance
- map_sdata_update_instance
- end
-
- def self.urlize(string)
- string.gsub("'", "(%27|')").gsub("\s", "(%20|\s)")
- end
-
- protected
-
- CONDITION = urlize("{:condition,([$](linked))}")
- PREDICATE = urlize("{:predicate,[A-z]+\s[A-z]+\s'?[^']*'?}")
-
- # http://localhost:3000/sdata/billingboss/crmErp/-/tradingAccounts
- def map_sdata_collection
- map_route "#{name_in_path}", 'sdata_collection', :get
- end
-
- # http://localhost:3000/sdata/billingboss/crmErp/-/tradingAccounts/$linked
- def map_sdata_collection_with_condition
- map_route "#{name_in_path}\/#{CONDITION}", 'sdata_collection', :get
- end
-
- # http://localhost:3000/sdata/billingboss/crmErp/-/tradingAccounts(name eq 'asdf')
- # http://localhost:3000/sdata/billingboss/crmErp/-/tradingAccounts(name eq asdf)
- # http://localhost:3000/sdata/billingboss/crmErp/-/tradingAccounts(name eq '')
- def map_sdata_collection_with_predicate
- map_route "#{name_in_path}\\(#{PREDICATE}\\)", 'sdata_collection', :get
- end
-
- # http://localhost:3000/sdata/billingboss/crmErp/-/tradingAccounts/$linked(name eq 'asdf')
- # http://localhost:3000/sdata/billingboss/crmErp/-/tradingAccounts/$linked(name eq asdf)
- # http://localhost:3000/sdata/billingboss/crmErp/-/tradingAccounts/$linked(name eq '')
- def map_sdata_collection_with_condition_and_predicate
- map_route "#{name_in_path}\/#{CONDITION}\\(#{PREDICATE}\\)", 'sdata_collection', :get
- end
-
- # http://localhost:3000/sdata/billingboss/crmErp/-/tradingAccounts('1')
- def map_sdata_show_instance
- map_route "#{name_in_path}\\(:instance_id\\)", 'sdata_show_instance', :get
- end
-
- # http://localhost:3000/sdata/billingboss/crmErp/-/tradingAccounts/$linked('1')
- def map_sdata_show_instance_with_condition
- map_route "#{name_in_path}/#{CONDITION}\\(:instance_id\\)", 'sdata_show_instance', :get
- end
-
- # http://localhost:3000/sdata/billingboss/crmErp/-/tradingAccounts
- def map_sdata_create_instance
- map_route "#{name_in_path}", 'sdata_create_instance', :post
- end
-
- # http://localhost:3000/sdata/billingboss/crmErp/-/tradingAccounts('1')
- def map_sdata_update_instance
- map_route "#{name_in_path}\\(:instance_id\\)", 'sdata_update_instance', :put
- end
-
- def map_route(path, action, method)
- path = prefix + path if prefix?
- path = path + ".sdata" if formatted_paths?
- router.connect path, :controller => controller_with_namespace, :action => action, :conditions => { :method => method }
- end
-
- def controller_with_namespace
- @controller_with_namespace ||= "#{namespace}#{controller}"
- end
-
- def namespace
- @namespace ||= (options[:namespace] ? "#{options[:namespace]}/" : "")
- end
-
- def controller
- @controller ||= resource_name.to_s.pluralize
- end
-
- def name_in_path
- @name_in_path ||= resource_name.to_s.camelize(:lower).pluralize
- end
-
- def formatted_paths?
- @formatted_paths ||= options[:formatted_paths]
- end
-
- def prefix
- @prefix ||= (options[:prefix] || '/')
- end
-
- def prefix?
- !! prefix
- end
-
- end
-end
View
10 lib/router_mixin.rb
@@ -1,10 +0,0 @@
-module SData
- module RouterMixin
- def sdata_resource(name, options={})
- route_creator = SData::RouteMapper.new(self, name, options)
- route_creator.map_sdata_routes!
- end
- end
-end
-
-ActionController::Routing::RouteSet::Mapper.__send__ :include, SData::RouterMixin
View
88 lib/s_data.rb
@@ -1,88 +0,0 @@
-require 'active_support'
-require 'action_controller'
-require 'atom' # TODO: add ratom _dependency_
-
-module SData
- class << self
- def sdata_name(klass)
- case klass
- when SData::VirtualBase
- klass.sdata_name
- when Class
- klass.respond_to?(:sdata_name) ? klass.sdata_name : nil
- when String
- klass.demodulize
- end
- end
-
- def sdata_url_component(klass)
- SData.sdata_name(klass).camelize(:lower)
- end
-
- def sdata_collection_url_component(klass)
- SData.sdata_url_component(klass).pluralize
- end
-
- def config
- unless @config
- @config = YAML.load_file(File.join(File.dirname(__FILE__), '..', 'config','sdata.yml'))
- app_config_file = ENV['SDATA_CONFIG_FILE']
- app_config_file ||= File.join(RAILS_ROOT, 'config','sdata.yml') if defined?(RAILS_ROOT)
- @config = @config.deep_merge(YAML.load_file(app_config_file)) unless app_config_file.nil?
- @config = @config.with_indifferent_access
- @config[:contracts] ||= []
- @config[:defaultContract] ||= @config[:contracts].first
- @config[:defaultContract] ||= "crmErp"
- @config[:contract_namespace] ||= "SData::Contracts"
- end
- @config
- end
-
- def config=(conf)
- @config = conf.with_indifferent_access
- end
-
- def sdata_contract_name(klassname)
- if (klassname =~ /#{@config[:contract_namespace]}::([^:]*)::/)
- $~[1].camelize(:lower)
- else
- raise "Cannot determine sdata_contract_name for #{klassname}"
- end
- end
-
-
- def contract_namespaces
- config[:contracts].map{|contract| "#{config[:contract_namespace]}::#{contract.camelize}"}
- end
-
- # this is pby expensive and will have to be optimized by using const_get directly
- # RADAR: this assumes resource names are unique across contracts. To change that must refactor sd_uuid to either
- # have a contract attr or pby better just store fully qualified name in sd_class
- def resource_class(klassname)
- contract_namespaces.each do |ns|
- begin
- return "#{ns}::#{klassname}".constantize
- rescue;end
- end
- end
-
- def store_path
- #TODO: remove dataset=nil and modify calls accordingly. dataset should not be implied at this level
- ['sdata', config[:application], config[:defaultContract]].compact.join('/')
- end
-
- def base_url
- config[:base_url].chomp('/')
- end
-
- def endpoint
- [base_url, store_path].join('/')
- end
-
- def reset!
- @config = nil
- end
-
-
- end
-end
View
100 lib/s_data/payload_map/payload_map.rb
@@ -1,3 +1,5 @@
+
+
module SData
module PayloadMap
def define_payload_map(map)
@@ -17,42 +19,26 @@ def has_sdata_attr(*args)
method_name = options[:method_name]
payload_map[name] ||= options
- if options.has_key?(:static_value)
- value = options[:static_value]
- class_eval do
- define_method method_name do
- value
- end
- end
- elsif options.has_key?(:baze_field)
- baze_field = options[:baze_field]
- class_eval do
- define_method method_name do
- self.baze.__send__ baze_field
- end
- end
- elsif options.has_key?(:method)
- elsif options.has_key?(:proc)
- block = options[:proc]
- class_eval do
- define_method method_name, block
- end
+
+ case field_type(options)
+ when :static_value
+ define_static_value_reader method_name, options[:static_value]
+
+ when :baze_field
+ define_baze_field_reference method_name, options[:baze_field]
+
+ when :method
+
+ when :proc
+ define_proc_caller method_name, options[:proc]
+
if options.has_key?(:proc_with_deleted)
method_name_with_deleted = options[:method_name_with_deleted] = "#{method_name.to_s}_with_deleted"
- block = options[:proc_with_deleted]
- cache_var = "@#{method_name_with_deleted.to_s}_cached"
- class_eval do
- define_method(method_name_with_deleted) do
- unless instance_variable_get(cache_var)
- instance_variable_set(cache_var, instance_eval(&block))
- else
- end
- instance_variable_get(cache_var)
- end
- end
+ define_proc_with_deleted_caller method_name_with_deleted, options[:proc_with_deleted]
end
+
else
- raise SData::Exception::VirtualBase::InvalidSDataAttribute.new(
+ raise SData::Exceptions::VirtualBase::InvalidSDataAttribute.new(
"#{args.join(", ")}: must supply a static_value, baze_field, method or proc")
end
end
@@ -61,9 +47,9 @@ def has_sdata_attr(*args)
def has_sdata_association(*args)
options = args.last.is_a?(Hash) ? args.pop : {:precedence => 50, :type => :association}
options[:type] ||= :association
- raise SData::Exception::VirtualBase::InvalidSDataAssociation.new(
+ raise SData::Exceptions::VirtualBase::InvalidSDataAssociation.new(
"#{args.join(", ")}: must supply a proc or method") unless [:proc, :method].any?{|k|options.has_key?(k)}
- raise SData::Exception::VirtualBase::InvalidSDataAssociation.new(
+ raise SData::Exceptions::VirtualBase::InvalidSDataAssociation.new(
"#{args.join(", ")}: invalid association type '#{options[:type]}") unless [:association, :child].include?(options[:type])
args.push options
has_sdata_attr(*args)
@@ -97,8 +83,52 @@ def associations_with_deleted(expand=:all_children)
associations_with_deleted(expand)
end
end
+ end
+ end
+
+ protected
+
+ def field_type(options)
+ [:static_value, :baze_field, :method, :proc].each do |type|
+ if options.has_key?(type)
+ return type
+ end
+ end
+ nil
+ end
+
+ def define_static_value_reader(method_name, value)
+ class_eval do
+ define_method method_name do
+ value
+ end
+ end
+ end
+
+ def define_baze_field_reference(method_name, baze_field)
+ class_eval do
+ define_method method_name do
+ self.baze.__send__ baze_field
+ end
+ end
+ end
+
+ def define_proc_caller(method_name, block)
+ class_eval do
+ define_method method_name, block
+ end
+ end
+
+ def define_proc_with_deleted_caller(method_name, block)
+ cache_var = "@#{method_name.to_s}_cached"
+ class_eval do
+ define_method(method_name) do
+ unless instance_variable_get(cache_var)
+ instance_variable_set(cache_var, instance_eval(&block))
+ end
+ instance_variable_get(cache_var)
+ end
end
-
end
end
end
View
4 lib/s_data/virtual_base.rb
@@ -43,6 +43,10 @@ def reference
"#{self.baze.class.name.demodulize}_#{self.baze.id}"
end
+ def sd_class
+ self.class.name
+ end
+
def self.build_for(data, the_type=nil)
if data.is_a? Array
data.map {|item| virtual_base_for_object(item, the_type) }.compact
View
54 lib/virtual_base.rb
@@ -1,54 +0,0 @@
-# Tried using ActiveRecord::BaseWithoutTable, but had problems calling __include__ on it.
-# Research if we need features provided by BWT, otherwise use this.
-
-require 'forwardable'
-
-class VirtualBase
- extend Forwardable
- attr_accessor :baze
- def_delegators :baze, :id, :created_at, :updated_at, :save, :update_attributes
-
- def initialize(the_baze, the_type=nil)
- self.baze = the_baze
-
- if self.respond_to?('sdata_type') && the_type
- self.sdata_type = the_type
- end
-
- super()
- end
-
- def self.build_for(data, the_type=nil)
- if data.is_a? Array
- array = []
- data.each do |item|
- array << self.new(item, the_type) if item
- end
- array
- else
- data ? self.new(data, the_type) : nil
- end
- end
-
- # FIXME: Below methods transfer ActiveRecord methods to the baze. Is there a cleaner way to do this?
-
- def self.find(*params)
- self.new(self.baze_class.find(*params))
- end
-
- def self.first(*params)
- self.new(self.baze_class.first(*params))
- end
-
- def self.all(*params)
- virtual_results = []
- results = self.baze_class.all(*params)
- results.each do |result|
- virtual_results << self.new(result)
- end
- virtual_results
- end
-end
-
-
-VirtualBase.extend SData::ActiveRecordMixin
View
14 test/unit/active_record_mixin/payload_spec.rb
@@ -64,7 +64,7 @@ def payload(options)
element.attributes_with_ns.keys.should == ['sdata:url']
element.attributes_with_ns['sdata:url'].should == "http://www.example.com/sdata/example/myContract/myDataSet/customer('12345')/associatedContacts"
element.children.map(&:name_with_ns).to_set.should == ["crmErp:contact", "crmErp:contact"].to_set
- children = element.children.each do |child_element|
+ element.children.each do |child_element|
case child_element.attributes_with_ns['sdata:key']
when '123'
child_element.attributes_with_ns.keys.to_set.should == ['sdata:key', 'sdata:url', 'sdata:uuid'].to_set
@@ -93,7 +93,7 @@ def payload(options)
element.attributes_with_ns.keys.should == ['sdata:url']
element.attributes_with_ns['sdata:url'].should == "http://www.example.com/sdata/example/myContract/myDataSet/customer('12345')/myContacts"
element.children.map(&:name_with_ns).to_set.should == ["crmErp:contact", "crmErp:contact"].to_set
- children = element.children.each do |child_element|
+ element.children.each do |child_element|
case child_element.attributes_with_ns['sdata:key']
when '123'
child_element.attributes_with_ns.keys.to_set.should == ['sdata:key', 'sdata:url', 'sdata:uuid'].to_set
@@ -205,7 +205,7 @@ def payload(options)
element.attributes_with_ns.keys.should == ['sdata:url']
element.attributes_with_ns['sdata:url'].should == "http://www.example.com/sdata/example/myContract/myDataSet/customer('12345')/associatedContacts"
element.children.map(&:name_with_ns).to_set.should == ["crmErp:contact", "crmErp:contact"].to_set
- children = element.children.each do |child_element|
+ element.children.each do |child_element|
case child_element.attributes_with_ns['sdata:key']
when '123'
child_element.attributes_with_ns.keys.to_set.should == ['sdata:key', 'sdata:url', 'sdata:uuid'].to_set
@@ -233,7 +233,7 @@ def payload(options)
element.attributes_with_ns.keys.should == ['sdata:url']
element.attributes_with_ns['sdata:url'].should == "http://www.example.com/sdata/example/myContract/myDataSet/customer('12345')/myContacts"
element.children.map(&:name_with_ns).to_set.should == ["crmErp:contact", "crmErp:contact"].to_set
- children = element.children.each do |child_element|
+ element.children.each do |child_element|
case child_element.attributes_with_ns['sdata:key']
when '123'
child_element.attributes_with_ns.keys.to_set.should == ['sdata:key', 'sdata:url', 'sdata:uuid'].to_set
@@ -343,7 +343,7 @@ def payload(options)
element.attributes_with_ns.keys.should == ['sdata:url']
element.attributes_with_ns['sdata:url'].should == "http://www.example.com/sdata/example/myContract/myDataSet/customer('12345')/associatedContacts"
element.children.map(&:name_with_ns).to_set.should == ["crmErp:contact", "crmErp:contact"].to_set
- children = element.children.each do |child_element|
+ element.children.each do |child_element|
case child_element.attributes_with_ns['sdata:key']
when '123'
child_element.attributes_with_ns.keys.to_set.should == ['sdata:key', 'sdata:url', 'sdata:uuid'].to_set
@@ -373,7 +373,7 @@ def payload(options)
element.attributes_with_ns.keys.should == ['sdata:url']
element.attributes_with_ns['sdata:url'].should == "http://www.example.com/sdata/example/myContract/myDataSet/customer('12345')/myContacts"
element.children.map(&:name_with_ns).to_set.should == ["crmErp:contact", "crmErp:contact"].to_set
- children = element.children.each do |child_element|
+ element.children.each do |child_element|
case child_element.attributes_with_ns['sdata:key']
when '123'
child_element.attributes_with_ns.keys.to_set.should == ['sdata:key', 'sdata:url', 'sdata:uuid'].to_set
@@ -480,7 +480,7 @@ def payload(options)
element.attributes_with_ns.keys.should == ['sdata:url']
element.attributes_with_ns['sdata:url'].should == "http://www.example.com/sdata/example/myContract/myDataSet/customer('12345')/associatedContacts"
element.children.map(&:name_with_ns).to_set.should == ["crmErp:contact", "crmErp:contact"].to_set
- children = element.children.each do |child_element|
+ element.children.each do |child_element|
case child_element.attributes_with_ns['sdata:key']
when '123'
child_element.attributes_with_ns.keys.to_set.should == ['sdata:key', 'sdata:url', 'sdata:uuid'].to_set
View
20 test/unit/active_record_mixin/to_atom_spec.rb
@@ -1,17 +1,11 @@
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
-
describe SData::ActiveRecordExtensions::Mixin, "#to_atom" do
describe "given a class extended by ActiveRecordExtensions" do
before :all do
- Base = Class.new
class Base
- def self.name
- super_name = super
- "SData::Contracts::CrmErp::#{super_name}"
- end
+ extend SData::ActiveRecordExtensions::Mixin
end
- Base.extend SData::ActiveRecordExtensions::Mixin
end
describe "when .acts_as_sdata is called without arguments" do
@@ -23,13 +17,7 @@ def self.name
end
it "should return an Atom::Entry instance" do
- # begin
@model.to_atom(:dataset => '-').should be_kind_of(Atom::Entry)
- # rescue Exception => e
- # puts "e: #{e.inspect}"
- # puts(e.backtrace.join("\n"))
- # end
-
end
it "should assign model name to Atom::Entry#content" do
@@ -68,6 +56,7 @@ def self.name
@model.to_atom.categories[0].scheme.should == "http://schemas.sage.com/sdata/categories"
end
+# #QUESTION: Why is it commented out?
# it "should expose activerecord attributes in a simple XML extension" do
# @model.stub! :attributes => { :last_name => "Washington", :first_name => "George" }
# atom_entry = @model.to_atom
@@ -80,14 +69,11 @@ def self.name
Base.class_eval do
acts_as_sdata :title => lambda { "#{id}: #{name}" },
:content => lambda { "#{name}" }
-
- def attributes; {} end
end
@model = Base.new
- @model.stub! :id => 1, :name => 'Test', :updated_at => Time.now - 1.day, :created_by => @model, :sage_username => 'basic_user'
+ @model.stub! :id => 1, :name => 'Test', :updated_at => Time.now - 1.day, :created_by => @model, :sage_username => 'basic_user'
@model.stub! :sdata_content => "Base ##{@model.id}: #{@model.name}", :to_xml => ''
-
end
it "should evaulate given lambda's in the correct context" do
View
125 test/unit/controller_mixin/diagnosis_spec.rb
@@ -21,17 +21,17 @@ def id
describe "given a controller which acts as sdata" do
before :all do
- Base = Class.new(ActionController::Base)
- Base.extend ControllerMixin
+ class Base < ActionController::Base
+ extend ControllerMixin
- Base.acts_as_sdata :model => Customer,
- :feed => { :id => 'some-unique-id',
- :author => 'Test Author',
- :path => '/test_resource',
- :title => 'List of Test Items',
- :default_items_per_page => 10,
- :maximum_items_per_page => 100}
-
+ Base.acts_as_sdata :model => Customer,
+ :feed => { :id => 'some-unique-id',
+ :author => 'Test Author',
+ :path => '/test_resource',
+ :title => 'List of Test Items',
+ :default_items_per_page => 10,
+ :maximum_items_per_page => 100}
+ end
end
before :each do
@@ -44,32 +44,67 @@ def id
:query_parameters => {}),
:params => {}
end
- it "should construct diagnosis for caught Entry exception" do
- #TODO: spec trying to populate xpaths for errored entries
- @controller.sdata_options[:model].stub! :all => [EntryDiagnosisCustomer.new, Customer.new]
- @controller.should_receive(:render) do |hash|
- hash[:xml].entries.size.should == 2
- hash[:xml].entries.collect{|e|e if e.diagnosis.nil?}.compact.size.should == 1
- hash[:xml].entries.collect{|e|e if !e.diagnosis.nil?}.compact.size.should == 1
- hash[:xml].entries.each do |entry|
- entry.id.should_not == nil
- entry.content.should_not == nil
- if entry.diagnosis.nil?
- entry.sdata_payload.should_not == nil
- entry.content.should_not == nil
- else
- entry.sdata_payload.should == nil
- entry.diagnosis[0].children.size.should == 4
- entry.diagnosis[0].children.detect{|x|x.name=='sdata:severity'}.children[0].to_s.should == 'error'
- entry.diagnosis[0].children.detect{|x|x.name=='sdata:sdataCode'}.children[0].to_s.should == 'ApplicationDiagnosis'
- entry.diagnosis[0].children.detect{|x|x.name=='sdata:message'}.children[0].to_s.should == "Exception while trying to construct payload map"
- entry.diagnosis[0].children.detect{|x|x.name=='sdata:stackTrace'}.children[0].to_s.include?('/diagnosis_spec.rb').should == true
- end
+
+ #TODO: spec trying to populate xpaths for errored entries
+
+ context "when one of entries is erroneous" do
+ before :each do
+ @controller.sdata_options[:model].stub! :all => [EntryDiagnosisCustomer.new, Customer.new]
+ end
+
+ it "should respond with both entries" do
+ @controller.should_receive(:render) do |hash|
+ hash[:xml].entries.size.should == 2
+
+ failed_entries = hash[:xml].entries.reject{ |e| e.diagnosis.nil? }
+ successful_entries = hash[:xml].entries.select { |e| e.diagnosis.nil? }
+
+ failed_entries.size.should == 1
+ successful_entries.size.should == 1
+ end
+
+ @controller.sdata_collection
+ end
+
+ it "should compose diagnosis entry correctly" do
+ @controller.should_receive(:render) do |hash|
+ failed_entry = hash[:xml].entries.reject{ |e| e.diagnosis.nil? }.first
+
+ failed_entry.id.should_not be_nil
+ failed_entry.content.should_not be_nil
+ failed_entry.sdata_payload.should be_nil
end
+ @controller.sdata_collection
+ end
+
+ it "should compose sdata:diagnosis properties correctly" do
+ @controller.should_receive(:render) do |hash|
+ failed_entry = hash[:xml].entries.reject{ |e| e.diagnosis.nil? }.first
+ entry = Nokogiri::XML(failed_entry.to_xml, nil, nil, Nokogiri::XML::ParseOptions::DEFAULT_XML | Nokogiri::XML::ParseOptions::NOBLANKS)
+
+ diagnosis = entry.xpath('/xmlns:entry/sdata:diagnosis').first
+ diagnosis.children.size.should == 4
+
+ diagnosis.xpath('sdata:severity/text()').to_s.should == 'error'
+ diagnosis.xpath('sdata:sdataCode/text()').to_s.should == 'ApplicationDiagnosis'
+ diagnosis.xpath('sdata:message/text()').to_s.should == "Exception while trying to construct payload map"
+ diagnosis.xpath('sdata:stackTrace/text()').to_s.include?('/diagnosis_spec.rb').should be_true
+ end
+ @controller.sdata_collection
+ end
+
+ it "should correctly compose regular entry as well" do
+ @controller.should_receive(:render) do |hash|
+ successful_entry = hash[:xml].entries.select{ |e| e.diagnosis.nil? }.first
+ successful_entry.id.should_not be_nil
+ successful_entry.content.should_not be_nil
+ successful_entry.sdata_payload.should_not be_nil
+ successful_entry.content.should_not be_nil
+ end
+ @controller.sdata_collection
end
- @controller.sdata_collection
end
-
+
it "should construct multiple diagnosis elements within the same entry to describe multiple caught exceptions" do
pending #not implemented, difficulties with rAtom
end
@@ -80,10 +115,10 @@ def id
@controller.should_receive(:render) do |hash|
hash[:xml].entries.size.should == 1
hash[:xml].entries.each do |entry|
- entry.id.should_not == nil
- entry.sdata_payload.should_not == nil
- entry.content.should_not == nil
- entry.diagnosis.should == nil
+ entry.id.should_not be_nil
+ entry.sdata_payload.should_not be_nil
+ entry.content.should_not be_nil
+ entry.diagnosis.should be_nil
end
hash[:xml].simple_extensions['{http://schemas.sage.com/sdata/2008/1,diagnosis}'].size.should == 1
feed_diagnosis = hash[:xml].simple_extensions['{http://schemas.sage.com/sdata/2008/1,diagnosis}'][0]
@@ -102,12 +137,12 @@ def id
hash[:xml].entries.collect{|e|e if e.diagnosis.nil?}.compact.size.should == 2
hash[:xml].entries.collect{|e|e if !e.diagnosis.nil?}.compact.size.should == 1
hash[:xml].entries.each do |entry|
- entry.id.should_not == nil
- entry.content.should_not == nil
+ entry.id.should_not be_nil
+ entry.content.should_not be_nil
if entry.diagnosis.nil?
- entry.sdata_payload.should_not == nil
+ entry.sdata_payload.should_not be_nil
else
- entry.sdata_payload.should == nil
+ entry.sdata_payload.should be_nil
entry.diagnosis[0].children.detect{|x|x.name=='sdata:severity'}.children[0].to_s.should == 'error'
entry.diagnosis[0].children.detect{|x|x.name=='sdata:sdataCode'}.children[0].to_s.should == 'ApplicationDiagnosis'
entry.diagnosis[0].children.detect{|x|x.name=='sdata:message'}.children[0].to_s.should == "Exception while trying to construct payload map"
@@ -115,10 +150,10 @@ def id
end
hash[:xml].simple_extensions['{http://schemas.sage.com/sdata/2008/1,diagnosis}'].size.should == 2
feed_diagnoses = hash[:xml].simple_extensions['{http://schemas.sage.com/sdata/2008/1,diagnosis}']
- feed_diagnoses.each do |diagnosis|
- diagnosis.children.detect{|x|x.name=='sdata:severity'}.children[0].to_s.should == 'error'
- diagnosis.children.detect{|x|x.name=='sdata:sdataCode'}.children[0].to_s.should == 'ApplicationDiagnosis'
- diagnosis.children.detect{|x|x.name=='sdata:message'}.children[0].to_s.should == "Exception while trying to get customer id"
+ feed_diagnoses.each do |failed_entry|
+ failed_entry.children.detect{|x|x.name=='sdata:severity'}.children[0].to_s.should == 'error'
+ failed_entry.children.detect{|x|x.name=='sdata:sdataCode'}.children[0].to_s.should == 'ApplicationDiagnosis'
+ failed_entry.children.detect{|x|x.name=='sdata:message'}.children[0].to_s.should == "Exception while trying to get customer id"
end
end
@controller.sdata_collection
View
139 test/unit/controller_mixin/sdata_scope_spec.rb
@@ -1,139 +0,0 @@
-require File.join(File.dirname(__FILE__), '..', 'spec_helper')
-
-include SData
-
-describe ControllerMixin, "#sdata_scope" do
- Model = Class.new
- Base = Class.new(ActionController::Base)
- describe "given a controller which acts as sdata and accesses a non-linked model" do
- before :all do
-
- Model.stub! :all => [Model.new, Model.new]
-
- Base.extend ControllerMixin
-
- Base.__send__ :define_method, :sdata_scope, lambda { super }
-
-
- Base.acts_as_sdata :model => Model, :feed =>
- {:author => 'Billing Boss',
- :path => '/trading_accounts',
- :title => 'Billing Boss | Trading Accounts',
- :default_items_per_page => 10,
- :maximum_items_per_page => 100}
- end
-
- before :each do
- @controller = Base.new
- end
-
- describe "when params contain :predicate key" do
- before :each do
- @controller.stub! :params => { :predicate => 'born_at gt 1900' }
- end
-
- it "should apply to SData::Predicate for conditions" do
- Model.should_receive(:all).with :conditions => ['"born_at" > ?', '1900']
- @controller.send :sdata_scope
- end
- end
-
- describe "when params do not contain :predicate key" do
- before :each do
- @controller.stub! :params => {}
- end
-
- it "should return all entity records" do
- Model.should_receive(:all).with({})
- @controller.send :sdata_scope
- end
- end
-
-
- end
-
- describe "given a controller which acts as sdata and accesses a linked model" do
- before :all do
-
- Model.stub! :all => [Model.new, Model.new]
- Model.stub! :sdata_options => {:link => :simply_guid}
-
- Base.extend ControllerMixin
-
- Base.__send__ :define_method, :sdata_scope, lambda { super }
- end
- describe "being configured without user scoping" do
- before :all do
-
- Base.acts_as_sdata :model => Model, :feed =>
- {:author => 'Billing Boss',
- :path => '/trading_accounts',
- :title => 'Billing Boss | Trading Accounts',
- :default_items_per_page => 10,
- :maximum_items_per_page => 100}
- end
-
- before :each do
- @controller = Base.new
- end
-
- describe "when params contain :condition key and :predicate key" do
- before :each do
- @controller.stub! :params => { :predicate => 'born_at gt 1900', :condition => '$linked' }
- end
-
- it "should apply to SData::Predicate for conditions and append requirement for simply guid" do
- Model.should_receive(:all).with :conditions => ['"born_at" > ? and simply_guid is not null', '1900']
- @controller.send :sdata_scope
- end
- end
-
- describe "when params contain :condition key but do not contain :predicate key" do
- before :each do
- @controller.stub! :params => {:condition => '$linked'}
- end
-
- it "should return all entity records with simply guid" do
- Model.should_receive(:all).with :conditions => ['simply_guid is not null']
- @controller.send :sdata_scope
- end
- end
- end
-
- describe "being configured with user scoping" do
- before :all do
- Base.acts_as_sdata :model => Model, :feed =>
- {:author => 'Billing Boss',
- :path => '/trading_accounts',
- :title => 'Billing Boss | Trading Accounts',
- :default_items_per_page => 10,
- :maximum_items_per_page => 100},
- :scoping => ["created_by_id = ?"]
- end
- @user = User.new.populate_defaults
- before :each do
- @controller = Base.new
- end
- describe "with no other params" do
- before :each do
- @controller.stub! :params => {}
- @controller.stub! :current_user => @user
- end
- it "should return all entity records created_by scope" do
- Model.should_receive(:all).with :conditions => ['created_by_id = ?', "#{@user.id}"]
- @controller.send :sdata_scope
- end
- end
- describe "with condition and predicate" do
- before :each do
- @controller.stub! :params => { :predicate => 'born_at gt 1900', :condition => '$linked' }
- @controller.stub! :current_user => @user
- end
- it "should return all entity records with created_by, predicate, and link scope" do
- Model.should_receive(:all).with :conditions => ['"born_at" > ? and created_by_id = ? and simply_guid is not null', '1900', @user.id.to_s]
- @controller.send :sdata_scope
- end
- end
- end
- end
-end
View
24 test/unit/payload_map/payload_map_spec.rb
@@ -4,7 +4,10 @@
context "given sdata model class extended by SData::PayloadMap" do
before :all do
class TradingAccount < SData::VirtualBase
- extend SData::PayloadMap
+# extend SData::PayloadMap
+#
+ define_payload_map :foo => { :static_value => :bar }
+
# temporary
def method_missing(meth, *args, &block)
if @payload
@@ -22,25 +25,10 @@ def method_missing(meth, *args, &block)
it "should respond to #has_sdata_attr class method" do
TradingAccount.should respond_to(:has_sdata_attr)
+ #QUESTION: do we really need this method to be public?
end
describe "#define_payload_map" do
- before :each do
- TradingAccount.define_payload_map :some_field => { :static_value => 0 }
- end
-
- subject { TradingAccount.new(Object) }
-
- it "should add :id baze field implicitly" do
- pending # Please explain why we need this
- #subject.payload_map[:id].should_not be_nil
- end
-
- it "shuold set precedence for implicity added :id" do
- pending # Please explain why we need this
- subject.payload_map[:id][:precedence].should_not be_nil
- end
-
context "when mapping leads to static value" do
before :each do
TradingAccount.define_payload_map :tax_reference => { :static_value => 'Some static tax reference' }
@@ -129,7 +117,7 @@ def method_missing(meth, *args, &block)
end
end
- describe "#{}has_sdata_attr" do
+ describe "#has_sdata_attr" do
before :each do
@mock_baze = mock("thing", :dude => "sweet")
end
View
37 test/unit/payload_map_spec.rb
@@ -1,37 +0,0 @@
-require File.join(File.dirname(__FILE__), 'spec_helper')
-
-describe SData::PayloadMap do
- context "given a VirtualBase class extended by SData::PayloadMap" do
- before :all do
- VirtualBase.extend SData::PayloadMap
- end
-
- it "should respond to #payload_map class method" do
- VirtualBase.should respond_to(:define_payload_map)
- end
-
- describe "#define_payload_map" do
- context "when mapping leads to static value" do
- before :all do
- VirtualBase.define_payload_map :tax_reference => { :static_value => 'Some static tax reference' }
- end
-
- subject { VirtualBase.new(Object) }
-
- it { should respond_to(:payload) }
-
- context "when correspondent field method is called" do
- it "should return given static value" do
- subject.payload.tax_reference.should == 'Some static tax reference'
- end
- end
-
- describe "#payload_map" do
- subject { VirtualBase.new(Object).payload_map }
-
- it { should == { :tax_reference => { :static_value => 'Some static tax reference' } } }
- end
- end
- end
- end
-end
Please sign in to comment.
Something went wrong with that request. Please try again.