tanita-api-client 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f0273fdeb978d519cf5c9f4dd0cc5c427fdb9b714c71bcf689e926a91abf35ff
4
- data.tar.gz: c01bbfd1394beb20f0c840a61ca6e3934d94904590f58749f41ef6b64081eece
3
+ metadata.gz: 91859c1415a0fc78e01c01c1e615acdca193ce8ec887abaa19ce5d3e1353285f
4
+ data.tar.gz: 4b875b46afb595f6ccb84fb6776da2f4527ab9b099274131251b0a65c2ceaba9
5
5
  SHA512:
6
- metadata.gz: 80c45f0e5452087291bf3bd563ae5352a3718c8e9416e1e728b06cff99332b601d77690aaa6a20e3d1ece855300b61394821341e1b6ffb2cf799a0b8891ac375
7
- data.tar.gz: 31b49bc20f568776ae04858c87471b6c1cb23b37cabcd772d1ac895553afcbba341cb264d71437f280dede68737e166efaa2fef59c2429eaa210ce7c97840088
6
+ metadata.gz: bcd9de5af29bcf2c760a501dab1f4165c6a9102960d64ca23c10d3fbbbeadccc96ccdafd92da4bf776b2778f4d65a1f5dd9976c952317b835a8bc8ec934986ad
7
+ data.tar.gz: 1193a310b0014f32f16cf6b5819960b6326a8ef486582007d0a4a179c9ce8fc0788dea6d0a2c67dbefd61c600a9ed731621d4044e22b955aaef54512c00240f2
data/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ # 0.3.0
2
+
3
+ changed Result hash to be Object.
4
+
5
+ ```
6
+ # before
7
+ result.items[0][:weight]
8
+ # after
9
+ result.items[0].weight
10
+ ```
11
+
12
+ # 0.2.3
13
+
14
+ remove Gemfile.lock
15
+
1
16
  # 0.2.2
2
17
 
3
18
  * define constants
data/README.md CHANGED
@@ -92,7 +92,7 @@ result = api.status
92
92
  result = api.status(from: Date.current.ago(1.month), to: Date.current)
93
93
 
94
94
  # list the body-weight data
95
- result.items.each{|item| puts "#{Time.at(item[:measured_at]).strftime('%F %R')} => #{item[:weight]}" }
95
+ result.items.each{|item| puts "#{Time.at(item.measured_at).strftime('%F %R')} => #{item.weight}" }
96
96
  2019-10-10 08:09 => 66.7
97
97
  2019-10-11 09:02 => 66.5
98
98
  2019-10-13 08:22 => 66.7
