amon 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md ADDED
@@ -0,0 +1,76 @@
1
+ Ruby Client for the AMEE AMON API
2
+ =================================
3
+
4
+ This is a Ruby client library for the [AMEE](http://www.amee.com/) <abbr title="AMEE Monitoring Object Notation">AMON</abbr> <abbr title="Application Programming Interface">API</abbr>. _More details and links to be inserted once information about the API is publicly available_.
5
+
6
+ ## Installation ##
7
+
8
+ ### Dependencies ###
9
+
10
+ Currently, the library depends on:
11
+
12
+ * [json](http://flori.github.com/json/) 1.4.X
13
+ * [rest-client](http://github.com/archiloque/rest-client) 1.6.X
14
+
15
+ These will be automatically installed if installing as a gem.
16
+
17
+ ### Standard installation: as a rubygem ###
18
+
19
+ The library is not currently available via any public gem servers. However, it can be installed as a gem using the following steps:
20
+
21
+ 1. Grab the code: `git clone git@github.com:AMEE/amon.client.ruby.git`
22
+ 2. Build the gem: `gem build amon.gemspec`
23
+ 3. Install the gem: `sudo gem install amon-0.1.0.gem`
24
+
25
+ ### Alternative: manual installation ###
26
+
27
+ You can manually install the code somewhere, and then ensure that the `lib/` directory is listed in your `LOAD_PATH`.
28
+
29
+ ### Alternative: vendoring in a Rails app ###
30
+
31
+ If you are using the library inside a Rails (2.3) app, clone the code into `vendor/gems/amon-0.1.0`. Then list it as a gem dependency in `config/environment.rb` and Rails will automatically find and load it.
32
+
33
+ If using Rails 3, you could do a similar thing using Bundler.
34
+
35
+ ## Loading the library in your code ##
36
+
37
+ Once installed, the library can be loaded using `require "amon"`.
38
+
39
+ ## Configuration ##
40
+
41
+ Interaction with the API is achieved through {AMON::Session Session} objects. For convenience, you can configure some 'default session options' by setting the values in the {AMON.default_session_options} hash. You can then create a session from these options at any time by calling {AMON.create_default_session}.
42
+
43
+ See the {AMON::Session} page for a full explanation of the options available.
44
+
45
+ ### Example default session configuration ###
46
+
47
+ AMON.default_session_options[:base_uri] = "http://amon.amee.com/1"
48
+ AMON.default_session_options[:user] = "fred"
49
+ AMON.default_session_options[:password] = "s3cr3t"
50
+
51
+ ## Usage ##
52
+
53
+ Methods which can be called on a {AMON::Session Session} can be called directly on the {AMON} module, which will cause a {AMON.create_default_session default session} to be created and used.
54
+
55
+ ### Simple usage example ###
56
+
57
+ This example gets some measurements from an electricity meter over a 1 month period.
58
+
59
+ start_date = Time.local(2010, 3)
60
+ end_date = Time.local(2010, 4)
61
+
62
+ property = AMON.entity("da3906c0-7c6b-012d-a6d5-001c23973687")
63
+ concentrator = property.meters.first
64
+ electricity_reading = concentrator.readings_by_type["electricalInput"]
65
+ electricity_reading.measurements(start_date, end_date) # => Array of measurements
66
+
67
+ ## Development ##
68
+
69
+ Tests can be run with RSpec: `spec spec/`.
70
+
71
+ The documentation is generated with YARD: `rake yard`.
72
+
73
+ ## TODO List ##
74
+
75
+ * Error handling
76
+ * Rename Document and DocumentPart to Resource and ResourcePart
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.dirname(__FILE__) + "/rails/init"
@@ -0,0 +1,45 @@
1
+ require 'forwardable'
2
+
3
+ # The AMON module responds to the same method names as an {AMON::Session}. When called,
4
+ # these methods use a 'default' session returned by {create_default_session}. So the following
5
+ # method calls are all equivalent:
6
+ #
7
+ # AMON::Session.new(AMON.default_session_options).entity("77e50660-93e7-012d-b57d-001c23973687")
8
+ # AMON.create_default_session.entity("77e50660-93e7-012d-b57d-001c23973687")
9
+ # AMON.entity("77e50660-93e7-012d-b57d-001c23973687")
10
+ #
11
+ # Note that using a default session implicitly (as in the final line above) will cause a new
12
+ # session to be created each time the method is called. This means caching will not be used.
13
+ #
14
+ # If you are likely to be requesting the same resources in short succession, it is advisable to
15
+ # hold on to a session object yourself. For example:
16
+ #
17
+ # @session = AMON.create_default_session
18
+ # @session.entity("77e50660-93e7-012d-b57d-001c23973687") # => <AMON::Entity> (from HTTP)
19
+ # @session.entity("77e50660-93e7-012d-b57d-001c23973687") # => <AMON::Entity> (from cache)
20
+ module AMON
21
+ class << self
22
+ # A hash of options which are used by {create_default_session}. The values of this hash
23
+ # should be configured by users as appropriate.
24
+ # @return [Hash] an options hash, initially empty
25
+ def default_session_options
26
+ @default_session_options ||= {}
27
+ end
28
+
29
+ # Assigns a new options hash as the {default_session_options}.
30
+ # @param [Hash] options the options hash
31
+ # @return [Hash] the options hash
32
+ def default_session_options=(options)
33
+ @default_session_options = options
34
+ end
35
+
36
+ # Creates a new session using the {default_session_options}.
37
+ # @return [Session]
38
+ def create_default_session
39
+ Session.new(default_session_options)
40
+ end
41
+
42
+ extend Forwardable
43
+ def_delegators :create_default_session, :entity, :meter, :metering_point, :measurements
44
+ end
45
+ end
@@ -0,0 +1,30 @@
1
+ module AMON
2
+ # A top-level object representing an AMON resource
3
+ # @abstract
4
+ class Document
5
+ include JSONHelper
6
+
7
+ # @return [Session] The session associated with this document
8
+ attr_reader :session
9
+
10
+ # @param [Session] session The session
11
+ # @param [Hash] json The JSON data as a Hash
12
+ def initialize(session, json)
13
+ @session, @json = session, json
14
+ end
15
+
16
+ # This should be implemented in subclasses, returning the UUID for the document
17
+ # @abstract
18
+ # @private
19
+ def id
20
+ raise NotImplementedError
21
+ end
22
+
23
+ # Two documents are equal if they have the same class and their id fields are equal
24
+ # @param [Document] other
25
+ # @return [Boolean]
26
+ def ==(other)
27
+ self.class == other.class && id == other.id
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,18 @@
1
+ module AMON
2
+ # An object representing part of an AMON {Document}. For example, a {Reading} is part of a
3
+ # {Meter}, and cannot exist outside of it.
4
+ #
5
+ # @abstract
6
+ class DocumentPart
7
+ include JSONHelper
8
+
9
+ # @return [Document] The parent document of which this object is a part
10
+ attr_reader :parent
11
+
12
+ # @param [Document] parent The parent document
13
+ # @param [Hash] json The JSON data as a Hash
14
+ def initialize(parent, json)
15
+ @parent, @json = parent, json
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,24 @@
1
+ module AMON
2
+ # An AMON entity, such as a house, business park, or building floor
3
+ class Entity < Document
4
+ # @return [String] The id for this entity
5
+ field :id, :name => 'entityId'
6
+
7
+ # @return [Array<String>] The ids of all the meters associated with this entity
8
+ field :meter_ids, :name => 'meterIds', :default => []
9
+
10
+ # @return [Array<String>] The qualified ids of all the metering points associated with this entity
11
+ # @todo Rename to qualified_metering_point_ids
12
+ field :metering_point_ids, :name => 'qualifiedMeteringPointIds', :default => []
13
+
14
+ # @return [Array<Meter>] The meters associated with this entity
15
+ def meters
16
+ @meters ||= meter_ids.map { |id| session.meter(id) }
17
+ end
18
+
19
+ # @return [Array<MeteringPoint>] The metering points associated with this entity
20
+ def metering_points
21
+ @metering_points ||= metering_point_ids.map { |id| session.metering_point(id) }
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,36 @@
1
+ module AMON
2
+ module JSONHelper
3
+ # @return [Hash] The raw JSON data for this object, represented as a Hash
4
+ attr_reader :json
5
+
6
+ private
7
+
8
+ def self.included(base)
9
+ base.class_eval do
10
+ extend ClassMethods
11
+ end
12
+ end
13
+
14
+ # @private
15
+ module ClassMethods
16
+ def field(name, options = {})
17
+ class_eval do
18
+ define_method(name) do
19
+ original_value = json[(options[:name] || name).to_s]
20
+
21
+ if original_value.nil?
22
+ options[:default]
23
+ else
24
+ case options[:as].to_s
25
+ when 'Time'
26
+ Time.parse(original_value)
27
+ else
28
+ original_value
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,55 @@
1
+ module AMON
2
+ # A measurement corresponding to a {Reading} of a {Meter}
3
+ class Measurement < DocumentPart
4
+ # @return [String] The measurement's name
5
+ field :name
6
+
7
+ # @return [Numeric] The measurement's value
8
+ field :value
9
+
10
+ # @return [Time] The measurement's timestamp, if provided
11
+ field :timestamp, :as => Time
12
+
13
+ # @return [Time] The measurement's start date, if provided
14
+ field :start_date, :name => 'startDate', :as => Time
15
+
16
+ # @return [Time] The measurement's end date, if provided
17
+ field :end_date, :name => 'endDate', :as => Time
18
+
19
+ # @attr_reader [Meter] meter The meter which took this measurement
20
+ alias_method :meter, :parent
21
+
22
+ # A measurement is instantaneous if it is given with a single timestamp. If, on the other hand,
23
+ # start and end dates are provided, it is durational.
24
+ # @return [Boolean]
25
+ # @see Measurement#durational?
26
+ def instantaneous?
27
+ !timestamp.nil?
28
+ end
29
+
30
+ # The opposite of {Measurement#instantaneous? instantaneous?}
31
+ # @return [Boolean]
32
+ # @see Measurement#instantaneous?
33
+ def durational?
34
+ !instantaneous?
35
+ end
36
+
37
+ # The {Meter meter} {Reading reading} associated with this measurement.
38
+ # @return [Reading]
39
+ def reading
40
+ meter.readings_by_type[name]
41
+ end
42
+
43
+ # A single timestamp in the 'middle' of this measurement. If the measurement is instantaneous,
44
+ # then the mid timestamp is identical to the {Measurement#timestamp timestamp}. However, if it
45
+ # is durational then the mid timestamp is the halfway point between the {Measurement#start_date}
46
+ # and the {Measurement#end_date}.
47
+ def mid_timestamp
48
+ if instantaneous?
49
+ timestamp
50
+ else
51
+ start_date + (end_date - start_date) / 2
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,34 @@
1
+ module AMON
2
+ # Metadata associated with a {Meter}. The metadata section of an AMON document can have an
3
+ # arbitrary number of fields, so this class uses `method_missing` to look them up and respond
4
+ # appropriately.
5
+ #
6
+ # @todo
7
+ # This doesn't yet support arbitrarily nested metadata, so you can't have JSON like so:
8
+ #
9
+ # "metadata": {
10
+ # "foo": {
11
+ # "bar": "baz"
12
+ # }
13
+ # }
14
+ #
15
+ # And then access:
16
+ #
17
+ # object.metadata.foo.bar # => "baz"
18
+ #
19
+ # However, in the meantime you could do:
20
+ #
21
+ # object.metadata.foo[:bar] # => "baz"
22
+ #
23
+ # (As the JSON is full parsed into a nested hash.)
24
+
25
+ class Metadata < DocumentPart
26
+ def method_missing(name, *args, &block)
27
+ if args.empty? && block.nil?
28
+ json[name.to_s]
29
+ else
30
+ raise NoMethodError, "undefined method `#{name}'"
31
+ end
32
+ end
33
+ end
34
+ end
data/lib/amon/meter.rb ADDED
@@ -0,0 +1,53 @@
1
+ module AMON
2
+ # An AMON meter, containing any number of {Reading readings}, and {Measurement measurements} for those readings.
3
+ class Meter < Document
4
+ # @return [String] The id of the meter
5
+ field :id, :name => 'meterId'
6
+
7
+ # @return <String> The description for the meter
8
+ def description
9
+ @description ||= json['description']
10
+ end
11
+
12
+ # @return <String> The location for the meter
13
+ def location_name
14
+ @location_name ||= json['location']['name']
15
+ end
16
+
17
+ # @return [Metadata] The metadata for the meter
18
+ def metadata
19
+ @metadata ||= Metadata.new(self, json['metadata'])
20
+ end
21
+
22
+ # @return [Array<Reading>] The readings for the meter
23
+ def readings
24
+ @readings ||= json['readings'].map { |reading| Reading.new(self, reading) }
25
+ end
26
+
27
+ # @return [Hash<String => Reading>] A hash allowing {Meter#readings} to be retrieved by their
28
+ # {Reading#type}
29
+ def readings_by_type
30
+ readings.inject({}) do |readings_by_type, reading|
31
+ readings_by_type[reading.type] = reading
32
+ readings_by_type
33
+ end
34
+ end
35
+
36
+ # @return [Array<Measurement>] Measurements for this meter
37
+ # @see Session#measurements
38
+ def measurements(start_date, end_date, raw = false)
39
+ session.measurements(id, start_date, end_date, raw)
40
+ end
41
+
42
+ # @return [Hash<String => Measurement>] A hash allowing {Meter#measurements} to be retrieved
43
+ # by their {Measurement#name}
44
+ # @see Meter#measurements
45
+ def measurements_by_name(start_date, end_date, raw = false)
46
+ measurements(start_date, end_date, raw).inject({}) do |measurements_by_name, measurement|
47
+ measurements_by_name[measurement.name] ||= []
48
+ measurements_by_name[measurement.name] << measurement
49
+ measurements_by_name
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,8 @@
1
+ module AMON
2
+ # An AMON metering point
3
+ # @todo Implement this class
4
+ class MeteringPoint < Document
5
+ # @return [String] The id for this metering point
6
+ field :id, :name => 'meteringPointId'
7
+ end
8
+ end
@@ -0,0 +1,59 @@
1
+ module AMON
2
+ # AMON readings are 'categories' of {Measurement measurements} which are taken by {Meter meters}.
3
+ # For example, one reading may be 'electricalInput' with the unit 'kWh'.
4
+ class Reading < DocumentPart
5
+ # @return [String] The type of reading, which is unique within the parent {Meter meter}
6
+ field :type
7
+
8
+ # @return [String] An arbitrary name for the reading
9
+ field :name
10
+
11
+ # @return [String] The units this reading records {Measurement measurements} in
12
+ field :unit
13
+
14
+ # @return [Numeric] The resolution of the reading
15
+ field :resolution
16
+
17
+ # @return [Numeric] The accuracy of the reading
18
+ field :accuracy
19
+
20
+ # @return ["instant", "duration"] Whether this reading records measurement values taken at a
21
+ # specific point in time ('instant'), or taken as an average over a period of time ('duration')
22
+ field :period, :default => "instant"
23
+
24
+ # @attr_reader [Meter] meter The meter which took this measurement
25
+ alias_method :meter, :parent
26
+
27
+ # @return [Array<Measurement>] Measurements for this reading
28
+ # @see Meter#measurements
29
+ def measurements(start_date, end_date, raw = false)
30
+ meter.measurements_by_name(start_date, end_date, raw)[type] || []
31
+ end
32
+
33
+ # @return [true] if the {#period} is 'instant'
34
+ # @return [false] if the {#period} is 'duration'
35
+ def instantaneous?
36
+ period == "instant"
37
+ end
38
+
39
+ # @return [Boolean] The opposite of {#instantaneous?}
40
+ def durational?
41
+ !instantaneous?
42
+ end
43
+
44
+ # One reading is equal to another if the meters are equal and they are the same type
45
+ # @return [Boolean]
46
+ # @param [Reading] other The other reading to compare with.
47
+ def ==(other)
48
+ meter == other.meter && type == other.type
49
+ end
50
+
51
+ # A unique id for the reading, composed of the {Meter meter} id, and the {#type}. So an
52
+ # '<code>electricalInput</code>' reading for a meter with id '<code>b7ddac00-9415-012d-b57e-001c23973687</code>' would
53
+ # have the id '<code>b7ddac00-9415-012d-b57e-001c23973687-electricalInput</code>'.
54
+ # @return [String] the id
55
+ def id
56
+ "#{meter.id}-#{type}"
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,130 @@
1
+ require 'uri'
2
+
3
+ module AMON
4
+ # Session objects take care of making the actual HTTP requests to the AMON API
5
+ #
6
+ # ## Caching ##
7
+ #
8
+ # Sessions support caching which is enabled by default, but can be optionally turned off. When
9
+ # caching is enabled, the same request will not be performed twice in a session. Be aware that
10
+ # this has some important implications:
11
+ #
12
+ # * If a long running process uses the same session, the cache may become stale as the backend
13
+ # data changes, but new API requests are not made.
14
+ # * There is no mechanism for automatically expiring the cache; this is left up to users of the
15
+ # library.
16
+ # * The cache stores the AMON objects, rather than the raw response data. In this sense it
17
+ # functions as a sort of identity map - getting the same entity twice will return exactly the
18
+ # same object twice, rather than two different objects representing the same data.
19
+ #
20
+ # Often the most natural way to 'expire the cache' is to discard the session and use a new one
21
+ # at regular intervals. Alternatively, you can use {Session#clear_cache} and keep the same
22
+ # session.
23
+ class Session
24
+ # @return [Hash] The hash of configuration options to be used when making requests
25
+ attr_reader :options
26
+
27
+ # The default options for a session
28
+ DEFAULT_OPTIONS = {
29
+ :base_uri => nil,
30
+ :user => nil,
31
+ :password => nil,
32
+ :cache => true
33
+ }.freeze
34
+
35
+ # @param [Hash] options the options for the session
36
+ # @option options [String] :base_uri The base URI for the AMON API, e.g. "http://amon.amee.com/1"
37
+ # (note that this includes the API version, as this library only knows about version 1 of the API)
38
+ # @option options [String] :user The HTTP user for authentication
39
+ # @option options [String] :password The HTTP password for authentication
40
+ # @option options [Boolean] :cache (true) Whether to perform caching or not. See above for details.
41
+ def initialize(options = {})
42
+ @options = DEFAULT_OPTIONS.merge(options)
43
+ @options.freeze
44
+ end
45
+
46
+ # Retrieves an entity from the API
47
+ # @param [String] entity_id the ID of the entity to be requested
48
+ # @return [Entity]
49
+ def entity(entity_id)
50
+ cache(:entities, entity_id) do
51
+ json = get("/entities/#{URI.escape(entity_id)}")['entity']
52
+ Entity.new(self, json)
53
+ end
54
+ end
55
+
56
+ # Retrieves a meter from the API
57
+ # @param [String] meter_id the ID of the meter to be requested
58
+ # @return [Meter]
59
+ def meter(meter_id)
60
+ cache(:meters, meter_id) do
61
+ json = get("/meters/#{URI.escape(meter_id)}")['meter']
62
+ Meter.new(self, json)
63
+ end
64
+ end
65
+
66
+ # Retrieves a metering point from the API
67
+ # @param [String] metering_point_id the ID of the metering point to be requested
68
+ # @return [MeteringPoint]
69
+ def metering_point(metering_point_id)
70
+ cache(:metering_points, :metering_point_id) do
71
+ json = get("/metering-points/#{URI.escape(metering_point_id)}")['metering_point']
72
+ MeteringPoint.new(self, json)
73
+ end
74
+ end
75
+
76
+ # Retrieves measurements from the API
77
+ # @param [String] meter_id The ID of the meter to get the measurements from
78
+ # @param [Time] start_date The starting point for the measurements
79
+ # @param [Time] end_date The ending point for the measurements
80
+ # @param [Boolean] raw Whether to return raw measurements as submitted by the hardware (may
81
+ # contain a lot of data), or appropriate aggregations over the time period
82
+ def measurements(meter_id, start_date, end_date, raw = false)
83
+ cache(:measurements, [meter_id, start_date, end_date, raw]) do
84
+ meter = meter(meter_id)
85
+ measurements = get(
86
+ "/meters/#{meter.id}/measurements?" +
87
+ "raw=" + raw.to_s + "&" +
88
+ "startDate=" + start_date.utc.xmlschema + "&" +
89
+ "endDate=" + end_date.utc.xmlschema
90
+ )['measurements']
91
+ measurements.map { |measurement| Measurement.new(meter, measurement) }
92
+ end
93
+ end
94
+
95
+ # Completely clears the cache
96
+ def clear_cache
97
+ @cache = nil
98
+ end
99
+
100
+ private
101
+
102
+ def cache(group, id, &block)
103
+ if options[:cache]
104
+ @cache ||= {}
105
+ @cache[group] ||= {}
106
+ @cache[group][id] ||= block.call
107
+ else
108
+ block.call
109
+ end
110
+ end
111
+
112
+ def get(url, params = {})
113
+ JSON.parse(client[url].get(:params => params))
114
+ end
115
+
116
+ def client
117
+ raise ArgumentError, "Can't make a request without :base_uri option" unless options[:base_uri]
118
+
119
+ @client ||= RestClient::Resource.new(
120
+ options[:base_uri],
121
+ :user => options[:user],
122
+ :password => options[:password],
123
+ :headers => {
124
+ :content_type => 'application/json',
125
+ :accept => 'application/json'
126
+ }
127
+ )
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,10 @@
1
+ module AMON
2
+ # Provides details about the version of the AMON library in use.
3
+ module Version
4
+ MAJOR = 0
5
+ MINOR = 3
6
+ TINY = 0
7
+
8
+ STRING = "#{MAJOR}.#{MINOR}.#{TINY}"
9
+ end
10
+ end
data/lib/amon.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'json'
2
+ require 'rest-client'
3
+
4
+ module AMON
5
+ autoload :JSONHelper, 'amon/json_helper'
6
+ autoload :Document, 'amon/document'
7
+ autoload :DocumentPart, 'amon/document_part'
8
+ autoload :Entity, 'amon/entity'
9
+ autoload :Meter, 'amon/meter'
10
+ autoload :MeteringPoint, 'amon/metering_point'
11
+ autoload :Metadata, 'amon/metadata'
12
+ autoload :Reading, 'amon/reading'
13
+ autoload :Measurement, 'amon/measurement'
14
+ autoload :Version, 'amon/version'
15
+ autoload :Session, 'amon/session'
16
+
17
+ require 'amon/default_session'
18
+ end
data/rails/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'amon'
metadata ADDED
@@ -0,0 +1,160 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: amon
3
+ version: !ruby/object:Gem::Version
4
+ hash: 19
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 3
9
+ - 0
10
+ version: 0.3.0
11
+ platform: ruby
12
+ authors:
13
+ - AMEE
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-08-25 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: json
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ hash: 7
29
+ segments:
30
+ - 1
31
+ - 4
32
+ - 0
33
+ version: 1.4.0
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: rest-client
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ hash: 15
45
+ segments:
46
+ - 1
47
+ - 6
48
+ - 0
49
+ version: 1.6.0
50
+ type: :runtime
51
+ version_requirements: *id002
52
+ - !ruby/object:Gem::Dependency
53
+ name: rspec
54
+ prerelease: false
55
+ requirement: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ~>
59
+ - !ruby/object:Gem::Version
60
+ hash: 27
61
+ segments:
62
+ - 1
63
+ - 3
64
+ - 0
65
+ version: 1.3.0
66
+ type: :development
67
+ version_requirements: *id003
68
+ - !ruby/object:Gem::Dependency
69
+ name: mocha
70
+ prerelease: false
71
+ requirement: &id004 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ hash: 43
77
+ segments:
78
+ - 0
79
+ - 9
80
+ - 8
81
+ version: 0.9.8
82
+ type: :development
83
+ version_requirements: *id004
84
+ - !ruby/object:Gem::Dependency
85
+ name: fakeweb
86
+ prerelease: false
87
+ requirement: &id005 !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ~>
91
+ - !ruby/object:Gem::Version
92
+ hash: 27
93
+ segments:
94
+ - 1
95
+ - 3
96
+ - 0
97
+ version: 1.3.0
98
+ type: :development
99
+ version_requirements: *id005
100
+ description:
101
+ email:
102
+ executables: []
103
+
104
+ extensions: []
105
+
106
+ extra_rdoc_files: []
107
+
108
+ files:
109
+ - lib/amon/default_session.rb
110
+ - lib/amon/document.rb
111
+ - lib/amon/document_part.rb
112
+ - lib/amon/entity.rb
113
+ - lib/amon/json_helper.rb
114
+ - lib/amon/measurement.rb
115
+ - lib/amon/metadata.rb
116
+ - lib/amon/meter.rb
117
+ - lib/amon/metering_point.rb
118
+ - lib/amon/reading.rb
119
+ - lib/amon/session.rb
120
+ - lib/amon/version.rb
121
+ - lib/amon.rb
122
+ - README.md
123
+ - init.rb
124
+ - rails/init.rb
125
+ homepage: http://amee.com
126
+ licenses: []
127
+
128
+ post_install_message:
129
+ rdoc_options: []
130
+
131
+ require_paths:
132
+ - lib
133
+ required_ruby_version: !ruby/object:Gem::Requirement
134
+ none: false
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ hash: 3
139
+ segments:
140
+ - 0
141
+ version: "0"
142
+ required_rubygems_version: !ruby/object:Gem::Requirement
143
+ none: false
144
+ requirements:
145
+ - - ">="
146
+ - !ruby/object:Gem::Version
147
+ hash: 3
148
+ segments:
149
+ - 0
150
+ version: "0"
151
+ requirements: []
152
+
153
+ rubyforge_project:
154
+ rubygems_version: 1.7.2
155
+ signing_key:
156
+ specification_version: 3
157
+ summary: Ruby client for the AMEE AMON API
158
+ test_files: []
159
+
160
+ has_rdoc: