quickbooks 0.4.0 → 0.9.9

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 (293) hide show
  1. data.tar.gz.sig +0 -0
  2. data/History.txt +23 -0
  3. data/License.txt +54 -0
  4. data/Manifest.txt +73 -0
  5. data/README.txt +79 -0
  6. data/Rakefile +17 -78
  7. data/lib/quickbooks.rb +153 -7
  8. data/lib/quickbooks/adaptability.rb +67 -0
  9. data/lib/quickbooks/adapters/http_adapter.rb +94 -0
  10. data/lib/quickbooks/adapters/https_adapter.rb +57 -0
  11. data/lib/quickbooks/adapters/ole_adapter.rb +141 -110
  12. data/lib/quickbooks/adapters/spew_adapter.rb +39 -0
  13. data/lib/quickbooks/adapters/tcp_adapter.rb +71 -0
  14. data/lib/quickbooks/adapters/test_adapter.rb +62 -0
  15. data/lib/quickbooks/element.rb +385 -0
  16. data/lib/quickbooks/element_collection.rb +105 -0
  17. data/lib/quickbooks/extlib.rb +8 -0
  18. data/lib/quickbooks/extlib/assertions.rb +8 -0
  19. data/lib/quickbooks/extlib/class.rb +98 -0
  20. data/lib/quickbooks/extlib/days_and_times.rb +10 -0
  21. data/lib/quickbooks/extlib/days_and_times/duration.rb +362 -0
  22. data/lib/quickbooks/extlib/days_and_times/numeric.rb +48 -0
  23. data/lib/quickbooks/extlib/days_and_times/object.rb +19 -0
  24. data/lib/quickbooks/extlib/days_and_times/time.rb +137 -0
  25. data/lib/quickbooks/extlib/hash.rb +327 -0
  26. data/lib/quickbooks/extlib/hook.rb +366 -0
  27. data/lib/quickbooks/extlib/inflection.rb +436 -0
  28. data/lib/quickbooks/extlib/logger.rb +202 -0
  29. data/lib/quickbooks/extlib/object.rb +162 -0
  30. data/lib/quickbooks/extlib/pathname.rb +15 -0
  31. data/lib/quickbooks/extlib/rubygems.rb +38 -0
  32. data/lib/quickbooks/extlib/string.rb +32 -0
  33. data/lib/quickbooks/extlib/time.rb +41 -0
  34. data/lib/quickbooks/model.rb +503 -121
  35. data/lib/quickbooks/option.rb +95 -0
  36. data/lib/quickbooks/property.rb +69 -0
  37. data/lib/quickbooks/ruby_ext.rb +251 -0
  38. data/lib/quickbooks/type.rb +75 -0
  39. data/lib/quickbooks/types.rb +58 -0
  40. data/lib/quickbooks/version.rb +10 -0
  41. data/lib/quickbooks/xsd.rb +243 -0
  42. data/lib/quickbooks/xsd/attribute.rb +57 -0
  43. data/lib/quickbooks/xsd/choice.rb +94 -0
  44. data/lib/quickbooks/xsd/complex_type.rb +77 -0
  45. data/lib/quickbooks/xsd/element.rb +214 -0
  46. data/lib/quickbooks/xsd/group.rb +94 -0
  47. data/lib/quickbooks/xsd/restriction.rb +51 -0
  48. data/lib/quickbooks/xsd/sequence.rb +85 -0
  49. data/lib/quickbooks/xsd/simple_type.rb +87 -0
  50. data/lib/quickbooks/xsd/union.rb +70 -0
  51. data/lib/quickbooks/xsd/validation.rb +89 -0
  52. data/lib/quickbooks/xsd/xml_parse.rb +80 -0
  53. data/quickbooks.gemspec +36 -0
  54. data/source/qbxml21_demo.xsd +2223 -0
  55. data/source/qbxmlops_demo.xsd +483 -0
  56. data/source/qbxmltypes.xsd +160 -0
  57. data/spec/association_spec.rb +5 -0
  58. data/spec/element_collection_spec.rb +8 -0
  59. data/spec/find_spec.rb +30 -0
  60. data/spec/lib/quickbooks/element_spec.rb +83 -0
  61. data/spec/lib/quickbooks/elements/sales_order_add_spec.rb +14 -0
  62. data/spec/lib/quickbooks/elements/vendor_add_spec.rb +78 -0
  63. data/spec/lib/quickbooks/model_spec.rb +89 -0
  64. data/spec/lib/quickbooks/models/customer_spec.rb +52 -0
  65. data/spec/lib/quickbooks/models/invoice_spec.rb +12 -0
  66. data/spec/lib/quickbooks/models/sales_order_line_spec.rb +0 -0
  67. data/spec/lib/quickbooks/models/sales_order_spec.rb +145 -0
  68. data/spec/lib/quickbooks/xsd/choice_spec.rb +18 -0
  69. data/spec/pending_spec.rb +11 -0
  70. data/spec/quickbooks_spec.rb +38 -0
  71. data/spec/repeatable_spec.rb +20 -0
  72. data/spec/requires_spec.rb +10 -0
  73. data/spec/spec_helper.rb +5 -0
  74. data/spec/validation_spec.rb +24 -0
  75. metadata +133 -285
  76. metadata.gz.sig +0 -0
  77. data/LICENSE +0 -16
  78. data/README +0 -49
  79. data/doc/classes/Array.html +0 -368
  80. data/doc/classes/Array.src/M000026.html +0 -18
  81. data/doc/classes/Array.src/M000027.html +0 -21
  82. data/doc/classes/Array.src/M000028.html +0 -18
  83. data/doc/classes/Array.src/M000029.html +0 -19
  84. data/doc/classes/Array.src/M000030.html +0 -18
  85. data/doc/classes/Array.src/M000031.html +0 -23
  86. data/doc/classes/Array.src/M000032.html +0 -18
  87. data/doc/classes/Array.src/M000033.html +0 -18
  88. data/doc/classes/Array.src/M000034.html +0 -18
  89. data/doc/classes/Array.src/M000035.html +0 -19
  90. data/doc/classes/Array.src/M000036.html +0 -18
  91. data/doc/classes/Array.src/M000037.html +0 -23
  92. data/doc/classes/Array.src/M000038.html +0 -18
  93. data/doc/classes/Array.src/M000039.html +0 -21
  94. data/doc/classes/Array.src/M000040.html +0 -18
  95. data/doc/classes/Array.src/M000041.html +0 -18
  96. data/doc/classes/Class.html +0 -171
  97. data/doc/classes/Class.src/M000042.html +0 -18
  98. data/doc/classes/Class.src/M000043.html +0 -18
  99. data/doc/classes/Hash.html +0 -516
  100. data/doc/classes/Hash.src/M000001.html +0 -18
  101. data/doc/classes/Hash.src/M000002.html +0 -21
  102. data/doc/classes/Hash.src/M000003.html +0 -18
  103. data/doc/classes/Hash.src/M000004.html +0 -21
  104. data/doc/classes/Hash.src/M000005.html +0 -18
  105. data/doc/classes/Hash.src/M000006.html +0 -20
  106. data/doc/classes/Hash.src/M000007.html +0 -18
  107. data/doc/classes/Hash.src/M000008.html +0 -22
  108. data/doc/classes/Hash.src/M000009.html +0 -18
  109. data/doc/classes/Hash.src/M000010.html +0 -21
  110. data/doc/classes/Hash.src/M000011.html +0 -24
  111. data/doc/classes/Hash.src/M000012.html +0 -18
  112. data/doc/classes/Hash.src/M000013.html +0 -21
  113. data/doc/classes/Hash.src/M000014.html +0 -18
  114. data/doc/classes/Hash.src/M000015.html +0 -21
  115. data/doc/classes/Hash.src/M000016.html +0 -18
  116. data/doc/classes/Hash.src/M000017.html +0 -21
  117. data/doc/classes/Hash.src/M000018.html +0 -27
  118. data/doc/classes/Hash.src/M000019.html +0 -20
  119. data/doc/classes/Hash.src/M000020.html +0 -18
  120. data/doc/classes/Hash.src/M000021.html +0 -18
  121. data/doc/classes/Hash.src/M000022.html +0 -18
  122. data/doc/classes/Hash.src/M000023.html +0 -18
  123. data/doc/classes/Hash.src/M000024.html +0 -18
  124. data/doc/classes/Hash.src/M000025.html +0 -28
  125. data/doc/classes/Object.html +0 -278
  126. data/doc/classes/Object.src/M000044.html +0 -24
  127. data/doc/classes/Object.src/M000045.html +0 -19
  128. data/doc/classes/Object.src/M000046.html +0 -24
  129. data/doc/classes/Object.src/M000047.html +0 -18
  130. data/doc/classes/Object.src/M000048.html +0 -19
  131. data/doc/classes/Object.src/M000049.html +0 -18
  132. data/doc/classes/Object.src/M000050.html +0 -18
  133. data/doc/classes/Object.src/M000051.html +0 -18
  134. data/doc/classes/Qbxml.html +0 -131
  135. data/doc/classes/Qbxml/Request.html +0 -224
  136. data/doc/classes/Qbxml/Request.src/M000132.html +0 -66
  137. data/doc/classes/Qbxml/Request.src/M000133.html +0 -19
  138. data/doc/classes/Qbxml/Request.src/M000134.html +0 -83
  139. data/doc/classes/Qbxml/RequestSet.html +0 -199
  140. data/doc/classes/Qbxml/RequestSet.src/M000135.html +0 -22
  141. data/doc/classes/Qbxml/RequestSet.src/M000136.html +0 -26
  142. data/doc/classes/Qbxml/RequestSet.src/M000137.html +0 -18
  143. data/doc/classes/Qbxml/RequestSet.src/M000138.html +0 -22
  144. data/doc/classes/Qbxml/Response.html +0 -302
  145. data/doc/classes/Qbxml/Response.src/M000123.html +0 -24
  146. data/doc/classes/Qbxml/Response.src/M000124.html +0 -19
  147. data/doc/classes/Qbxml/Response.src/M000125.html +0 -55
  148. data/doc/classes/Qbxml/Response.src/M000126.html +0 -18
  149. data/doc/classes/Qbxml/Response.src/M000127.html +0 -18
  150. data/doc/classes/Qbxml/Response.src/M000128.html +0 -18
  151. data/doc/classes/Qbxml/Response.src/M000129.html +0 -18
  152. data/doc/classes/Qbxml/Response.src/M000130.html +0 -18
  153. data/doc/classes/Qbxml/Response.src/M000131.html +0 -63
  154. data/doc/classes/Qbxml/ResponseSet.html +0 -244
  155. data/doc/classes/Qbxml/ResponseSet.src/M000116.html +0 -22
  156. data/doc/classes/Qbxml/ResponseSet.src/M000117.html +0 -26
  157. data/doc/classes/Qbxml/ResponseSet.src/M000118.html +0 -24
  158. data/doc/classes/Qbxml/ResponseSet.src/M000119.html +0 -20
  159. data/doc/classes/Qbxml/ResponseSet.src/M000120.html +0 -27
  160. data/doc/classes/Qbxml/ResponseSet.src/M000121.html +0 -18
  161. data/doc/classes/Qbxml/ResponseSet.src/M000122.html +0 -18
  162. data/doc/classes/Quickbooks.html +0 -196
  163. data/doc/classes/Quickbooks/Address.html +0 -139
  164. data/doc/classes/Quickbooks/Address.src/M000115.html +0 -19
  165. data/doc/classes/Quickbooks/Base.html +0 -567
  166. data/doc/classes/Quickbooks/Base.src/M000095.html +0 -18
  167. data/doc/classes/Quickbooks/Base.src/M000096.html +0 -20
  168. data/doc/classes/Quickbooks/Base.src/M000097.html +0 -19
  169. data/doc/classes/Quickbooks/Base.src/M000098.html +0 -18
  170. data/doc/classes/Quickbooks/Base.src/M000099.html +0 -19
  171. data/doc/classes/Quickbooks/Base.src/M000100.html +0 -30
  172. data/doc/classes/Quickbooks/Base.src/M000101.html +0 -22
  173. data/doc/classes/Quickbooks/Base.src/M000102.html +0 -30
  174. data/doc/classes/Quickbooks/Base.src/M000103.html +0 -19
  175. data/doc/classes/Quickbooks/Base.src/M000104.html +0 -19
  176. data/doc/classes/Quickbooks/Base.src/M000105.html +0 -18
  177. data/doc/classes/Quickbooks/Base.src/M000106.html +0 -18
  178. data/doc/classes/Quickbooks/Base.src/M000107.html +0 -19
  179. data/doc/classes/Quickbooks/Base.src/M000108.html +0 -18
  180. data/doc/classes/Quickbooks/Base.src/M000109.html +0 -45
  181. data/doc/classes/Quickbooks/Base.src/M000110.html +0 -18
  182. data/doc/classes/Quickbooks/Base.src/M000111.html +0 -18
  183. data/doc/classes/Quickbooks/Base.src/M000112.html +0 -20
  184. data/doc/classes/Quickbooks/BillAddress.html +0 -113
  185. data/doc/classes/Quickbooks/CreditCardInfo.html +0 -113
  186. data/doc/classes/Quickbooks/Customer.html +0 -113
  187. data/doc/classes/Quickbooks/CustomerTypeRef.html +0 -113
  188. data/doc/classes/Quickbooks/Deleted.html +0 -113
  189. data/doc/classes/Quickbooks/ItemSalesTaxRef.html +0 -113
  190. data/doc/classes/Quickbooks/JobTypeRef.html +0 -113
  191. data/doc/classes/Quickbooks/ListDeleted.html +0 -139
  192. data/doc/classes/Quickbooks/ListDeleted.src/M000114.html +0 -18
  193. data/doc/classes/Quickbooks/ListItem.html +0 -170
  194. data/doc/classes/Quickbooks/ListItem.src/M000093.html +0 -20
  195. data/doc/classes/Quickbooks/ListItem.src/M000094.html +0 -18
  196. data/doc/classes/Quickbooks/Model.html +0 -462
  197. data/doc/classes/Quickbooks/Model.src/M000073.html +0 -24
  198. data/doc/classes/Quickbooks/Model.src/M000074.html +0 -19
  199. data/doc/classes/Quickbooks/Model.src/M000075.html +0 -18
  200. data/doc/classes/Quickbooks/Model.src/M000076.html +0 -18
  201. data/doc/classes/Quickbooks/Model.src/M000077.html +0 -18
  202. data/doc/classes/Quickbooks/Model.src/M000078.html +0 -22
  203. data/doc/classes/Quickbooks/Model.src/M000079.html +0 -32
  204. data/doc/classes/Quickbooks/Model.src/M000080.html +0 -32
  205. data/doc/classes/Quickbooks/Model.src/M000081.html +0 -18
  206. data/doc/classes/Quickbooks/Model.src/M000082.html +0 -18
  207. data/doc/classes/Quickbooks/Model.src/M000083.html +0 -22
  208. data/doc/classes/Quickbooks/Model.src/M000084.html +0 -23
  209. data/doc/classes/Quickbooks/Model.src/M000085.html +0 -18
  210. data/doc/classes/Quickbooks/Model.src/M000086.html +0 -21
  211. data/doc/classes/Quickbooks/Model.src/M000087.html +0 -26
  212. data/doc/classes/Quickbooks/Model.src/M000088.html +0 -26
  213. data/doc/classes/Quickbooks/Model.src/M000089.html +0 -26
  214. data/doc/classes/Quickbooks/Model.src/M000090.html +0 -21
  215. data/doc/classes/Quickbooks/Model.src/M000091.html +0 -23
  216. data/doc/classes/Quickbooks/OleAdapter.html +0 -129
  217. data/doc/classes/Quickbooks/OleAdapter/Connection.html +0 -343
  218. data/doc/classes/Quickbooks/OleAdapter/Connection.src/M000058.html +0 -18
  219. data/doc/classes/Quickbooks/OleAdapter/Connection.src/M000059.html +0 -19
  220. data/doc/classes/Quickbooks/OleAdapter/Connection.src/M000060.html +0 -24
  221. data/doc/classes/Quickbooks/OleAdapter/Connection.src/M000061.html +0 -18
  222. data/doc/classes/Quickbooks/OleAdapter/Connection.src/M000062.html +0 -18
  223. data/doc/classes/Quickbooks/OleAdapter/Connection.src/M000063.html +0 -21
  224. data/doc/classes/Quickbooks/OleAdapter/Connection.src/M000064.html +0 -24
  225. data/doc/classes/Quickbooks/OleAdapter/Connection.src/M000065.html +0 -20
  226. data/doc/classes/Quickbooks/OleAdapter/Connection.src/M000066.html +0 -24
  227. data/doc/classes/Quickbooks/OleAdapter/Connection.src/M000067.html +0 -24
  228. data/doc/classes/Quickbooks/OleAdapter/Ole.html +0 -209
  229. data/doc/classes/Quickbooks/OleAdapter/Ole.src/M000068.html +0 -21
  230. data/doc/classes/Quickbooks/OleAdapter/Ole.src/M000069.html +0 -22
  231. data/doc/classes/Quickbooks/OleAdapter/Ole.src/M000070.html +0 -18
  232. data/doc/classes/Quickbooks/ParentRef.html +0 -113
  233. data/doc/classes/Quickbooks/PreferredPaymentMethodRef.html +0 -113
  234. data/doc/classes/Quickbooks/PriceLevelRef.html +0 -113
  235. data/doc/classes/Quickbooks/QbxmlDebugAdapter.html +0 -111
  236. data/doc/classes/Quickbooks/QbxmlDebugAdapter/Connection.html +0 -139
  237. data/doc/classes/Quickbooks/QbxmlDebugAdapter/Connection.src/M000057.html +0 -18
  238. data/doc/classes/Quickbooks/Ref.html +0 -146
  239. data/doc/classes/Quickbooks/Ref.src/M000113.html +0 -18
  240. data/doc/classes/Quickbooks/SalesRepRef.html +0 -113
  241. data/doc/classes/Quickbooks/SalesTaxCodeRef.html +0 -113
  242. data/doc/classes/Quickbooks/ShipAddress.html +0 -113
  243. data/doc/classes/Quickbooks/TermsRef.html +0 -113
  244. data/doc/classes/Quickbooks/Transaction.html +0 -154
  245. data/doc/classes/Quickbooks/Transaction.src/M000071.html +0 -19
  246. data/doc/classes/Quickbooks/Transaction.src/M000072.html +0 -18
  247. data/doc/classes/Quickbooks/TxnDeleted.html +0 -139
  248. data/doc/classes/Quickbooks/TxnDeleted.src/M000092.html +0 -18
  249. data/doc/classes/String.html +0 -203
  250. data/doc/classes/String.src/M000052.html +0 -18
  251. data/doc/classes/String.src/M000053.html +0 -18
  252. data/doc/classes/String.src/M000054.html +0 -18
  253. data/doc/classes/String.src/M000055.html +0 -18
  254. data/doc/classes/String.src/M000056.html +0 -18
  255. data/doc/created.rid +0 -1
  256. data/doc/files/LICENSE.html +0 -129
  257. data/doc/files/README.html +0 -225
  258. data/doc/files/lib/qbxml/request_rb.html +0 -110
  259. data/doc/files/lib/qbxml/response_rb.html +0 -109
  260. data/doc/files/lib/qbxml/support_rb.html +0 -101
  261. data/doc/files/lib/qbxml_rb.html +0 -122
  262. data/doc/files/lib/quickbooks/adapters/ole_adapter_rb.html +0 -108
  263. data/doc/files/lib/quickbooks/adapters/qbxml_debug_adapter_rb.html +0 -108
  264. data/doc/files/lib/quickbooks/base_rb.html +0 -327
  265. data/doc/files/lib/quickbooks/model_rb.html +0 -108
  266. data/doc/files/lib/quickbooks/models/common/address_rb.html +0 -101
  267. data/doc/files/lib/quickbooks/models/common/all_refs_rb.html +0 -101
  268. data/doc/files/lib/quickbooks/models/customer/credit_card_info_rb.html +0 -101
  269. data/doc/files/lib/quickbooks/models/customer_rb.html +0 -110
  270. data/doc/files/lib/quickbooks/models/deleted_rb.html +0 -101
  271. data/doc/files/lib/quickbooks/models/list_item_rb.html +0 -101
  272. data/doc/files/lib/quickbooks/models/transaction_rb.html +0 -101
  273. data/doc/files/lib/quickbooks/ruby_magic_rb.html +0 -120
  274. data/doc/files/lib/quickbooks_rb.html +0 -125
  275. data/doc/fr_class_index.html +0 -64
  276. data/doc/fr_file_index.html +0 -45
  277. data/doc/fr_method_index.html +0 -164
  278. data/doc/index.html +0 -24
  279. data/doc/rdoc-style.css +0 -208
  280. data/lib/qbxml.rb +0 -3
  281. data/lib/qbxml/request.rb +0 -207
  282. data/lib/qbxml/response.rb +0 -197
  283. data/lib/qbxml/support.rb +0 -130
  284. data/lib/quickbooks/adapters/qbxml_debug_adapter.rb +0 -10
  285. data/lib/quickbooks/base.rb +0 -277
  286. data/lib/quickbooks/models/common/address.rb +0 -14
  287. data/lib/quickbooks/models/common/all_refs.rb +0 -37
  288. data/lib/quickbooks/models/customer.rb +0 -70
  289. data/lib/quickbooks/models/customer/credit_card_info.rb +0 -5
  290. data/lib/quickbooks/models/deleted.rb +0 -22
  291. data/lib/quickbooks/models/list_item.rb +0 -41
  292. data/lib/quickbooks/models/transaction.rb +0 -49
  293. data/lib/quickbooks/ruby_magic.rb +0 -213