@@ -101,23 +101,27 @@ result.items.each{|item| puts "#{Time.at(item[:measured_at]).strftime('%F %R')}
101
101
 
102
102
  # Result of Innerscan Api
103
103
  result = Tanita::Api::Client::Innerscan.new.status
104
- result.items[0].keys
105
- => [:measured_at, :model, :weight, :body_fat, :muscle_mass, :physique_rating, :visceral_fat_rating, :basal_metabolic_rate, :metabolic_age, :bone_mass]
104
+ => #<Tanita::Api::Client::Result:70199592389780 properties=birth_date,height,sex,items>
105
+ result.items[0]
106
+ => #<Tanita::Api::Client::InnerscanItem:70199597695880 properties=measured_at,registered_at,model,weight,body_fat,muscle_mass,physique_rating,visceral_fat_rating,basal_metabolic_rate,metabolic_age,bone_mass>
107
+ result.items[0].weight
108
+ => 66.7
106
109
 
107
110
  # Result of Sphygmomanometer Api
108
111
  result = Tanita::Api::Client::Sphygmomanometer.new.status
109
- result.items[0].keys
110
- => [:measured_at, :model, :maximal_pressure, :minimal_pressure, :pulse]
112
+ result.items[0]
113
+ => #<Tanita::Api::Client::SphygmomanometerItem:70199592475760 properties=measured_at,registered_at,model,maximal_pressure,minimal_pressure,pulse>
111
114
 
112
115
  # Result of Pedometer Api
113
116
  result = Tanita::Api::Client::Pedometer.new.status
114
- result.items[0].keys
115
- => [:measured_at, :model, :steps, :calories]
117
+ result.items[0]
118
+ => #<Tanita::Api::Client::PedometerItem:70199605021160 properties=measured_at,registered_at,model,steps,exercise,calories>
119
+
116
120
 
117
121
  # Result of Smug Api
118
122
  result = Tanita::Api::Client::Smug.new.status
119
- result.items[0].keys
120
- => [:measured_at, :model, :urinary_sugar]
123
+ result.items[0]
124
+ => #<Tanita::Api::Client::SmugItem:70199600803680 properties=measured_at,registered_at,model,urinary_sugar>
121
125
 
122
126
  # common attributes of Result class
123
127
  result.birth_date # [Date]
@@ -1,11 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'time'
4
- require 'tanita/api/client/helpers'
5
-
6
3
  module Tanita
7
4
  module Api
8
5
  module Client
6
+
9
7
  module Scope
10
8
  INNERSCAN = 'innerscan'
11
9
  SPHYGMOMANOMETER = 'sphygmomanometer'
@@ -19,122 +17,6 @@ module Tanita
19
17
  class Error < StandardError
20
18
  end
21
19
 
22
- DATE_TYPE_REGISTERD_AT = 0
23
- DATE_TYPE_MEASURED_AT = 1
24
-
25
- class BaseApiClient
26
- include HttpHelper
27
-
28
- def initialize(access_token: nil, date_type: DATE_TYPE_MEASURED_AT)
29
- config = Tanita::Api::Client.configuration
30
- @access_token = access_token || config.access_token
31
- raise Error.new("param:'access_token' is required.'") if @access_token.nil?
32
-
33
- @date_type = date_type
34
- raise Error.new("param:'date_type' is invalid.'") unless [DATE_TYPE_REGISTERD_AT, DATE_TYPE_MEASURED_AT].include? date_type
35
- end
36
-
37
- def status(
38
- from: nil,
39
- to: nil
40
- )
41
- tags = measurement_tags.values.map { |i| i[:code] }.join(',')
42
- params = {
43
- :access_token => @access_token,
44
- :date => @date_type,
45
- :tag => tags
46
- }
47
- params[:from] = time_format(from) unless from.nil?
48
- params[:to] = time_format(to) unless to.nil?
49
- res = request(endpoint, params)
50
- Result.new(:client => self, :response => res)
51
- end
52
-
53
- def endpoint
54
- raise NotImplementedError
55
- end
56
-
57
- def measurement_tags
58
- raise NotImplementedError
59
- end
60
-
61
- def find_measurement_tag(code:)
62
- return @inverted_measurement[code] unless @inverted_measurement.nil?
63
-
64
- @inverted_measurement = {}
65
- measurement_tags.each do |m_name, m_info|
66
- @inverted_measurement[m_info[:code]] = {:name => m_name, :type => m_info[:type]}
67
- end
68
- @inverted_measurement[code]
69
- end
70
-
71
- def date_key
72
- case @date_type
73
- when DATE_TYPE_REGISTERD_AT
74
- :registered_at
75
- when DATE_TYPE_MEASURED_AT
76
- :measured_at
77
- end
78
- end
79
-
80
- private
81
-
82
- def time_format(time)
83
- time.strftime('%Y%m%d%H%M%S')
84
- end
85
- end
86
-
87
- class Result
88
- include HttpHelper
89
-
90
- # [Date]
91
- attr_reader :birth_date
92
-
93
- # [Float] (centimeter)
94
- attr_reader :height
95
-
96
- # [String] 'male' or 'female'
97
- attr_reader :sex
98
-
99
- # [Array<Hash>]
100
- attr_reader :items
101
-
102
- def initialize(client:, response:)
103
- @client = client
104
- result = parse_json(response.body)
105
- @birth_date = Date.parse(result[:birth_date])
106
- @height = result[:height].to_f
107
- @sex = result[:sex]
108
- @items = build_items(result[:data])
109
- end
110
-
111
- private
112
-
113
- def build_items(raw_items)
114
- item_dic = {}
115
- raw_items.each do |item|
116
- date = item[:date]
117
- model = item[:model]
118
- key = "#{date}_#{model}"
119
- measurement = @client.find_measurement_tag(:code => item[:tag])
120
- value = cast(:value => item[:keydata], :type => measurement[:type])
121
- item_dic[key] ||= {}
122
- item_dic[key][@client.date_key] = Time.parse("#{date} +09:00").to_i unless item_dic[key].key? :date
123
- item_dic[key][:model] = model unless item_dic[key].key? :model
124
- item_dic[key][measurement[:name]] = value
125
- end
126
- # sort by date in ascending order
127
- item_dic.values.sort_by { |dic| dic[@client.date_key] }
128
- end
129
-
130
- def cast(value:, type:)
131
- return value if value.nil?
132
- return value.to_i if type == Integer
133
- return value.to_f if type == Float
134
-
135
- value
136
- end
137
- end
138
20
  end
139
21
  end
140
22
  end
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'time'
4
+ require 'tanita/api/client/helpers'
5
+
6
+ module Tanita
7
+ module Api
8
+ module Client
9
+ DATE_TYPE_REGISTERD_AT = 0
10
+ DATE_TYPE_MEASURED_AT = 1
11
+
12
+ class BaseApiClient
13
+ include HttpHelper
14
+
15
+ def self.endpoint
16
+ raise NotImplementedError
17
+ end
18
+
19
+ def self.properties
20
+ raise NotImplementedError
21
+ end
22
+
23
+ def initialize(access_token: nil, date_type: DATE_TYPE_MEASURED_AT)
24
+ config = Tanita::Api::Client.configuration
25
+ @access_token = access_token || config.access_token
26
+ raise Error.new("param:'access_token' is required.'") if @access_token.nil?
27
+
28
+ @date_type = date_type
29
+ raise Error.new("param:'date_type' is invalid.'") unless [DATE_TYPE_REGISTERD_AT, DATE_TYPE_MEASURED_AT].include? date_type
30
+
31
+ ClassBuilder.load
32
+ end
33
+
34
+ def status(
35
+ from: nil,
36
+ to: nil
37
+ )
38
+ tags = self.class.properties.values.map { |i| i[:code] }.join(',')
39
+ params = {
40
+ :access_token => @access_token,
41
+ :date => @date_type,
42
+ :tag => tags
43
+ }
44
+ params[:from] = time_format(from) unless from.nil?
45
+ params[:to] = time_format(to) unless to.nil?
46
+ res = request(self.class.endpoint, params)
47
+ build_result(res)
48
+ end
49
+
50
+ def inspect
51
+ "\#<#{self.class}:#{object_id}>"
52
+ end
53
+
54
+ private
55
+
56
+ def build_result(res)
57
+ result = parse_json(res.body)
58
+ Result.new(
59
+ :birth_date => Date.parse(result[:birth_date]),
60
+ :height => result[:height].to_f,
61
+ :sex => result[:sex],
62
+ :items => build_result_items(:raw_items => result[:data])
63
+ )
64
+ end
65
+
66
+ def build_result_items(raw_items:)
67
+ item_dic = {}
68
+ raw_items.each do |item|
69
+ date = item[:date]
70
+ model = item[:model]
71
+ key = "#{date}_#{model}"
72
+ property = find_property_by_code(:code => item[:tag])
73
+ value = cast(:value => item[:keydata], :type => property[:type])
74
+ item_dic[key] ||= {}
75
+ item_dic[key][date_key] = Time.parse("#{date} +09:00").to_i unless item_dic[key].key? :date
76
+ item_dic[key][:model] = model unless item_dic[key].key? :model
77
+ item_dic[key][property[:name]] = value
78
+ end
79
+ items = item_dic.values.sort_by { |dic| dic[date_key] } # sort by date in ascending order
80
+ items.map { |_item_dic| eval "#{self.class}Item.new _item_dic" }
81
+ end
82
+
83
+ def cast(value:, type:)
84
+ return value if value.nil?
85
+ return value.to_i if type == Integer
86
+ return value.to_f if type == Float
87
+
88
+ value
89
+ end
90
+
91
+ def find_property_by_code(code:)
92
+ return @property_code_dic[code] unless @property_code_dic.nil?
93
+
94
+ @property_code_dic = {}
95
+ self.class.properties.each do |m_name, m_info|
96
+ @property_code_dic[m_info[:code]] = {:name => m_name, :type => m_info[:type]}
97
+ end
98
+ @property_code_dic[code]
99
+ end
100
+
101
+ def date_key
102
+ case @date_type
103
+ when DATE_TYPE_REGISTERD_AT
104
+ :registered_at
105
+ when DATE_TYPE_MEASURED_AT
106
+ :measured_at
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tanita
4
+ module Api
5
+ module Client
6
+ class BaseEntity
7
+ def initialize(property_values = {})
8
+ @properties = []
9
+ @cached_property_values = {}
10
+ @cached_property_values.merge!(property_values)
11
+ end
12
+
13
+ def to_h
14
+ ret = {}
15
+ self.class.properties.each do |property|
16
+ ret[property.to_sym] = eval property.to_s
17
+ end
18
+ ret
19
+ end
20
+
21
+ def inspect
22
+ "\#<#{self.class}:#{object_id} properties=#{self.class.properties.join(',')}>"
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tanita
4
+ module Api
5
+ module Client
6
+ class ClassBuilder
7
+ def self.load
8
+ return if loaded
9
+
10
+ create_class('Result', %i[birth_date height sex items])
11
+ base_properties = %i[measured_at registered_at model]
12
+ [Innerscan, Sphygmomanometer, Pedometer, Smug].each do |klass|
13
+ klass_name = klass.to_s.split('::')[-1] + 'Item'
14
+ properties = base_properties + klass.properties.keys
15
+ create_class(klass_name, properties)
16
+ end
17
+ @loaded = true
18
+ end
19
+
20
+ def self.loaded
21
+ @loaded || false
22
+ end
23
+ private_class_method :loaded
24
+
25
+ def self.create_class(class_name, property_names = [])
26
+ super_klass = Class.new(BaseEntity)
27
+ klass = Tanita::Api::Client.const_set(class_name, super_klass)
28
+ define_properties_reader(klass)
29
+ property_names.each do |property_name|
30
+ klass.properties << property_name if klass.respond_to?(:properties)
31
+ define_getter_and_setter(klass, property_name)
32
+ end
33
+ klass.properties.freeze if klass.respond_to?(:properties)
34
+ end
35
+ private_class_method :create_class
36
+
37
+ def self.define_properties_reader(klass)
38
+ klass.class_eval do
39
+ def self.properties
40
+ @properties = [] if @properties.nil?
41
+ @properties
42
+ end
43
+ end
44
+ end
45
+ private_class_method :define_properties_reader
46
+
47
+ def self.define_getter_and_setter(klass, property_name)
48
+ klass.class_eval do
49
+ define_method(property_name.to_sym) do
50
+ @cached_property_values[property_name.to_sym]
51
+ end
52
+ define_method("#{property_name}=".to_sym) do |value|
53
+ @cached_property_values[property_name.to_sym] = value
54
+ end
55
+ end
56
+ end
57
+ private_class_method :define_getter_and_setter
58
+ end
59
+ end
60
+ end
61
+ end
@@ -11,7 +11,7 @@ module Tanita
11
11
  AUTH_URL_PATH = '/oauth/auth'
12
12
  AUTH_URL = "#{BASE_URL}#{AUTH_URL_PATH}"
13
13
 
14
- TOKEN_URL_PATH = '/oauth/token'
14
+ TOKEN_URL_PATH = '/oauth/token'
15
15
  TOKEN_URL = "#{BASE_URL}#{TOKEN_URL_PATH}"
16
16
 
17
17
  DEFAULT_REDIRECT_URI = "#{BASE_URL}/success.html"
@@ -37,6 +37,10 @@ module Tanita
37
37
  rescue JSON::ParserError => e
38
38
  raise Error.new("JSON::ParseError: '#{e}'\nstr:#{str}")
39
39
  end
40
+
41
+ def time_format(time)
42
+ time.strftime('%Y%m%d%H%M%S')
43
+ end
40
44
  end
41
45
  end
42
46
  end
@@ -3,7 +3,7 @@
3
3
  module Tanita
4
4
  module Api
5
5
  module Client
6
- VERSION = '0.2.3'
6
+ VERSION = '0.3.0'
7
7
  end
8
8
  end
9
9
  end
@@ -1,9 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'tanita/api/client/base'
4
- require 'tanita/api/client/helpers'
5
- require 'tanita/api/client/configuration'
6
- require 'tanita/api/client/version'
3
+ Dir[
4
+ File.join(
5
+ File.dirname(__FILE__),
6
+ 'client',
7
+ '*'
8
+ )
9
+ ].sort.each { |f| require f }
7
10
 
8
11
  module Tanita
9
12
  module Api
@@ -67,11 +70,11 @@ module Tanita
67
70
  end
68
71
 
69
72
  class Innerscan < BaseApiClient
70
- def endpoint
73
+ def self.endpoint
71
74
  '/status/innerscan.json'
72
75
  end
73
76
 
74
- def measurement_tags
77
+ def self.properties
75
78
  {
76
79
  :weight => {:code => '6021', :type => Float},
77
80
  :body_fat => {:code => '6022', :type => Float},
@@ -86,11 +89,11 @@ module Tanita
86
89
  end
87
90
 
88
91
  class Sphygmomanometer < BaseApiClient
89
- def endpoint
92
+ def self.endpoint
90
93
  '/status/sphygmomanometer.json'
91
94
  end
92
95
 
93
- def measurement_tags
96
+ def self.properties
94
97
  {
95
98
  :maximal_pressure => {:code => '622E', :type => Integer},
96
99
  :minimal_pressure => {:code => '622F', :type => Integer},
@@ -100,11 +103,11 @@ module Tanita
100
103
  end
101
104
 
102
105
  class Pedometer < BaseApiClient
103
- def endpoint
106
+ def self.endpoint
104
107
  '/status/pedometer.json'
105
108
  end
106
109
 
107
- def measurement_tags
110
+ def self.properties
108
111
  {
109
112
  :steps => {:code => '6331', :type => Integer},
110
113
  :exercise => {:code => '6335', :type => Integer},
@@ -114,11 +117,11 @@ module Tanita
114
117
  end
115
118
 
116
119
  class Smug < BaseApiClient
117
- def endpoint
120
+ def self.endpoint
118
121
  '/status/smug.json'
119
122
  end
120
123
 
121
- def measurement_tags
124
+ def self.properties
122
125
  {
123
126
  :urinary_sugar => {:code => '6240', :type => Integer}
124
127
  }
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.metadata['homepage_uri'] = spec.homepage
20
20
  spec.metadata['source_code_uri'] = 'https://github.com/koshilife/tanita-api-ruby-client'
21
21
  spec.metadata['changelog_uri'] = "#{spec.metadata['source_code_uri']}/blob/master/CHANGELOG.md"
22
+ spec.metadata['documentation_uri'] = 'https://www.rubydoc.info/gems/tanita-api-client/'
22
23
 
23
24
  # Specify which files should be added to the gem when it is released.
24
25
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tanita-api-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kenji Koshikawa
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-01-12 00:00:00.000000000 Z
11
+ date: 2020-02-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -87,6 +87,9 @@ files:
87
87
  - bin/setup
88
88
  - lib/tanita/api/client.rb
89
89
  - lib/tanita/api/client/base.rb
90
+ - lib/tanita/api/client/base_api_client.rb
91
+ - lib/tanita/api/client/base_entity.rb
92
+ - lib/tanita/api/client/class_builder.rb
90
93
  - lib/tanita/api/client/configuration.rb
91
94
  - lib/tanita/api/client/helpers.rb
92
95
  - lib/tanita/api/client/version.rb
@@ -98,6 +101,7 @@ metadata:
98
101
  homepage_uri: https://github.com/koshilife/tanita-api-ruby-client
99
102
  source_code_uri: https://github.com/koshilife/tanita-api-ruby-client
100
103
  changelog_uri: https://github.com/koshilife/tanita-api-ruby-client/blob/master/CHANGELOG.md
104
+ documentation_uri: https://www.rubydoc.info/gems/tanita-api-client/
101
105
  post_install_message:
102
106
  rdoc_options: []
103
107
  require_paths: