medic 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +210 -10
- data/lib/medic.rb +1 -3
- data/lib/medic/anchor.rb +32 -0
- data/lib/medic/anchored_object_query.rb +18 -0
- data/lib/medic/correlation_query.rb +22 -0
- data/lib/medic/finders.rb +122 -0
- data/lib/medic/hk_constants.rb +76 -0
- data/lib/medic/interval.rb +29 -0
- data/lib/medic/medic.rb +68 -1
- data/lib/medic/observer_query.rb +15 -0
- data/lib/medic/predicate.rb +39 -0
- data/lib/medic/query_options.rb +23 -0
- data/lib/medic/sample_query.rb +22 -0
- data/lib/medic/sort.rb +24 -0
- data/lib/medic/source_query.rb +15 -0
- data/lib/medic/statistics_collection_query.rb +39 -0
- data/lib/medic/statistics_options.rb +31 -0
- data/lib/medic/statistics_query.rb +17 -0
- data/lib/medic/store.rb +117 -0
- data/lib/medic/types.rb +100 -0
- data/lib/medic/version.rb +1 -1
- data/spec/medic/anchor.rb +16 -0
- data/spec/medic/anchored_object_query_spec.rb +12 -0
- data/spec/medic/correlation_query_spec.rb +16 -0
- data/spec/medic/hk_constants_spec.rb +67 -0
- data/spec/medic/interval_spec.rb +16 -0
- data/spec/medic/medic_spec.rb +153 -0
- data/spec/medic/observer_query_spec.rb +12 -0
- data/spec/medic/predicate_spec.rb +27 -0
- data/spec/medic/query_options_spec.rb +24 -0
- data/spec/medic/sample_query_spec.rb +12 -0
- data/spec/medic/sort_spec.rb +26 -0
- data/spec/medic/source_query_spec.rb +12 -0
- data/spec/medic/statistics_collection_query_spec.rb +27 -0
- data/spec/medic/statistics_options_spec.rb +32 -0
- data/spec/medic/statistics_query_spec.rb +12 -0
- data/spec/medic/store_spec.rb +159 -0
- data/spec/medic/types_spec.rb +95 -0
- metadata +72 -9
- data/spec/main_spec.rb +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bf3a75beba5a3f3be3df75476d6d18d188752bac
|
4
|
+
data.tar.gz: 01bb258ba550c735090e7d04df792972562f4f91
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 02ff5adbb1f076e1e95fee777d4d5289e0bd1eb73808f32d3ee90a6b2a45aafc27b13e323ea96885e55294e4356d2eb783cbd02e7b271287a7dc1afa07df7fa1
|
7
|
+
data.tar.gz: 780718864993970ea3889ac42df1627066152d3862aab9be21f7f5eded7b146195874fff3c1a68497dc46b14482aa5348f089c70eac31e9572250511ee34ca8e
|
data/README.md
CHANGED
@@ -1,24 +1,224 @@
|
|
1
|
-
# medic
|
1
|
+
# Medic [![Gem Version](https://badge.fury.io/rb/medic.svg)](http://badge.fury.io/rb/medic) [![Build Status](https://travis-ci.org/ryanlntn/medic.svg)](https://travis-ci.org/ryanlntn/medic) [![Code Climate](https://codeclimate.com/github/ryanlntn/medic/badges/gpa.svg)](https://codeclimate.com/github/ryanlntn/medic) [![Dependency Status](https://gemnasium.com/ryanlntn/medic.svg)](https://gemnasium.com/ryanlntn/medic)
|
2
2
|
|
3
|
-
|
3
|
+
Is HealthKit's verbose and convoluted API driving you to autolobotomization? Quick! You need a medic!
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
7
|
-
Add this line to your application's Gemfile:
|
7
|
+
1. Add this line to your application's Gemfile:
|
8
8
|
|
9
|
-
|
9
|
+
```ruby
|
10
|
+
gem 'medic'
|
11
|
+
```
|
10
12
|
|
11
|
-
|
13
|
+
1. Add the following lines to your Rakefile:
|
12
14
|
|
13
|
-
|
15
|
+
```ruby
|
16
|
+
app.entitlements['com.apple.developer.healthkit'] = true
|
17
|
+
app.frameworks += ['HealthKit']
|
18
|
+
```
|
14
19
|
|
15
|
-
|
16
|
-
|
17
|
-
$ gem install medic
|
20
|
+
1. Run `bundle` and `rake`.
|
18
21
|
|
19
22
|
## Usage
|
20
23
|
|
21
|
-
|
24
|
+
### Authorization
|
25
|
+
|
26
|
+
To request authorization to read or share (i.e. write) a data type implement the following in `viewDidAppear` of your `UIViewController`:
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
if Medic.available?
|
30
|
+
types = { share: :step_count, read: [:step_count, :date_of_birth] }
|
31
|
+
|
32
|
+
Medic.authorize types do |success, error|
|
33
|
+
NSLog "Success!" if success
|
34
|
+
end
|
35
|
+
end
|
36
|
+
```
|
37
|
+
|
38
|
+
This will open the permissions modal. `success` will be `false` if the user canceled the prompt without selecting permissions; `true` otherwise.
|
39
|
+
|
40
|
+
You can subsequently check if you're authorized to share a data type:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
Medic.authorized?(:step_count)
|
44
|
+
```
|
45
|
+
|
46
|
+
Note: For privacy reasons Apple does not allow you to check if you're authorized to read data types.
|
47
|
+
|
48
|
+
### Sharing Samples
|
49
|
+
|
50
|
+
Coming soon...
|
51
|
+
|
52
|
+
### Reading Data
|
53
|
+
|
54
|
+
HealthKit provides a number of methods for accessing its data, mostly in the form of query objects with verbose initializers that return more `HKObject`s with repetitive method names. For example, if I wanted to get the total number of steps taken per day for the last week I could use a `HKStatisticsCollectionQuery` like so:
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
@store = HKHealthStore.new
|
58
|
+
|
59
|
+
today = NSDate.date
|
60
|
+
one_week_ago = NSCalendar.currentCalendar.dateByAddingComponents(NSDateComponents.new.setDay(-7), toDate: today, options: 0)
|
61
|
+
|
62
|
+
query = HKStatisticsCollectionQuery.initWithQuantityType(
|
63
|
+
HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount),
|
64
|
+
quantitySamplePredicate: nil,
|
65
|
+
options: HKStatisticsOptionCumulativeSum,
|
66
|
+
anchorDate: one_week_ago,
|
67
|
+
intervalComponents: (NSDateComponents.new.day = 1)
|
68
|
+
)
|
69
|
+
|
70
|
+
query.initialResultsHandler = ->(query, results, error){
|
71
|
+
results.enumerateStatisticsFromDate(one_week_ago, toDate: today, withBlock: ->(result, stop){
|
72
|
+
if quantity = result.sumQuantity
|
73
|
+
NSLog quantity.doubleValueForUnit(HKUnit.countUnit).to_s
|
74
|
+
end
|
75
|
+
})
|
76
|
+
}
|
77
|
+
|
78
|
+
@store.executeQuery(query)
|
79
|
+
```
|
80
|
+
|
81
|
+
This doesn't make for the most readable code. As a Ruby developer you might find this downright distasteful. Let's check out the Medic equivalent:
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
options = { options: :sum, anchor: :one_week_ago, interval: :day}
|
85
|
+
|
86
|
+
Medic.find_statistics_collection :step_count, options do |statistics|
|
87
|
+
statistics.each do |stats|
|
88
|
+
NSLog stats[:sum].to_s
|
89
|
+
end
|
90
|
+
end
|
91
|
+
```
|
92
|
+
|
93
|
+
Now that's more like it! Instead of constructing `HKObjectType` by hand we can now just pass in a symbol. We also don't have to work directly with `HKStatisticsCollection` anymore. The result is parsed into an array of hashes with reasonable values for us.
|
94
|
+
|
95
|
+
#### Finders
|
96
|
+
|
97
|
+
Medic provides a finder for each class of `HKQuery`:
|
98
|
+
|
99
|
+
##### find_anchored
|
100
|
+
|
101
|
+
Provide an easy way to search for new data in the HealthKit store.
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
@anchor = nil
|
105
|
+
|
106
|
+
Medic.find_anchored :step_count, anchor: @anchor do |results, new_anchor|
|
107
|
+
@anchor = new_anchor
|
108
|
+
results.each do |sample|
|
109
|
+
NSLog sample.to_s
|
110
|
+
end
|
111
|
+
end
|
112
|
+
```
|
113
|
+
|
114
|
+
##### find_correlation
|
115
|
+
|
116
|
+
Search for correlations in the HealthKit store.
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
high_cal = HKQuantity.quantityWithUnit(HKUnit.kilocalorieUnit, doubleValue: 800.0)
|
120
|
+
greater_than_high_cal = HKQuery.predicateForQuantitySamplesWithOperatorType(NSGreaterThanOrEqualToPredicateOperatorType, quantity: high_cal)
|
121
|
+
|
122
|
+
sample_predicates = { dietary_energy_consumed: greater_than_high_cal }
|
123
|
+
|
124
|
+
Medic.find_correlations :food, sample_predicates: sample_predicates do |correlations|
|
125
|
+
correlations.each do |correlation|
|
126
|
+
NSLog correlation.to_s
|
127
|
+
end
|
128
|
+
end
|
129
|
+
```
|
130
|
+
|
131
|
+
##### observe
|
132
|
+
|
133
|
+
Set up a long-running task on a background queue.
|
134
|
+
|
135
|
+
```ruby
|
136
|
+
Medic.observe :step_count do |completion, error|
|
137
|
+
Medic.find_sources :step_count do |sources|
|
138
|
+
sources.each do |source|
|
139
|
+
NSLog source
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
```
|
144
|
+
|
145
|
+
##### find_samples
|
146
|
+
|
147
|
+
Search for sample data in the HealthKit store.
|
148
|
+
|
149
|
+
```ruby
|
150
|
+
Medic.find_samples :blood_pressure, sort: :start_date, limit: 7 do |samples|
|
151
|
+
samples.each do |sample|
|
152
|
+
NSLog sample.to_s
|
153
|
+
end
|
154
|
+
end
|
155
|
+
```
|
156
|
+
|
157
|
+
##### find_sources
|
158
|
+
|
159
|
+
Search for the sources (apps and devices) that have saved data to the HealthKit store.
|
160
|
+
|
161
|
+
```ruby
|
162
|
+
Medic.find_sources :step_count do |sources|
|
163
|
+
sources.each do |source|
|
164
|
+
NSLog source
|
165
|
+
end
|
166
|
+
end
|
167
|
+
```
|
168
|
+
|
169
|
+
##### find_statistics
|
170
|
+
|
171
|
+
Perform statistical calculations over the set of matching quantity samples.
|
172
|
+
|
173
|
+
```ruby
|
174
|
+
Medic.find_statistics :step_count, options: :sum do |statistics|
|
175
|
+
NSLog statistics.to_s
|
176
|
+
end
|
177
|
+
```
|
178
|
+
|
179
|
+
##### find_statistics_collection
|
180
|
+
|
181
|
+
Perform multiple statistics queries over a series of fixed-length time intervals.
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
options = { options: :sum, anchor: :one_week_ago, interval: :day}
|
185
|
+
|
186
|
+
Medic.find_statistics_collection :step_count, options do |statistics|
|
187
|
+
statistics.each do |stats|
|
188
|
+
NSLog stats[:sum].to_s
|
189
|
+
end
|
190
|
+
end
|
191
|
+
```
|
192
|
+
|
193
|
+
#### Characteristic Data
|
194
|
+
|
195
|
+
Characteristic data like biological sex or blood type have their own methods:
|
196
|
+
|
197
|
+
```ruby
|
198
|
+
Medic.biological_sex # => :male
|
199
|
+
Medic.date_of_birth # => 1987-11-07 00:00:00 -0800
|
200
|
+
Medic.blood_type # => :o_negative
|
201
|
+
```
|
202
|
+
|
203
|
+
#### Queries
|
204
|
+
|
205
|
+
If for some reason you need to access the `HKSample` objects directly you can use Medic's Query objects:
|
206
|
+
|
207
|
+
```ruby
|
208
|
+
query_params = { type: :dietary_protein, sort_desc: :start_date, limit: 7 }
|
209
|
+
|
210
|
+
query = Medic::SampleQuery.new query_params do |query, results, error|
|
211
|
+
if results
|
212
|
+
results.each do |sample|
|
213
|
+
NSLog "#{sample.startDate} - #{sample.quantity.doubleValueForUnit(HKUnit.gramUnit)}"
|
214
|
+
end
|
215
|
+
else
|
216
|
+
NSLog "no results"
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
Medic.execute(query)
|
221
|
+
```
|
22
222
|
|
23
223
|
## Contributing
|
24
224
|
|
data/lib/medic.rb
CHANGED
@@ -1,10 +1,8 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
unless defined?(Motion::Project::Config)
|
4
2
|
raise "This file must be required within a RubyMotion project Rakefile."
|
5
3
|
end
|
6
4
|
|
7
5
|
lib_dir_path = File.dirname(File.expand_path(__FILE__))
|
8
6
|
Motion::Project::App.setup do |app|
|
9
|
-
app.files.unshift(Dir.glob(File.join(lib_dir_path, "
|
7
|
+
app.files.unshift(Dir.glob(File.join(lib_dir_path, "medic/**/*.rb")))
|
10
8
|
end
|
data/lib/medic/anchor.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
module Medic
|
2
|
+
module Anchor
|
3
|
+
|
4
|
+
NUMBER_WORDS = {
|
5
|
+
'zero' => 0, 'one' => 1, 'two' => 2, 'three' => 3, 'four' => 4, 'five' => 5,
|
6
|
+
'six' => 6, 'seven' => 7, 'eight' => 8, 'nine' => 9, 'ten' => 10, 'eleven' => 11,
|
7
|
+
'twelve' => 12, 'thirteen' => 13, 'fourteen' => 14, 'fifteen' => 15, 'sixteen' => 16,
|
8
|
+
'seventeen' => 17, 'eighteen' => 18, 'nineteen' => 19, 'twenty' => 20, 'thirty' => 30,
|
9
|
+
'fourty' => 40, 'fifty' => 50, 'sixty' => 60, 'seventy' => 70, 'eighty' => 80,
|
10
|
+
'ninety' => 90, 'hundred' => 100
|
11
|
+
}
|
12
|
+
|
13
|
+
def anchor_for_symbol(sym)
|
14
|
+
return unless sym
|
15
|
+
return sym if sym.to_s == '0'
|
16
|
+
return sym if sym.is_a? NSDate
|
17
|
+
parts = sym.to_s.gsub('_', ' ').split.reject{ |part| part == 'ago' }
|
18
|
+
component = parts.pop.chomp('s')
|
19
|
+
n = parts.map{|p| NUMBER_WORDS[p] || p.to_i}.reduce do |sum, p|
|
20
|
+
if p == 100 && sum > 0
|
21
|
+
sum * p
|
22
|
+
else
|
23
|
+
sum + p
|
24
|
+
end
|
25
|
+
end
|
26
|
+
n ||= 1
|
27
|
+
date_comp = NSDateComponents.new.send("#{component}=", -n)
|
28
|
+
NSCalendar.currentCalendar.dateByAddingComponents(date_comp, toDate: NSDate.date, options: 0)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Medic
|
2
|
+
class AnchoredObjectQuery < HKAnchoredObjectQuery
|
3
|
+
|
4
|
+
include Medic::Types
|
5
|
+
include Medic::Predicate
|
6
|
+
include Medic::Anchor
|
7
|
+
|
8
|
+
def initialize(args={}, block=Proc.new)
|
9
|
+
self.initWithType(object_type(args[:type]),
|
10
|
+
predicate: predicate(args),
|
11
|
+
anchor: anchor_for_symbol(args[:anchor_date] || args[:anchor] || args[:date] || HKAnchoredObjectQueryNoAnchor),
|
12
|
+
limit: args[:limit] || HKObjectQueryNoLimit,
|
13
|
+
completionHandler: block
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Medic
|
2
|
+
class CorrelationQuery < HKCorrelationQuery
|
3
|
+
|
4
|
+
include Medic::Types
|
5
|
+
include Medic::Predicate
|
6
|
+
|
7
|
+
def initialize(args={}, block=Proc.new)
|
8
|
+
self.initWithType(object_type(args[:type]),
|
9
|
+
predicate: predicate(args),
|
10
|
+
samplePredicates: sample_predicates(args[:sample_predicates]),
|
11
|
+
completion: block
|
12
|
+
)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def sample_predicates(predicates)
|
18
|
+
Hash[ predicates.map{ |type, pred| [object_type(type), predicate(pred)] } ]
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
module Medic
|
2
|
+
module Finders
|
3
|
+
|
4
|
+
def observe(type, options={}, block=Proc.new)
|
5
|
+
query_params = options.merge(type: type)
|
6
|
+
query = Medic::ObserverQuery.new query_params do |query, completion, error|
|
7
|
+
block.call(completion, error)
|
8
|
+
end
|
9
|
+
Medic.execute(query)
|
10
|
+
end
|
11
|
+
|
12
|
+
def find_sources(type, options={}, block=Proc.new)
|
13
|
+
query_params = options.merge(type: type)
|
14
|
+
query = Medic::SourceQuery.new query_params do |query, results, error|
|
15
|
+
sources = results ? results.allObjects.map{ |source| source.name.to_s } : []
|
16
|
+
block.call(sources)
|
17
|
+
end
|
18
|
+
Medic.execute(query)
|
19
|
+
end
|
20
|
+
|
21
|
+
def find_samples(type, options={}, block=Proc.new)
|
22
|
+
query_params = options.merge(type: type)
|
23
|
+
query = Medic::SampleQuery.new query_params do |query, results, error|
|
24
|
+
block.call(samples_to_hashes(Array(results)))
|
25
|
+
end
|
26
|
+
Medic.execute(query)
|
27
|
+
end
|
28
|
+
|
29
|
+
def find_correlations(type, options={}, block=Proc.new)
|
30
|
+
query_params = options.merge(type: type)
|
31
|
+
query = Medic::CorrelationQuery.new query_params do |query, correlations, error|
|
32
|
+
block.call(samples_to_hashes(Array(correlations)))
|
33
|
+
end
|
34
|
+
Medic.execute(query)
|
35
|
+
end
|
36
|
+
|
37
|
+
def find_anchored(type, options={}, block=Proc.new)
|
38
|
+
query_params = options.merge(type: type)
|
39
|
+
query = Medic::AnchoredObjectQuery.new query_params do |query, results, new_anchor, error|
|
40
|
+
block.call(samples_to_hashes(Array(results)), new_anchor)
|
41
|
+
end
|
42
|
+
Medic.execute(query)
|
43
|
+
end
|
44
|
+
|
45
|
+
def find_statistics(type, options={}, block=Proc.new)
|
46
|
+
query_params = options.merge(type: type)
|
47
|
+
query = Medic::StatisticsQuery.new query_params do |query, statistics, error|
|
48
|
+
block.call(statistics_to_hash(statistics)) if statistics
|
49
|
+
end
|
50
|
+
Medic.execute(query)
|
51
|
+
end
|
52
|
+
|
53
|
+
def find_statistics_collection(type, options={}, block=Proc.new)
|
54
|
+
query_params = options.merge(type: type)
|
55
|
+
query = Medic::StatisticsCollectionQuery.new query_params do |query, collection, error|
|
56
|
+
formatted_stats = []
|
57
|
+
collection.enumerateStatisticsFromDate(collection.anchorDate, toDate: NSDate.date, withBlock: ->(result, stop){
|
58
|
+
formatted_stats << statistics_to_hash(result)
|
59
|
+
})
|
60
|
+
block.call(formatted_stats)
|
61
|
+
end
|
62
|
+
Medic.execute(query)
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def samples_to_hashes(samples)
|
68
|
+
samples.map do |sample|
|
69
|
+
h = {}
|
70
|
+
h[:uuid] = sample.UUID.UUIDString
|
71
|
+
h[:metadata] = sample.metadata
|
72
|
+
h[:source] = sample.source.name
|
73
|
+
h[:start_date] = sample.startDate
|
74
|
+
h[:end_date] = sample.endDate
|
75
|
+
h[:sample_type] = Medic::Types::TYPE_IDENTIFIERS.index(sample.sampleType.identifier)
|
76
|
+
|
77
|
+
if sample.respond_to?(:categoryType) && sample.respond_to?(:value)
|
78
|
+
h[:category_type] = Medic::Types::TYPE_IDENTIFIERS.index(sample.categoryType.identifier)
|
79
|
+
h[:value] = [:in_bed, :asleep][sample.value] # SleepAnalysis is the only category type at the moment
|
80
|
+
end
|
81
|
+
|
82
|
+
if sample.respond_to?(:correlationType) && sample.respond_to?(:objects)
|
83
|
+
h[:correlation_type] = Medic::Types::TYPE_IDENTIFIERS.index(sample.correlationType.identifier)
|
84
|
+
h[:objects] = samples_to_hashes(Array(sample.objects.allObjects))
|
85
|
+
end
|
86
|
+
|
87
|
+
if sample.respond_to?(:quantity) && sample.respond_to?(:quantityType)
|
88
|
+
h[:quantity] = sample.quantity.doubleValueForUnit(sample.quantityType.canonicalUnit)
|
89
|
+
h[:quantity_type] = Medic::Types::TYPE_IDENTIFIERS.index(sample.quantityType.identifier)
|
90
|
+
h[:canonical_unit] = sample.quantityType.canonicalUnit.unitString
|
91
|
+
end
|
92
|
+
|
93
|
+
h[:duration] = sample.duration if sample.respond_to?(:duration)
|
94
|
+
h[:total_distance] = sample.totalDistance if sample.respond_to?(:totalDistance)
|
95
|
+
h[:total_energy_burned] = sample.totalEnergyBurned if sample.respond_to?(:totalEnergyBurned)
|
96
|
+
h[:workout_activity_type] = sample.workoutActivityType if sample.respond_to?(:workoutActivityType)
|
97
|
+
h[:workout_events] = sample.workoutEvents if sample.respond_to?(:workoutEvents)
|
98
|
+
h
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def statistics_to_hash(stats)
|
103
|
+
h = {}
|
104
|
+
h[:start_date] = stats.startDate
|
105
|
+
h[:end_date] = stats.endDate
|
106
|
+
h[:sources] = stats.sources.map(&:name) if stats.sources
|
107
|
+
h[:quantity_type] = Medic::Types::TYPE_IDENTIFIERS.index(stats.quantityType.identifier)
|
108
|
+
h[:canonical_unit] = stats.quantityType.canonicalUnit.unitString
|
109
|
+
h[:data_count] = stats.dataCount
|
110
|
+
h[:average] = stats.averageQuantity.doubleValueForUnit(stats.quantityType.canonicalUnit) if stats.averageQuantity
|
111
|
+
h[:minimum] = stats.minimumQuantity.doubleValueForUnit(stats.quantityType.canonicalUnit) if stats.minimumQuantity
|
112
|
+
h[:maximum] = stats.maximumQuantity.doubleValueForUnit(stats.quantityType.canonicalUnit) if stats.maximumQuantity
|
113
|
+
h[:sum] = stats.sumQuantity.doubleValueForUnit(stats.quantityType.canonicalUnit) if stats.sumQuantity
|
114
|
+
h[:average_by_source] = stats.averageQuantityBySource.doubleValueForUnit(stats.quantityType.canonicalUnit) if stats.averageQuantityBySource
|
115
|
+
h[:minimum_by_source] = stats.minimumQuantityBySource.doubleValueForUnit(stats.quantityType.canonicalUnit) if stats.minimumQuantityBySource
|
116
|
+
h[:maximum_by_source] = stats.maximumQuantityBySource.doubleValueForUnit(stats.quantityType.canonicalUnit) if stats.maximumQuantityBySource
|
117
|
+
h[:sum_by_source] = stats.sumQuantityBySource.doubleValueForUnit(stats.quantityType.canonicalUnit) if stats.sumQuantityBySource
|
118
|
+
h
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
end
|