medic 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +210 -10
  3. data/lib/medic.rb +1 -3
  4. data/lib/medic/anchor.rb +32 -0
  5. data/lib/medic/anchored_object_query.rb +18 -0
  6. data/lib/medic/correlation_query.rb +22 -0
  7. data/lib/medic/finders.rb +122 -0
  8. data/lib/medic/hk_constants.rb +76 -0
  9. data/lib/medic/interval.rb +29 -0
  10. data/lib/medic/medic.rb +68 -1
  11. data/lib/medic/observer_query.rb +15 -0
  12. data/lib/medic/predicate.rb +39 -0
  13. data/lib/medic/query_options.rb +23 -0
  14. data/lib/medic/sample_query.rb +22 -0
  15. data/lib/medic/sort.rb +24 -0
  16. data/lib/medic/source_query.rb +15 -0
  17. data/lib/medic/statistics_collection_query.rb +39 -0
  18. data/lib/medic/statistics_options.rb +31 -0
  19. data/lib/medic/statistics_query.rb +17 -0
  20. data/lib/medic/store.rb +117 -0
  21. data/lib/medic/types.rb +100 -0
  22. data/lib/medic/version.rb +1 -1
  23. data/spec/medic/anchor.rb +16 -0
  24. data/spec/medic/anchored_object_query_spec.rb +12 -0
  25. data/spec/medic/correlation_query_spec.rb +16 -0
  26. data/spec/medic/hk_constants_spec.rb +67 -0
  27. data/spec/medic/interval_spec.rb +16 -0
  28. data/spec/medic/medic_spec.rb +153 -0
  29. data/spec/medic/observer_query_spec.rb +12 -0
  30. data/spec/medic/predicate_spec.rb +27 -0
  31. data/spec/medic/query_options_spec.rb +24 -0
  32. data/spec/medic/sample_query_spec.rb +12 -0
  33. data/spec/medic/sort_spec.rb +26 -0
  34. data/spec/medic/source_query_spec.rb +12 -0
  35. data/spec/medic/statistics_collection_query_spec.rb +27 -0
  36. data/spec/medic/statistics_options_spec.rb +32 -0
  37. data/spec/medic/statistics_query_spec.rb +12 -0
  38. data/spec/medic/store_spec.rb +159 -0
  39. data/spec/medic/types_spec.rb +95 -0
  40. metadata +72 -9
  41. data/spec/main_spec.rb +0 -9
@@ -0,0 +1,100 @@
1
+ module Medic
2
+ module Types
3
+
4
+ TYPE_IDENTIFIERS = {
5
+ body_mass_index: HKQuantityTypeIdentifierBodyMassIndex,
6
+ body_fat_percentage: HKQuantityTypeIdentifierBodyFatPercentage,
7
+ height: HKQuantityTypeIdentifierHeight,
8
+ body_mass: HKQuantityTypeIdentifierBodyMass,
9
+ lean_body_mass: HKQuantityTypeIdentifierLeanBodyMass,
10
+ step_count: HKQuantityTypeIdentifierStepCount,
11
+ distance_walking_running: HKQuantityTypeIdentifierDistanceWalkingRunning,
12
+ distance_cycling: HKQuantityTypeIdentifierDistanceCycling,
13
+ basal_energy_burned: HKQuantityTypeIdentifierBasalEnergyBurned,
14
+ active_energy_burned: HKQuantityTypeIdentifierActiveEnergyBurned,
15
+ flights_climbed: HKQuantityTypeIdentifierFlightsClimbed,
16
+ nike_fuel: HKQuantityTypeIdentifierNikeFuel,
17
+ heart_rate: HKQuantityTypeIdentifierHeartRate,
18
+ body_temperature: HKQuantityTypeIdentifierBodyTemperature,
19
+ blood_pressure_systolic: HKQuantityTypeIdentifierBloodPressureSystolic,
20
+ blood_pressure_diastolic: HKQuantityTypeIdentifierBloodPressureDiastolic,
21
+ respiratory_rate: HKQuantityTypeIdentifierRespiratoryRate,
22
+ oxygen_saturation: HKQuantityTypeIdentifierOxygenSaturation,
23
+ peripheral_perfusion_index: HKQuantityTypeIdentifierPeripheralPerfusionIndex,
24
+ blood_glucose: HKQuantityTypeIdentifierBloodGlucose,
25
+ number_of_times_fallen: HKQuantityTypeIdentifierNumberOfTimesFallen,
26
+ electrodermal_activity: HKQuantityTypeIdentifierElectrodermalActivity,
27
+ inhaler_usage: HKQuantityTypeIdentifierInhalerUsage,
28
+ blood_alcohol_content: HKQuantityTypeIdentifierBloodAlcoholContent,
29
+ forced_vital_capacity: HKQuantityTypeIdentifierForcedVitalCapacity,
30
+ forced_expiratory_volume1: HKQuantityTypeIdentifierForcedExpiratoryVolume1,
31
+ peak_expiratory_flow_rate: HKQuantityTypeIdentifierPeakExpiratoryFlowRate,
32
+ dietary_biotin: HKQuantityTypeIdentifierDietaryBiotin,
33
+ dietary_caffeine: HKQuantityTypeIdentifierDietaryCaffeine,
34
+ dietary_calcium: HKQuantityTypeIdentifierDietaryCalcium,
35
+ dietary_carbohydrates: HKQuantityTypeIdentifierDietaryCarbohydrates,
36
+ dietary_chloride: HKQuantityTypeIdentifierDietaryChloride,
37
+ dietary_cholesterol: HKQuantityTypeIdentifierDietaryCholesterol,
38
+ dietary_chromium: HKQuantityTypeIdentifierDietaryChromium,
39
+ dietary_copper: HKQuantityTypeIdentifierDietaryCopper,
40
+ dietary_energy_consumed: HKQuantityTypeIdentifierDietaryEnergyConsumed,
41
+ dietary_fat_monounsaturated: HKQuantityTypeIdentifierDietaryFatMonounsaturated,
42
+ dietary_fat_polyunsaturated: HKQuantityTypeIdentifierDietaryFatPolyunsaturated,
43
+ dietary_fat_saturated: HKQuantityTypeIdentifierDietaryFatSaturated,
44
+ dietary_fat_total: HKQuantityTypeIdentifierDietaryFatTotal,
45
+ dietary_fiber: HKQuantityTypeIdentifierDietaryFiber,
46
+ dietary_folate: HKQuantityTypeIdentifierDietaryFolate,
47
+ dietary_iodine: HKQuantityTypeIdentifierDietaryIodine,
48
+ dietary_iron: HKQuantityTypeIdentifierDietaryIron,
49
+ dietary_magnesium: HKQuantityTypeIdentifierDietaryMagnesium,
50
+ dietary_manganese: HKQuantityTypeIdentifierDietaryManganese,
51
+ dietary_molybdenum: HKQuantityTypeIdentifierDietaryMolybdenum,
52
+ dietary_niacin: HKQuantityTypeIdentifierDietaryNiacin,
53
+ dietary_pantothenic_acid: HKQuantityTypeIdentifierDietaryPantothenicAcid,
54
+ dietary_phosphorus: HKQuantityTypeIdentifierDietaryPhosphorus,
55
+ dietary_potassium: HKQuantityTypeIdentifierDietaryPotassium,
56
+ dietary_protein: HKQuantityTypeIdentifierDietaryProtein,
57
+ dietary_riboflavin: HKQuantityTypeIdentifierDietaryRiboflavin,
58
+ dietary_selenium: HKQuantityTypeIdentifierDietarySelenium,
59
+ dietary_sodium: HKQuantityTypeIdentifierDietarySodium,
60
+ dietary_sugar: HKQuantityTypeIdentifierDietarySugar,
61
+ dietary_thiamin: HKQuantityTypeIdentifierDietaryThiamin,
62
+ dietary_vitamin_a: HKQuantityTypeIdentifierDietaryVitaminA,
63
+ dietary_vitamin_b12: HKQuantityTypeIdentifierDietaryVitaminB12,
64
+ dietary_vitamin_b6: HKQuantityTypeIdentifierDietaryVitaminB6,
65
+ dietary_vitamin_c: HKQuantityTypeIdentifierDietaryVitaminC,
66
+ dietary_vitamin_d: HKQuantityTypeIdentifierDietaryVitaminD,
67
+ dietary_vitamin_e: HKQuantityTypeIdentifierDietaryVitaminE,
68
+ dietary_vitamin_k: HKQuantityTypeIdentifierDietaryVitaminK,
69
+ dietary_zinc: HKQuantityTypeIdentifierDietaryZinc,
70
+ sleep_analysis: HKCategoryTypeIdentifierSleepAnalysis,
71
+ biological_sex: HKCharacteristicTypeIdentifierBiologicalSex,
72
+ blood_type: HKCharacteristicTypeIdentifierBloodType,
73
+ date_of_birth: HKCharacteristicTypeIdentifierDateOfBirth,
74
+ blood_pressure: HKCorrelationTypeIdentifierBloodPressure,
75
+ food: HKCorrelationTypeIdentifierFood,
76
+ workout: HKWorkoutTypeIdentifier
77
+ }
78
+
79
+ def object_type(type)
80
+ return type if type.is_a? HKObjectType
81
+ case type
82
+ when :workout
83
+ HKObjectType.workoutType
84
+ when :sleep_analysis
85
+ HKObjectType.categoryTypeForIdentifier type_identifier(type)
86
+ when :biological_sex, :blood_type, :date_of_birth
87
+ HKObjectType.characteristicTypeForIdentifier type_identifier(type)
88
+ when :blood_pressure, :food
89
+ HKObjectType.correlationTypeForIdentifier type_identifier(type)
90
+ else
91
+ HKObjectType.quantityTypeForIdentifier type_identifier(type)
92
+ end
93
+ end
94
+
95
+ def type_identifier(type)
96
+ type.is_a?(Symbol) ? TYPE_IDENTIFIERS[type] : type
97
+ end
98
+
99
+ end
100
+ end
data/lib/medic/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Medic
2
- VERSION = "0.0.1" unless defined?(Medic::VERSION)
2
+ VERSION = "0.0.2"
3
3
  end
