tanita-api-client 0.2.3 → 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.
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: