module Eeml include Eeml::Constants include Eeml::Exceptions # One of the component classes of Environment. Represents the location of the environment. Environments can only have a single location object. class Location attr_accessor :name, :latitude, :longitude, :elevation attr_accessor :domain, :exposure, :disposition def initialize(options = {}) @name = options[:name] @latitude = options[:latitude] @longitude = options[:longitude] @elevation = options[:elevation] @domain = options[:domain] @exposure = options[:exposure] @disposition = options[:disposition] end end # One of the component classes of Environment. Represents an individual datastream, and provides access to it's value # and other attributes. Environments can have zero or more datastreams. class DataStream attr_accessor :identifier, :tags, :unit_symbol, :unit_type, :unit_value attr_accessor :values def initialize(options = {}) @identifier = options[:identifier] @tags = [] @unit_symbol = options[:unit_symbol] @unit_type = options[:unit_type] @unit_value = options[:unit_value] @values = [] @values << Value.new(:value => options[:value], :max_value => options[:max_value], :min_value => options[:min_value], :recorded_at => options[:recorded_at]) end def add_value(value) @values << value end def remove_last_value @values.pop end def min_value unless @values.last.nil? return @values.last.min_value else return nil end end def max_value unless @values.last.nil? return @values.last.max_value else return nil end end def value unless @values.last.nil? return @values.last.value else return nil end end def recorded_at unless @values.last.nil? return @values.last.recorded_at else return nil end end def to_s "identifier: '#{@identifier}', value: '#{@value}', min_value: '#{@min_value}', max_value: '#{@max_value}', tags: '#{@tags.join(", ")}'" end end class Value attr_accessor :min_value, :max_value, :value, :recorded_at def initialize(options = {}) @min_value = options[:min_value] @max_value = options[:max_value] @value = options[:value] @recorded_at = options[:recorded_at] end end # This class represents the main point of entry to this library. In general we will be creating instances of this class, either # by manually specifying the parameters, or probably more commonly, by passing in either an EEML or JSON formatted string which # will be parsed to initialize the object. class Environment attr_accessor :identifier, :updated, :publisher attr_accessor :title, :description, :feed_url, :website, :email, :icon, :status attr_accessor :owner attr_accessor :location attr_accessor :csv_version attr_accessor :datastreams attr_accessor :tags attr_writer :private attr_accessor :owner attr_alias :creator, :publisher # Create a new Environment object by passing parameters in a hash (just like creating an ActiveRecord object) def initialize(options = {}) @datastreams = [] @identifier = options[:identifier] @publisher = options[:publisher] || options[:creator] @title = options[:title] @status = options[:status] @feed_url = options[:feed_url] @description = options[:description] @website = options[:website] @email = options[:email] @icon = options[:icon] @private = options[:private] @csv_version = options[:csv_version] @owner = options[:owner] @tags = [] end def add_datastream(datastream) #TODO: consider checking for unique identifier datastreams << datastream if dups = datastreams.map(&:identifier).compact.uniq! raise Eeml::Exceptions::DuplicateDataStreams, "Duplicate Datastream IDs: #{dups.join(', ')}" end end def add_datastreams(array) array.each { |d| add_datastream d } end def remove_last_datastream datastreams.pop end # Create multiple Environment objects from an EEML string containing multiple `environment` stanzas. def self.new_list_from_eeml(xml_str) EnvironmentBuilder.build_list_from_xml(xml_str) end # Create a new Environment object from an EEML string. def self.new_from_eeml(xml_str) EnvironmentBuilder.build_from_xml(xml_str) end # Create a new Environment object from a JSON string. def self.new_from_json(json_str) EnvironmentBuilder.build_from_json(json_str) end # Create a new Environment object from a CSV string def self.new_from_csv(csv_str, version = nil) EnvironmentBuilder.build_from_csv(csv_str, detect_csv_version(version, csv_str)) end def update_datastreams_from_csv_values!(csv_values) csv_values.each_with_index do |new_val, index| datastream = datastreams[index] #if we don't have an existing datastream at same index, create new one if datastream.nil? datastream = DataStream.new(:identifier => index, :ordering => index) datastream.add_value(Value.new(:value => new_val)) self.datastreams << datastream else #we had a match, so update the existing datastream datastream.values.last.value = new_val end end # if the csv specifies FEWER feeds than the env currently has. if csv_values.size < self.datastreams.size # remove the excess from the end of the env's list. num_extra = datastreams.size - csv_values.size 1.upto(num_extra) { remove_last_datastream } end end def private if @private return true else return false end end private def self.detect_csv_version(version, csv) return version if version parsed_csv = LightCsv.parse(strip_content(csv)) return :v2 if parsed_csv.size >= 2 return :v1 if parsed_csv.size == 1 && parsed_csv.first.length != 2 raise(CsvEncodingError, "CSV version could not be detected") end end end