@@ -0,0 +1,105 @@
1
+ class ElementCollection
2
+ include Enumerable
3
+ def each
4
+ items.each {|e| yield e}
5
+ end
6
+
7
+ attr_reader :type
8
+ def initialize(parent, type, items=[])
9
+ @parent = parent
10
+ @type = QB[type.to_s]
11
+ (items.is_a?(Enumerable) ? items : [items]).each { |item| add_item(item) }
12
+ end
13
+
14
+ # Access items by index.
15
+ def [](index)
16
+ items[index]
17
+ end
18
+
19
+ # Adds an item to the collection. The item type must be the same as the registered type for this Collection.
20
+ def build(item={})
21
+ raise RuntimeError, "cannot introduce an existing #{@type.to_s} to a new #{self.class.short_name}!" if item.is_a?(Quickbooks::Model) && !item.new_record? && @parent.new_record?
22
+ item = add_item(item)
23
+ item.instance_variable_set(:@collection_index, items.length-1)
24
+ return item
25
+ end
26
+ alias :<< :build
27
+
28
+ # Returns the number of items in the collection
29
+ def length
30
+ items.length
31
+ end
32
+
33
+ def empty? #:nodoc:
34
+ items.empty?
35
+ end
36
+
37
+ def valid?
38
+ errors.clear
39
+ r = items.inject(Valean.new) {|r,e| r << e.validate; r}
40
+ errors.concat(r.errors) if !r.errors.empty?
41
+ r.perfect?
42
+ end
43
+
44
+ def errors
45
+ @errors ||= []
46
+ end
47
+ def add_error(msg) #:nodoc:
48
+ errors << [nil, msg]
49
+ end
50
+
51
+ def dirty? #:nodoc:
52
+ @dirty ||= false
53
+ end
54
+
55
+ def inspect #:nodoc:
56
+ "[Collection of #{@type.short_name}: #{items.join(', ')}]"
57
+ end
58
+
59
+ # TODO: Has a problem when an element is a new_record and a child isn't, or vice-versa.
60
+ def to_element #:nodoc:
61
+ element_klass = @type < Quickbooks::Model ? (@type.short_name + (@parent.new_record? ? 'Add' : 'Mod')) : @type.short_name
62
+ puts "Converting to #{element_klass}"
63
+ elements = ElementCollection.new(@parent, element_klass)
64
+ items.each {|e| elements << (@type < Quickbooks::Model ? e.to_element : e)}
65
+ return elements
66
+ end
67
+
68
+ def to_model #:nodoc:
69
+ # Strips off Add, Mod, or Ret to turn whatever it is into a Model object
70
+ models = ElementCollection.new(@parent, @type.short_name.gsub(/(Add|Mod|Ret)$/,''))
71
+ items.each {|e| models << e.to_model}
72
+ return models
73
+ end
74
+
75
+ # Returns this collection but as a regular Array.
76
+ def to_a
77
+ items.dup
78
+ end
79
+
80
+ def save_associations #:nodoc:
81
+ each { |el| el.save_associations if el.respond_to?(:save_associations) }
82
+ end
83
+
84
+ private
85
+
86
+ def items
87
+ @items ||= []
88
+ end
89
+
90
+ def add_item(item)
91
+ item = @type.new(item) unless item.is_a?(@type)
92
+ item.send(:dirty!) if dirty?
93
+ items << item
94
+ return item
95
+ end
96
+
97
+ def clean!
98
+ @dirty = false
99
+ items.each {|e| e.send(:clean!)}
100
+ end
101
+
102
+ def dirty!
103
+ @dirty = true
104
+ end
105
+ end
@@ -0,0 +1,8 @@
1
+ require 'quickbooks/extlib/class'
2
+ require 'quickbooks/extlib/object'
3
+ require 'quickbooks/extlib/string'
4
+ require 'quickbooks/extlib/hash'
5
+ require 'quickbooks/extlib/time'
6
+ require 'quickbooks/extlib/assertions'
7
+ require 'quickbooks/extlib/inflection'
8
+ require 'quickbooks/extlib/days_and_times'
@@ -0,0 +1,8 @@
1
+ module Extlib
2
+ module Assertions
3
+ def assert_kind_of(name, value, *klasses)
4
+ klasses.each { |k| return if value.kind_of?(k) }
5
+ raise ArgumentError, "+#{name}+ should be #{klasses.map { |k| k.name } * ' or '}, but was #{value.class.name}", caller(2)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,98 @@
1
+ # Copyright (c) 2004-2008 David Heinemeier Hansson
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ # Allows attributes to be shared within an inheritance hierarchy, but where
23
+ # each descendant gets a copy of their parents' attributes, instead of just a
24
+ # pointer to the same. This means that the child can add elements to, for
25
+ # example, an array without those additions being shared with either their
26
+ # parent, siblings, or children, which is unlike the regular class-level
27
+ # attributes that are shared across the entire hierarchy.
28
+ class Class
29
+ # Defines class-level and instance-level attribute reader.
30
+ #
31
+ # @param *syms<Array> Array of attributes to define reader for.
32
+ # @return <Array[#to_s]> List of attributes that were made into cattr_readers
33
+ #
34
+ # @api public
35
+ #
36
+ # @todo Is this inconsistent in that it does not allow you to prevent
37
+ # an instance_reader via :instance_reader => false
38
+ def cattr_reader(*syms)
39
+ syms.flatten.each do |sym|
40
+ next if sym.is_a?(Hash)
41
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
42
+ unless defined? @@#{sym}
43
+ @@#{sym} = nil
44
+ end
45
+
46
+ def self.#{sym}
47
+ @@#{sym}
48
+ end
49
+
50
+ def #{sym}
51
+ @@#{sym}
52
+ end
53
+ RUBY
54
+ end
55
+ end
56
+
57
+ # Defines class-level (and optionally instance-level) attribute writer.
58
+ #
59
+ # @param <Array[*#to_s, Hash{:instance_writer => Boolean}]> Array of attributes to define writer for.
60
+ # @option syms :instance_writer<Boolean> if true, instance-level attribute writer is defined.
61
+ # @return <Array[#to_s]> List of attributes that were made into cattr_writers
62
+ #
63
+ # @api public
64
+ def cattr_writer(*syms)
65
+ options = syms.last.is_a?(Hash) ? syms.pop : {}
66
+ syms.flatten.each do |sym|
67
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
68
+ unless defined? @@#{sym}
69
+ @@#{sym} = nil
70
+ end
71
+
72
+ def self.#{sym}=(obj)
73
+ @@#{sym} = obj
74
+ end
75
+ RUBY
76
+
77
+ unless options[:instance_writer] == false
78
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
79
+ def #{sym}=(obj)
80
+ @@#{sym} = obj
81
+ end
82
+ RUBY
83
+ end
84
+ end
85
+ end
86
+
87
+ # Defines class-level (and optionally instance-level) attribute accessor.
88
+ #
89
+ # @param *syms<Array[*#to_s, Hash{:instance_writer => Boolean}]> Array of attributes to define accessor for.
90
+ # @option syms :instance_writer<Boolean> if true, instance-level attribute writer is defined.
91
+ # @return <Array[#to_s]> List of attributes that were made into accessors
92
+ #
93
+ # @api public
94
+ def cattr_accessor(*syms)
95
+ cattr_reader(*syms)
96
+ cattr_writer(*syms)
97
+ end
98
+ end
@@ -0,0 +1,10 @@
1
+ module DaysAndTimes
2
+ def self.VERSION
3
+ '1.0.0'
4
+ end
5
+ end
6
+
7
+ require File.dirname(__FILE__)+'/days_and_times/duration'
8
+ require File.dirname(__FILE__)+'/days_and_times/numeric'
9
+ require File.dirname(__FILE__)+'/days_and_times/time'
10
+ require File.dirname(__FILE__)+'/days_and_times/object'
@@ -0,0 +1,362 @@
1
+ require 'time'
2
+ class Duration
3
+ # Length is the length of the time span, in seconds
4
+ # Unit is a length of time (in seconds) to use in collection methods
5
+ # StartTime is an optional attribute that can 'anchor' a duration
6
+ # to a specific real time.
7
+ attr_accessor :length, :unit, :start_time
8
+ def initialize(count=0,unit=1,start_time=nil,auto_klass={})
9
+ if unit.is_a?(Time) || unit.is_a?(DateTime)
10
+ start_time = unit
11
+ unit = 1
12
+ end
13
+ options = {:count => count || 0, :unit => unit || 1, :start_time => start_time}.merge(count.is_a?(Hash) ? count : {})
14
+
15
+ @unit = options[:unit]
16
+ @length = (@unit * options[:count].to_f).round
17
+ @start_time = options[:start_time]
18
+ end
19
+ def self.new(*args)
20
+ a = super
21
+ if self.name == 'Duration' && (args.last.is_a?(Hash) ? args.last[:auto_class] == true : true)
22
+ a.send(:auto_class)
23
+ else
24
+ a
25
+ end
26
+ end
27
+ def self.length
28
+ 1
29
+ end
30
+
31
+ # * * * * * * * * * * * * * * * *
32
+ # A Duration is a LENGTH of Time
33
+ # -This is measured in seconds,
34
+ # but set in terms of the unit
35
+ # currently being used.
36
+ def length=(value)
37
+ if value.respond_to?(:to_f)
38
+ @length = (self.unit * value.to_f).round
39
+ else
40
+ raise TypeError, "Can't set a Duration's length to a #{value.class.name} object."
41
+ end
42
+ end
43
+ def length
44
+ length = @length.to_f / self.unit
45
+ length.to_i == length ? length.to_i : length
46
+ end
47
+ def abs_length=(value)
48
+ if value.respond_to?(:to_i)
49
+ @length = value.to_i
50
+ else
51
+ raise TypeError, "Can't set a Duration's length to a #{value.class.name} object."
52
+ end
53
+ end
54
+ def abs_length
55
+ @length
56
+ end
57
+ def to_i
58
+ self.abs_length.to_i
59
+ end
60
+ def to_f
61
+ self.abs_length.to_f
62
+ end
63
+ def to_s
64
+ "#{self.length} #{self.class.name}"
65
+ end
66
+ def coerce(*args)
67
+ to_f.coerce(*args)
68
+ end
69
+
70
+ def ===(other)
71
+ self.to_f == other.to_f
72
+ end
73
+ def inspect
74
+ "#<#{self.class.name}:#{self.object_id} (length=#{self.length.inspect}) #{self.instance_variables.reject {|d| d=='@length' || self.instance_variable_get(d).nil?}.collect {|iv| "#{iv}=#{self.instance_variable_get(iv).inspect}"}.join(' ')}>"
75
+ end
76
+ # * * * * * * * * * * * * * * * *
77
+
78
+ # * * * * * * * * * * * * * * * * * * * * *
79
+ # A Duration's calculations utilize a UNIT
80
+ # -This is stored as the number of
81
+ # seconds equal to the unit's value.
82
+ def unit=(value)
83
+ if value.respond_to?(:to_i)
84
+ @unit = value.to_i
85
+ else
86
+ raise TypeError, "Can't set a Duration's unit to a #{value.class.name} object."
87
+ end
88
+ end
89
+ def -(value)
90
+ if value.respond_to?(:to_i)
91
+ auto_class(Duration.new(@length - value.to_i))
92
+ else
93
+ raise TypeError, "Can't convert #{value.class.name} to an integer."
94
+ end
95
+ end
96
+ def +(value)
97
+ if value.respond_to?(:to_i)
98
+ auto_class(Duration.new(@length + value.to_i))
99
+ else
100
+ raise TypeError, "Can't convert #{value.class.name} to an integer."
101
+ end
102
+ end
103
+ def *(value)
104
+ if value.is_a?(Duration)
105
+ @length * value.length * value.unit
106
+ elsif value.respond_to?(:to_i)
107
+ auto_class(Duration.new(@length * value))
108
+ else
109
+ raise TypeError, "Can't convert #{value.class.name} to an integer."
110
+ end
111
+ end
112
+ def /(value)
113
+ if value.is_a?(Duration)
114
+ @length / (value.length * value.unit)
115
+ elsif value.respond_to?(:to_i)
116
+ auto_class(Duration.new(@length / value))
117
+ else
118
+ raise TypeError, "Can't convert #{value.class.name} to an integer."
119
+ end
120
+ end
121
+ def in_weeks
122
+ Duration.new(@length.to_f / Week.length, Week.length)
123
+ end
124
+ def in_days
125
+ Duration.new(@length.to_f / Day.length, Day.length)
126
+ end
127
+ def in_hours
128
+ Duration.new(@length.to_f / Hour.length, Hour.length)
129
+ end
130
+ def in_minutes
131
+ Duration.new(@length.to_f / Minute.length, Minute.length)
132
+ end
133
+ def in_seconds
134
+ Duration.new(@length.to_f / Second.length, Second.length)
135
+ end
136
+ def weeks
137
+ @length.to_f / Week.length
138
+ end
139
+ def days
140
+ @length.to_f / Day.length
141
+ end
142
+ def hours
143
+ @length.to_f / Hour.length
144
+ end
145
+ def minutes
146
+ @length.to_f / Minute.length
147
+ end
148
+ def seconds
149
+ @length.to_f / Second.length
150
+ end
151
+ # * * * * * * * * * * * * * * * * * * * * *
152
+
153
+ # * * * * * * * * * * * * * * * * * * * * * * *
154
+ # A Duration can be 'anchored' to a START_TIME
155
+ # -This start_time is a Time object
156
+ def start_time=(value)
157
+ if value.is_a?(Time) || value.is_a?(DateTime)
158
+ @start_time = value.to_time
159
+ else
160
+ raise TypeError, "A Duration's start_time must be a Time or DateTime object."
161
+ end
162
+ end
163
+ def end_time=(value)
164
+ if value.is_a?(Time) || value.is_a?(DateTime)
165
+ @start_time = value.to_time - self #Subtracts this duration from the end_time to get the start_time
166
+ else
167
+ raise TypeError, "A Duration's end_time must be a Time or DateTime object."
168
+ end
169
+ end
170
+ def end_time
171
+ @start_time + self
172
+ end
173
+ def anchored?
174
+ !self.start_time.nil?
175
+ end
176
+ # * * * * * * * * * * * * * * * * * * * * * * *
177
+
178
+ # * * * * * * * * * * * * * * * * * * * * * * * *
179
+ # Calculations using Duration as an intermediate
180
+ def from(time)
181
+ time + @length
182
+ end
183
+ def before(time)
184
+ time - @length
185
+ end
186
+ def from_now
187
+ self.from(Time.now)
188
+ end
189
+ def ago
190
+ self.before(Time.now)
191
+ end
192
+ def starting(time)
193
+ self.start_time = time
194
+ self
195
+ end
196
+ def ending(time)
197
+ self.end_time = time
198
+ self
199
+ end
200
+ # * * * * * * * * * * * * * * * * * * * * * * * *
201
+
202
+ # * * * * * * * * * * * * * * * * * * * * * * * * * * *
203
+ # A Duration can be treated as a 'collection' of units
204
+ def each_week(&block)
205
+ self.each(Week.length,&block)
206
+ end
207
+ def each_day(&block)
208
+ self.each(Day.length,&block)
209
+ end
210
+ def each_hour(&block)
211
+ self.each(Hour.length,&block)
212
+ end
213
+ def each_minute(&block)
214
+ self.each(Minute.length,&block)
215
+ end
216
+ def each_second(&block)
217
+ self.each(Second.length,&block)
218
+ end
219
+ def collect(use_unit=self.class.length,&block)
220
+ ary = []
221
+ self.each(use_unit) do |x|
222
+ ary << (block_given? ? yield(x) : x)
223
+ end
224
+ ary
225
+ end
226
+ def each(use_unit=self.class.length)
227
+ remainder = @length.to_f % use_unit
228
+ ret = []
229
+ if self.start_time.nil?
230
+ (@length.to_f / use_unit).to_i.times do |i|
231
+ ret << Duration.new(1, use_unit)
232
+ yield(ret[-1])
233
+ end
234
+ else
235
+ (@length.to_f / use_unit).to_i.times do |i|
236
+ ret << Duration.new(1, use_unit, (self.start_time + (use_unit * i)))
237
+ yield(ret[-1])
238
+ end
239
+ end
240
+ if remainder > 0
241
+ ret << (self.start_time.nil? ? Duration.new(remainder, 1) : Duration.new(remainder, 1, (self.start_time + @length - remainder)))
242
+ yield(ret[-1])
243
+ end
244
+ ret
245
+ end
246
+ # * * * * * * * * * * * * * * * * * * * * * * * * * * *
247
+
248
+ # * * * * * * * * * * * * * * * * * * * * * * * * * * *
249
+ # Through some ingenious metacoding (see 'def bind_object_method') below,
250
+ # it is possible to create a new method on a Duration object
251
+ # to a method on another object, in order to gather information
252
+ # based on the duration mentioned.
253
+ def create_find_within_method_for(other, method_name, other_method_name)
254
+ self.bind_object_method(other, method_name, other_method_name, [[], ['self.start_time', 'self.end_time']])
255
+ end
256
+ def self.create_find_within_method_for(other, method_name, other_method_name)
257
+ self.bind_class_object_method(other, method_name, other_method_name, [[], ['self.start_time', 'self.end_time']])
258
+ end
259
+ # * * * * * * * * * * * * * * * * * * * * * * * * * * *
260
+
261
+ def method_missing(method_name, *args)
262
+ # Delegate any missing methods to the start_time Time object, if we have a start_time and the method exists there.
263
+ return self.start_time.send(method_name, *args) if self.anchored? && self.start_time.respond_to?(method_name)
264
+ super
265
+ end
266
+
267
+ private
268
+ def auto_class(obj=self)
269
+ new_obj = case obj.unit
270
+ when 1
271
+ obj.class.name == 'Seconds' ? obj : (obj.length == 1 ? Second.new(obj.start_time) : Seconds.new(obj.length,obj.start_time))
272
+ when 60
273
+ obj.class.name == 'Minutes' ? obj : (obj.length == 1 ? Minute.new(obj.start_time) : Minutes.new(obj.length,obj.start_time))
274
+ when 3600
275
+ obj.class.name == 'Hours' ? obj : (obj.length == 1 ? Hour.new(obj.start_time) : Hours.new(obj.length,obj.start_time))
276
+ when 86400
277
+ obj.class.name == 'Days' ? obj : (obj.length == 1 ? Day.new(obj.start_time) : Days.new(obj.length,obj.start_time))
278
+ when 604800
279
+ obj.class.name == 'Weeks' ? obj : (obj.length == 1 ? Week.new(obj.start_time) : Weeks.new(obj.length,obj.start_time))
280
+ else
281
+ obj.class.name == 'Duration' ? obj : Duration.new(obj.length,obj.unit,obj.start_time,{:auto_class => false})
282
+ end
283
+ # Now, auto-transform class if possible:
284
+ case
285
+ when !['Weeks', 'Week'].include?(new_obj.class.name) && new_obj.to_i.remainder(Week.length) == 0
286
+ new_obj.to_i == Week.length ? Week.new(new_obj.start_time) : Weeks.new(new_obj.to_f / Week.length,new_obj.start_time)
287
+ when !['Weeks', 'Week', 'Days', 'Day'].include?(new_obj.class.name) && new_obj.to_i.remainder(Day.length) == 0
288
+ new_obj.to_i == Day.length ? Day.new(new_obj.start_time) : Days.new(new_obj.to_f / Day.length,new_obj.start_time)
289
+ when !['Weeks', 'Week', 'Days', 'Day', 'Hours', 'Hour'].include?(new_obj.class.name) && new_obj.to_i.remainder(Hour.length) == 0
290
+ new_obj.to_i == Hour.length ? Hour.new(new_obj.start_time) : Hours.new(new_obj.to_f / Hour.length,new_obj.start_time)
291
+ when !['Weeks', 'Week', 'Days', 'Day', 'Hours', 'Hour', 'Minutes', 'Minute'].include?(new_obj.class.name) && new_obj.to_f.remainder(Minute.length) == 0
292
+ new_obj.to_i == Minute.length ? Minute.new(new_obj.start_time) : Minutes.new(new_obj.to_f / Minute.length,new_obj.start_time)
293
+ else
294
+ new_obj
295
+ end
296
+ end
297
+ end
298
+ class Weeks < Duration
299
+ def initialize(count=1,start_time=nil)
300
+ super(count,Week.length,start_time)
301
+ end
302
+ def self.length
303
+ 604800
304
+ end
305
+ end
306
+ class Week < Weeks
307
+ def initialize(start_time=nil)
308
+ super(1,start_time)
309
+ end
310
+ end
311
+ class Days < Duration
312
+ def initialize(count=1,start_time=nil)
313
+ super(count,Day.length,start_time)
314
+ end
315
+ def self.length
316
+ 86400
317
+ end
318
+ end
319
+ class Day < Days
320
+ def initialize(start_time=nil)
321
+ super(1,start_time)
322
+ end
323
+ end
324
+ class Hours < Duration
325
+ def initialize(count=1,start_time=nil)
326
+ super(count,Hour.length,start_time)
327
+ end
328
+ def self.length
329
+ 3600
330
+ end
331
+ end
332
+ class Hour < Hours
333
+ def initialize(start_time=nil)
334
+ super(1,start_time)
335
+ end
336
+ end
337
+ class Minutes < Duration
338
+ def initialize(count=1,start_time=nil)
339
+ super(count,Minute.length,start_time)
340
+ end
341
+ def self.length
342
+ 60
343
+ end
344
+ end
345
+ class Minute < Minutes
346
+ def initialize(start_time=nil)
347
+ super(1,start_time)
348
+ end
349
+ end
350
+ class Seconds < Duration
351
+ def initialize(count=1,start_time=nil)
352
+ super(count,Second.length,start_time)
353
+ end
354
+ def self.length
355
+ 1
356
+ end
357
+ end
358
+ class Second < Seconds
359
+ def initialize(start_time=nil)
360
+ super(1,start_time)
361
+ end
362
+ end