pillboxr 0.0.3 → 0.6.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.
@@ -0,0 +1,267 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require_relative 'constants'
3
+ require 'erb'
4
+
5
+ module Pillboxr
6
+ module Attributes
7
+ def attributes
8
+ { :color => :splcolor,
9
+ :shape => :splshape,
10
+ :product_code => :product_code,
11
+ :schedule => :dea_schedule_code,
12
+ :ingredients => :ingredients,
13
+ :imprint => :splimprint,
14
+ :id => :spl_id,
15
+ :ndc9 => :ndc9,
16
+ :size => :splsize,
17
+ :score => :splscore,
18
+ :rxcui => :rxcui,
19
+ :rxtty => :rxtty,
20
+ :rxstring => :rxstring,
21
+ :image => :has_image,
22
+ :image_id => :image_id,
23
+ :setid => :setid,
24
+ :author => :author,
25
+ :inactive_ingredients => :spl_inactive_ing,
26
+ :lower_limit => :lower_limit }
27
+ end
28
+
29
+ def api_attributes
30
+ attributes.invert
31
+ end
32
+
33
+ # Creates a series of class methods on Pillboxr::Attributes module
34
+ # that allow easy access to all the possible colors, shapes, dea codes, etc..
35
+ # Example:
36
+ #
37
+ # Pillboxr::Attributes.colors
38
+ # => [:bullet,:capsule,:clover,:diamond,:double_circle,:freeform,:gear,:heptagon,
39
+ # :hexagon,:octagon,:oval,:pentagon,:rectangle,:round,:semi_circle,:square,
40
+ # :tear,:trapezoid,:triangle]
41
+ #
42
+ # Available methods are colors, color_codes, shapes, shape_codes, dea_codes,
43
+ # and schedule_codes.
44
+ self.constants.each do |const|
45
+ self.module_eval("def self.#{const.downcase}; #{const}.keys; end")
46
+ end
47
+
48
+ class Color
49
+ attr_accessor :color
50
+
51
+ def initialize(color_arg)
52
+ # puts "argument to method = #{color_arg}"
53
+ @color = case color_arg
54
+ when NilClass; raise ColorError
55
+ when Array; color_arg.size > 1 ? Pill::Attributes::Colors.new(color_arg) : COLORS[color_arg[0]]
56
+ when Symbol; COLORS.fetch(color_arg, color_arg)
57
+ when String; COLORS.fetch(color_arg.to_sym, color_arg.to_sym)
58
+ else raise "invalid arguments."
59
+ end
60
+ return self
61
+ end
62
+
63
+ def to_param
64
+ "&color=" + String(@color)
65
+ end
66
+ end
67
+
68
+ class Shape
69
+ attr_accessor :shape
70
+
71
+ def initialize(shape_arg)
72
+ # puts "argument to method = #{shape_arg}"
73
+ @shape = case shape_arg
74
+ when NilClass; raise ShapeError
75
+ when Array; shape_arg.size > 1 ? Pill::Attributes::Shapes.new(color_arg) : SHAPES[shape_arg[0]]
76
+ when /^([Cc]{1}\d{5})+/; shape_arg # valid hex
77
+ when Symbol; SHAPES.fetch(shape_arg, shape_arg)
78
+ when String; SHAPES.fetch(shape_arg.to_sym, shape_arg.to_sym)
79
+ else raise "invalid arguments."
80
+ end
81
+ return self
82
+ end
83
+
84
+ def to_param
85
+ "&shape=" + String(@shape)
86
+ end
87
+ end
88
+
89
+ class Productcode
90
+ attr_accessor :product_code
91
+
92
+ def initialize(product_code_arg)
93
+ # puts "argument to method = #{product_code_arg}"
94
+ @code = case product_code_arg
95
+ when NilClass; raise ProductcodeError
96
+ when Array; raise "product_code must be unique."
97
+ when /^\d+-\d+/; product_code_arg # valid hex
98
+ when Symbol; raise "product_code cannot be a symbol."
99
+ else raise "invalid arguments."
100
+ end
101
+ return self
102
+ end
103
+
104
+ def to_param
105
+ "&prodcode=" + String(@code)
106
+ end
107
+ end
108
+
109
+ class Schedule
110
+ attr_accessor :schedule
111
+
112
+ def initialize(schedule_code)
113
+ # puts "argument to method = #{schedule_code}"
114
+ @schedule = case schedule_code
115
+ when NilClass; raise ScheduleError
116
+ when Array; schedule_code.size > 1 ? Pill::Attributes::Schedules.new(color_arg) : DEA_CODES.fetch(schedule_code[0])
117
+ when /^([Cc]{1}\d{5})+/; schedule_code # valid hex
118
+ when /\AI{1,3}\z|\AIV\z|\AV\z/; DEA_CODES.fetch(schedule_code, schedule_code)
119
+ else raise "invalid arguments."
120
+ end
121
+ return self
122
+ end
123
+
124
+ def to_param
125
+ "&dea=" + String(@schedule)
126
+ end
127
+ end
128
+
129
+ class Ingredients
130
+ attr_accessor :ingredients
131
+
132
+ def initialize(ingredient_arg)
133
+ # puts "argument to method = #{ingredient_arg}"
134
+ @ingredients = case ingredient_arg
135
+ when NilClass; raise IngredientError
136
+ when Array; raise ArgumentError, "can only search for one active ingredient at this time."
137
+ when String; ingredient_arg
138
+ when Symbol; String(ingredient_arg)
139
+ else raise ArgumentError, "invalid arguments."
140
+ end
141
+ return self
142
+ end
143
+
144
+ def to_param
145
+ "&ingredient=" + String(@ingredients)
146
+ end
147
+ end
148
+
149
+ # class Imprint # Broken currently
150
+ # attr_accessor :imprint
151
+
152
+ # def initialize(imprint_arg)
153
+ # # puts "argument to method = #{ingredient_arg}"
154
+ # @imprint = case imprint_arg
155
+ # when NilClass; raise ImprintError
156
+ # when Array; raise ArgumentError, "can only search for one imprint string at this time."
157
+ # when String; imprint_arg
158
+ # when Symbol; imprint_arg
159
+ # when Integer; imprint_arg
160
+ # else raise ArgumentError, "invalid arguments."
161
+ # end
162
+ # return self
163
+ # end
164
+
165
+ # def to_param
166
+ # "&imprint=" + String(@imprint)
167
+ # end
168
+ # end
169
+
170
+ class Size
171
+ attr_accessor :size
172
+
173
+ def initialize(size_arg)
174
+ @size = case size_arg
175
+ when NilClass; raise SizeError
176
+ when Integer; size_arg
177
+ when Float; Integer(size_arg)
178
+ when String; Integer(size_arg)
179
+ when Symbol; Integer(size_arg)
180
+ else raise ArgumentError, "invalid arguments."
181
+ end
182
+ return self
183
+ end
184
+
185
+ def to_param
186
+ "&size=" + String(@size)
187
+ end
188
+
189
+ end
190
+
191
+
192
+ class Score
193
+ attr_accessor :score
194
+
195
+ def initialize(score_arg)
196
+ # puts "argument to method = #{score_arg}"
197
+ @score = case score_arg
198
+ when NilClass; raise ScoreError
199
+ when TrueClass; 2
200
+ when FalseClass; 1
201
+ when Integer; score_arg
202
+ when Array; raise ArgumentError, "Must be true or false."
203
+ else raise ArgumentError, "invalid arguments."
204
+ end
205
+ return self
206
+ end
207
+
208
+ def to_param
209
+ "&score=" + String(@score)
210
+ end
211
+ end
212
+
213
+ class Image
214
+ attr_accessor :image
215
+
216
+ def initialize(image_arg)
217
+ # puts "argument to method = #{image_arg}"
218
+ @image = case image_arg
219
+ when NilClass; raise ImageError
220
+ when TrueClass; 1
221
+ when FalseClass; 0
222
+ when Array; raise ArgumentError, "Must be true or false."
223
+ else raise ArgumentError, "Invalid argument. Must be true or false."
224
+ end
225
+ return self
226
+ end
227
+
228
+ def to_param
229
+ "&has_image=" + String(@image)
230
+ end
231
+ end
232
+
233
+ class Author
234
+ attr_accessor :author
235
+
236
+ def initialize(author_arg)
237
+ @author = case author_arg
238
+ when String; author_arg
239
+ when Array; raise ArgumentError, "Author can only take a single string."
240
+ else raise ArgumentError, "invalid arguments."
241
+ end
242
+ return self
243
+ end
244
+
245
+ def to_param
246
+ "&author=" + ERB::Util.url_encode(@author)
247
+ end
248
+ end
249
+
250
+ class Lowerlimit
251
+ attr_accessor :lower_limit
252
+
253
+ def initialize(limit = DEFAULT_LOWER_LIMIT)
254
+ @lower_limit = case limit
255
+ when NilClass; raise LowerLimitError
256
+ when Integer; limit
257
+ else raise ArgumentError, "Lower limit must be an integer."
258
+ end
259
+ return self
260
+ end
261
+
262
+ def to_param
263
+ "&lower_limit=" + String(@lower_limit)
264
+ end
265
+ end
266
+ end
267
+ end
@@ -0,0 +1,61 @@
1
+ # -*- encoding: utf-8 -*-
2
+ module Pillboxr
3
+ RECORDS_PER_PAGE = 201
4
+ DEFAULT_LOWER_LIMIT = 1
5
+ BASE_URI = 'pillbox.nlm.nih.gov'
6
+ NO_RECORDS_ERROR_MESSAGE = "The document \"No records found\" does not have a valid root"
7
+ API_KEY_ERROR_MESSAGE = "The document \"Key does not match, you may not access this service\" does not have a valid root"
8
+
9
+ module Attributes
10
+ SHAPES = {
11
+ :bullet=> :C48335,
12
+ :capsule=> :C48336,
13
+ :clover=> :C48337,
14
+ :diamond=> :C48338,
15
+ :double_circle=> :C48339,
16
+ :freeform=> :C48340,
17
+ :gear=> :C48341,
18
+ :heptagon=> :C48342,
19
+ :hexagon=> :C48343,
20
+ :octagon=> :C48344,
21
+ :oval=> :C48345,
22
+ :pentagon=> :C48346,
23
+ :rectangle=> :C48347,
24
+ :round=> :C48348,
25
+ :semi_circle=> :C48349,
26
+ :square=> :C48350,
27
+ :tear=> :C48351,
28
+ :trapezoid=> :C48352,
29
+ :triangle=> :C48353
30
+ }
31
+
32
+ SHAPE_CODES = SHAPES.invert
33
+
34
+ COLORS = {
35
+ :black => :C48323,
36
+ :blue => :C48333,
37
+ :brown => :C48332,
38
+ :gray => :C48324,
39
+ :green => :C48329,
40
+ :orange => :C48331,
41
+ :pink => :C48328,
42
+ :purple => :C48327,
43
+ :red => :C48326,
44
+ :turquoise => :C48334,
45
+ :white => :C48325,
46
+ :yellow => :C48330
47
+ }
48
+
49
+ COLOR_CODES = COLORS.invert
50
+
51
+ DEA_CODES = {
52
+ :I => :C48672,
53
+ :II => :C48675,
54
+ :III => :C48676,
55
+ :IV => :C48677,
56
+ :V => :C48679
57
+ }
58
+
59
+ SCHEDULE_CODES = DEA_CODES.invert
60
+ end
61
+ end
@@ -0,0 +1,11 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require_relative 'attributes'
3
+
4
+ module Pillboxr
5
+ module Extensions
6
+ def to_constant
7
+ raise TypeError unless self.kind_of?(String)
8
+ Array(self).inject(Pillboxr::Attributes) { |s,e| s.const_get(e.to_sym) }
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,120 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'forwardable'
3
+
4
+ module Pillboxr
5
+ class Pages
6
+ extend Forwardable
7
+ def_delegators :@data, :<<, :size, :each, :include?, :empty?, :count,
8
+ :join, :first, :last, :[], :[]=, :all?, :any?, :inject
9
+
10
+ def initialize(size = 0, obj = nil, &block)
11
+ @data = Array.new(size, &block)
12
+ end
13
+
14
+ def inspect
15
+ string = "#<Pillboxr::Result::Pages:#{object_id} ["
16
+ @data.each do |page|
17
+ string << String(page)
18
+ string << ", "
19
+ end
20
+ string << "], size = #{self.size}>"
21
+ return string
22
+ end
23
+
24
+ alias_method :to_s, :inspect
25
+
26
+ def start
27
+ self.current = @data[0]
28
+ end
29
+
30
+ def start?
31
+ self.current == @data[0]
32
+ end
33
+
34
+ def end
35
+ self.current = @data[-1]
36
+ end
37
+
38
+ def end?
39
+ self.current == @data[-1]
40
+ end
41
+
42
+ def advance(slots = 1)
43
+ slots.times { self.current = self.next }
44
+ return self.current
45
+ end
46
+
47
+ def retreat(slots = 1)
48
+ slots.times { self.current = self.previous }
49
+ return self.current
50
+ end
51
+
52
+ def next(slots = 1)
53
+ if slots == 1
54
+ self.end? ? @data[0] : @data[current_index + 1]
55
+ else
56
+ if slots <= (@data.size - (current_index + 1))
57
+ @data[(current_index + 1), slots]
58
+ else
59
+ temporary_array = @data[(current_index + 1)..-1].push(@data[0..(current_index - 1)]).flatten
60
+ return temporary_array[0..(slots - 1)]
61
+ end
62
+ end
63
+ end
64
+
65
+ def previous(slots = 1)
66
+ if slots == 1
67
+ self.start? ? @data[-1] : @data[current_index - 1]
68
+ else
69
+ if slots <= current_index
70
+ @data[(current_index - slots)..(current_index - 1)]
71
+ else
72
+ (@data[0..(current_index - 1)].reverse.push(@data[(current_index - slots)..-1].reverse)).flatten
73
+ end
74
+ end
75
+ end
76
+
77
+ def current
78
+ @data[current_index]
79
+ end
80
+
81
+ def current=(page)
82
+ unless page.current?
83
+ self.current.send(:current=, false)
84
+ page.send(:current=, true)
85
+ end
86
+ return page
87
+ end
88
+
89
+ def current_index
90
+ @data.index { |page| page.current }
91
+ end
92
+
93
+ private :current_index
94
+ end
95
+
96
+ Page = Struct.new(:current, :retrieved, :number, :pills, :params) do
97
+ def inspect
98
+ "<Page: current: #{current}, retrieved: #{retrieved}, number: #{number}, params: #{params}, #{pills.size} pills>"
99
+ end
100
+
101
+ def current?
102
+ self.current == true
103
+ end
104
+
105
+ def retrieved?
106
+ self.retrieved == true
107
+ end
108
+
109
+ def get
110
+ unless self.retrieved
111
+ self.pills = Result.subsequent(Request.new(self.params).perform)
112
+ puts "#{self.pills.size} records retrieved."
113
+ self.retrieved = true
114
+ end
115
+ end
116
+
117
+ alias_method :to_s, :inspect
118
+ private :current=, :retrieved=, :number=, :pills=, :params=
119
+ end
120
+ end