medic 0.0.1 → 0.0.2

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.
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