@@ -0,0 +1,16 @@
1
+ describe "Medic::Anchor" do
2
+
3
+ before do
4
+ @subject = Object.new
5
+ @subject.extend(Medic::Anchor)
6
+ end
7
+
8
+ describe "#anchor_for_symbol" do
9
+ it "returns the correct NSDate object for symbol" do
10
+ @subject.anchor_for_symbol(:nine_hundred_ninety_nine_days_ago).should.be.kind_of? NSDate
11
+ @subject.anchor_for_symbol(:nine_hundred_ninety_nine_days_ago).to_s.should == NSCalendar.currentCalendar.dateByAddingComponents(NSDateComponents.new.setDay(-999), toDate: NSDate.date, options: 0).to_s
12
+ @subject.anchor_for_symbol("365 days").to_s.should == NSCalendar.currentCalendar.dateByAddingComponents(NSDateComponents.new.setDay(-365), toDate: NSDate.date, options: 0).to_s
13
+ @subject.anchor_for_symbol(:day).to_s.should == NSCalendar.currentCalendar.dateByAddingComponents(NSDateComponents.new.setDay(-1), toDate: NSDate.date, options: 0).to_s
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,12 @@
1
+ describe "Medic::AnchoredObjectQuery" do
2
+
3
+ before do
4
+ @subject = Medic::AnchoredObjectQuery.new type: :step_count do |query, results, new_anchor, error|
5
+ end
6
+ end
7
+
8
+ it "is a subclass of HKAnchoredObjectQuery" do
9
+ @subject.should.be.kind_of? HKAnchoredObjectQuery
10
+ end
11
+
12
+ end
@@ -0,0 +1,16 @@
1
+ describe "Medic::CorrelationQuery" do
2
+
3
+ before do
4
+ high_cal = HKQuantity.quantityWithUnit(HKUnit.kilocalorieUnit, doubleValue: 800.0)
5
+ greater_than_high_cal = HKQuery.predicateForQuantitySamplesWithOperatorType(NSGreaterThanOrEqualToPredicateOperatorType, quantity: high_cal)
6
+ energy_consumed = HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDietaryEnergyConsumed)
7
+ sample_predicates = { energy_consumed => greater_than_high_cal }
8
+ @subject = Medic::CorrelationQuery.new type: :food, sample_predicates: sample_predicates do |query, correlations, error|
9
+ end
10
+ end
11
+
12
+ it "is a subclass of HKCorrelationQuery" do
13
+ @subject.should.be.kind_of? HKCorrelationQuery
14
+ end
15
+
16
+ end
@@ -0,0 +1,67 @@
1
+ describe "Medic::HKConstants" do
2
+
3
+ before do
4
+ @subject = Object.new
5
+ @subject.extend(Medic::HKConstants)
6
+ end
7
+
8
+ describe "#error_code" do
9
+ it "returns the correct error code for symbol" do
10
+ @subject.error_code(:no_error).should == HKNoError
11
+ @subject.error_code(:health_data_unavailable).should == HKErrorHealthDataUnavailable
12
+ @subject.error_code(:health_data_restricted).should == HKErrorHealthDataRestricted
13
+ @subject.error_code(:invalid_argument).should == HKErrorInvalidArgument
14
+ @subject.error_code(:authorization_denied).should == HKErrorAuthorizationDenied
15
+ @subject.error_code(:authorization_not_determined).should == HKErrorAuthorizationNotDetermined
16
+ @subject.error_code(:database_inaccessible).should == HKErrorDatabaseInaccessible
17
+ @subject.error_code(:user_canceled).should == HKErrorUserCanceled
18
+ end
19
+ end
20
+
21
+ describe "#update_frequency" do
22
+ it "returns the correct update frequency for symbol" do
23
+ @subject.update_frequency(:immediate).should == HKUpdateFrequencyImmediate
24
+ @subject.update_frequency(:hourly).should == HKUpdateFrequencyHourly
25
+ @subject.update_frequency(:daily).should == HKUpdateFrequencyDaily
26
+ @subject.update_frequency(:weekly).should == HKUpdateFrequencyWeekly
27
+ end
28
+ end
29
+
30
+ describe "#authorization_status" do
31
+ it "returns the correct authorization status for symbol" do
32
+ @subject.authorization_status(:not_determined).should == HKAuthorizationStatusNotDetermined
33
+ @subject.authorization_status(:sharing_denied).should == HKAuthorizationStatusSharingDenied
34
+ @subject.authorization_status(:sharing_authorized).should == HKAuthorizationStatusSharingAuthorized
35
+ end
36
+ end
37
+
38
+ describe "#biological_sex" do
39
+ it "returns the correct biological sex for symbol" do
40
+ @subject.biological_sex(:not_set).should == HKBiologicalSexNotSet
41
+ @subject.biological_sex(:female).should == HKBiologicalSexFemale
42
+ @subject.biological_sex(:male).should == HKBiologicalSexMale
43
+ end
44
+ end
45
+
46
+ describe "#blood_type" do
47
+ it "returns the correct blood type for symbol" do
48
+ @subject.blood_type(:not_set).should == HKBloodTypeNotSet
49
+ @subject.blood_type(:a_positive).should == HKBloodTypeAPositive
50
+ @subject.blood_type(:a_negative).should == HKBloodTypeANegative
51
+ @subject.blood_type(:b_positive).should == HKBloodTypeBPositive
52
+ @subject.blood_type(:b_negative).should == HKBloodTypeBNegative
53
+ @subject.blood_type(:a_b_positive).should == HKBloodTypeABPositive
54
+ @subject.blood_type(:a_b_negative).should == HKBloodTypeABNegative
55
+ @subject.blood_type(:o_positive).should == HKBloodTypeOPositive
56
+ @subject.blood_type(:o_negative).should == HKBloodTypeONegative
57
+ end
58
+ end
59
+
60
+ describe "#sleep_analysis" do
61
+ it "returns the correct sleep analysis for symbol" do
62
+ @subject.sleep_analysis(:in_bed).should == HKCategoryValueSleepAnalysisInBed
63
+ @subject.sleep_analysis(:asleep).should == HKCategoryValueSleepAnalysisAsleep
64
+ end
65
+ end
66
+
67
+ end
@@ -0,0 +1,16 @@
1
+ describe "Medic::Interval" do
2
+
3
+ before do
4
+ @subject = Object.new
5
+ @subject.extend(Medic::Interval)
6
+ end
7
+
8
+ describe "#interval" do
9
+ it "returns the correct NSDateComponents object for symbol" do
10
+ @subject.interval(:nine_hundred_ninety_nine_days).should.be.kind_of? NSDateComponents
11
+ @subject.interval(:nine_hundred_ninety_nine_days).day.should == 999
12
+ @subject.interval("365 days").day.should == 365
13
+ @subject.interval(:day).day.should == 1
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,153 @@
1
+ describe "Medic" do
2
+
3
+ before do
4
+ @store = Medic::Store.shared
5
+ end
6
+
7
+ describe ".available?" do
8
+ it "determines if HealthKit is available" do
9
+ Medic.available?.should == true
10
+ end
11
+
12
+ it "has an .is_available? alias" do
13
+ Medic.is_available?.should == true
14
+ end
15
+ end
16
+
17
+ describe ".authorize" do
18
+ it "delegates to Medic::Store" do
19
+ @store.stub! 'authorize' do |types, block|
20
+ types.should.be.kind_of? Hash
21
+ block.should.respond_to? :call
22
+ end
23
+ Medic.authorize(read: :step_count){|success, error|}
24
+ end
25
+ end
26
+
27
+ describe ".authorized?" do
28
+ it "delegates to Medic::Store" do
29
+ @store.stub! 'authorized?' do |sym|
30
+ sym.should.be.kind_of? Symbol
31
+ end
32
+ Medic.authorized? :step_count
33
+ end
34
+
35
+ it "has an .is_authorized? alias" do
36
+ Medic.method(:is_authorized?).should == Medic.method(:authorized?)
37
+ end
38
+
39
+ it "has an .authorized_for? alias" do
40
+ Medic.method(:authorized_for?).should == Medic.method(:authorized?)
41
+ end
42
+
43
+ it "has an .is_authorized_for? alias" do
44
+ Medic.method(:is_authorized_for?).should == Medic.method(:authorized?)
45
+ end
46
+ end
47
+
48
+ describe ".biological_sex" do
49
+ it "delegates to Medic::Store" do
50
+ @store.stub! 'biological_sex' { true }
51
+ Medic.biological_sex.should == true
52
+ end
53
+ end
54
+
55
+ describe ".blood_type" do
56
+ it "delegates to Medic::Store" do
57
+ @store.stub! 'blood_type' { true }
58
+ Medic.blood_type.should == true
59
+ end
60
+ end
61
+
62
+ describe ".date_of_birth" do
63
+ it "delegates to Medic::Store" do
64
+ @store.stub! 'date_of_birth' { true }
65
+ Medic.date_of_birth.should == true
66
+ end
67
+ end
68
+
69
+ describe ".delete" do
70
+ it "delegates to Medic::Store" do
71
+ @store.stub! 'delete' do |hk_object, block|
72
+ hk_object.should == :hk_object
73
+ block.should.respond_to? :call
74
+ end
75
+ Medic.delete(:hk_object){|success, error|}
76
+ end
77
+ end
78
+
79
+ describe ".save" do
80
+ it "delegates to Medic::Store" do
81
+ @store.stub! 'save' do |hk_objects, block|
82
+ hk_objects.should == :hk_objects
83
+ block.should.respond_to? :call
84
+ end
85
+ Medic.save(:hk_objects){|success, error|}
86
+ end
87
+ end
88
+
89
+ describe ".execute" do
90
+ it "delegates to Medic::Store" do
91
+ @store.stub! 'execute' do |query|
92
+ query.should == :query
93
+ end
94
+ Medic.execute(:query)
95
+ end
96
+
97
+ it "has an .execute_query alias" do
98
+ Medic.method(:execute_query).should == Medic.method(:execute)
99
+ end
100
+ end
101
+
102
+ describe ".stop" do
103
+ it "delegates to Medic::Store" do
104
+ @store.stub! 'stop' do |query|
105
+ query.should == :query
106
+ end
107
+ Medic.stop(:query)
108
+ end
109
+
110
+ it "has an .stop_query alias" do
111
+ Medic.method(:stop_query).should == Medic.method(:stop)
112
+ end
113
+ end
114
+
115
+ describe ".enable_background_delivery" do
116
+ it "delegates to Medic::Store" do
117
+ @store.stub! 'enable_background_delivery' do |type, freq, block|
118
+ type.should == :type
119
+ freq.should == :freq
120
+ block.should.respond_to? :call
121
+ end
122
+ Medic.enable_background_delivery(:type, :freq){|success, error|}
123
+ end
124
+
125
+ it "has a .enable_background_delivery_for alias" do
126
+ Medic.method(:enable_background_delivery_for).should == Medic.method(:enable_background_delivery)
127
+ end
128
+ end
129
+
130
+ describe ".disable_background_delivery" do
131
+ it "delegates to Medic::Store" do
132
+ @store.stub! 'disable_background_delivery' do |type, block|
133
+ type.should == :type
134
+ block.should.respond_to? :call
135
+ end
136
+ Medic.disable_background_delivery(:type){|success, error|}
137
+ end
138
+
139
+ it "has a .disable_background_delivery_for alias" do
140
+ Medic.method(:disable_background_delivery_for).should == Medic.method(:disable_background_delivery)
141
+ end
142
+ end
143
+
144
+ describe ".disable_all_background_delivery" do
145
+ it "delegates to Medic::Store" do
146
+ @store.stub! 'disable_all_background_delivery' do |block|
147
+ block.should.respond_to? :call
148
+ end
149
+ Medic.disable_all_background_delivery{|success, error|}
150
+ end
151
+ end
152
+
153
+ end
@@ -0,0 +1,12 @@
1
+ describe "Medic::ObserverQuery" do
2
+
3
+ before do
4
+ @subject = Medic::ObserverQuery.new type: :step_count do |query, completion, error|
5
+ end
6
+ end
7
+
8
+ it "is a subclass of HKObserverQuery" do
9
+ @subject.should.be.kind_of? HKObserverQuery
10
+ end
11
+
12
+ end
@@ -0,0 +1,27 @@
1
+ describe "Medic::Predicate" do
2
+
3
+ before do
4
+ @subject = Object.new
5
+ @subject.extend(Medic::Predicate)
6
+ end
7
+
8
+ describe "#predicate" do
9
+ it "returns an NSPredicate for the given symbols" do
10
+ @subject.predicate(uuid: :something).should.be.kind_of NSPredicate
11
+ @subject.predicate(source: :something).should.be.kind_of NSPredicate
12
+ @subject.predicate(meta_data: :something).should.be.kind_of NSPredicate
13
+ @subject.predicate(no_correlation: true).should.be.kind_of NSPredicate
14
+ @subject.predicate(workout: :something).should.be.kind_of NSPredicate
15
+ end
16
+
17
+ it "passes through the NSPredicate if given a predicate" do
18
+ @subject.predicate(predicate: :whatever).should == :whatever
19
+ end
20
+
21
+ it "returns nil if no arguments match" do
22
+ @subject.predicate({}).should == nil
23
+ @subject.predicate({nonsense: nil}).should == nil
24
+ end
25
+ end
26
+
27
+ end
@@ -0,0 +1,24 @@
1
+ describe "Medic::QueryOptions" do
2
+
3
+ before do
4
+ @subject = Object.new
5
+ @subject.extend(Medic::QueryOptions)
6
+ end
7
+
8
+ describe "#query_options" do
9
+ it "correctly calculates the value for options" do
10
+ @subject.query_options(:none).should == 0
11
+ @subject.query_options([:strict_start_date]).should == 1
12
+ @subject.query_options([:strict_start_date, :strict_end_date]).should == 3
13
+ end
14
+ end
15
+
16
+ describe "#query_option" do
17
+ it "returns the correct type identifier for symbol" do
18
+ @subject.query_option(:none).should == HKQueryOptionNone
19
+ @subject.query_option(:strict_start_date).should == HKQueryOptionStrictStartDate
20
+ @subject.query_option(:strict_end_date).should == HKQueryOptionStrictEndDate
21
+ end
22
+ end
23
+
24
+ end