From 8280a21a23d44aa90177e2bc041d0b8dc8556f4b Mon Sep 17 00:00:00 2001 From: Unit 193 Date: Mon, 12 Jun 2017 03:37:11 -0400 Subject: Import Upstream version 2.7.1 --- spec/fixtures/vcr_cassettes/google_drive.yml | 165 ++++ .../vcr_cassettes/google_drive_access_token.yml | 73 ++ spec/fixtures/vcr_cassettes/google_drive_set.yml | 857 +++++++++++++++++++++ spec/helpers.rb | 5 + spec/lib/roo/base_spec.rb | 233 ++++++ spec/lib/roo/csv_spec.rb | 81 ++ spec/lib/roo/excelx/format_spec.rb | 51 ++ spec/lib/roo/excelx_spec.rb | 537 +++++++++++++ spec/lib/roo/libreoffice_spec.rb | 29 + spec/lib/roo/openoffice_spec.rb | 43 ++ spec/lib/roo/spreadsheet_spec.rb | 108 +++ spec/lib/roo/utils_spec.rb | 106 +++ spec/spec_helper.rb | 9 + 13 files changed, 2297 insertions(+) create mode 100644 spec/fixtures/vcr_cassettes/google_drive.yml create mode 100644 spec/fixtures/vcr_cassettes/google_drive_access_token.yml create mode 100644 spec/fixtures/vcr_cassettes/google_drive_set.yml create mode 100644 spec/helpers.rb create mode 100644 spec/lib/roo/base_spec.rb create mode 100644 spec/lib/roo/csv_spec.rb create mode 100644 spec/lib/roo/excelx/format_spec.rb create mode 100755 spec/lib/roo/excelx_spec.rb create mode 100644 spec/lib/roo/libreoffice_spec.rb create mode 100644 spec/lib/roo/openoffice_spec.rb create mode 100644 spec/lib/roo/spreadsheet_spec.rb create mode 100644 spec/lib/roo/utils_spec.rb create mode 100644 spec/spec_helper.rb (limited to 'spec') diff --git a/spec/fixtures/vcr_cassettes/google_drive.yml b/spec/fixtures/vcr_cassettes/google_drive.yml new file mode 100644 index 0000000..6f56579 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/google_drive.yml @@ -0,0 +1,165 @@ +--- +http_interactions: +- request: + method: post + uri: https://www.google.com/accounts/ClientLogin + body: + encoding: UTF-8 + string: accountType=HOSTED_OR_GOOGLE&Email=user&Passwd=password&service=wise&source=Gimite-RubyGoogleDrive-1.00 + headers: + Content-Type: + - application/x-www-form-urlencoded + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - '*/*' + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - text/plain + Cache-Control: + - no-cache, no-store + Pragma: + - no-cache + Expires: + - Mon, 01-Jan-1990 00:00:00 GMT + Date: + - Thu, 15 Aug 2013 00:43:34 GMT + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '881' + Server: + - GSE + body: + encoding: UTF-8 + string: | + SID=DQAAAMoAAAA8IKlqi2aGAAGTzd6pCfMwqwabb79_cvhermJV2M78CNvpiYiujQEkQMienaye4SnKIV-oS6r6KEdGp46SZy5radXnkV5pxGSHLWvExZh7pGH7o3cgmvF8N3WX_FWdGQatg_-ypztq4tgHb_E3wlQtRmT1snh8lqVDIqoaXXdlQJ_WKvgPW8NBAOQBMsnb2fV0FX2abuth0DzS6t9gpR_f-1w8d8jI7rwgBhVg0PxxHPUJMnciPDaEjK3WxLj-zGgPCZfr6vBG8asFAjFzCDYO + LSID=DQAAAMsAAADMWltQuejlYd78Px9RfXhcHnb7tlPHfKPY4i69F9Hi0dhIQbyFRlHVcyMKaR3ajpm39Tx27o5qgddVcti2kZ3CoOB6bthhPlKls7s4G9nz8ObyHSilTTNP5tjNdNNz0--4NP9lacZ-UHhKoDGKnH6lgKFi6BaCAHpQzXo-vsvStxXqo0D1OE81zL2UOYRvN1rc9evr04qtlSvCHQ8THv7eH8SGwZrdf_okjtKQDyLaEJFn5d0_YP-CiM1JLNyNtjwk6E3cWEi8NUrZh459-Lif + Auth=DQAAAMwAAADMWltQuejlYd78Px9RfXhcHnb7tlPHfKPY4i69F9Hi0dhIQbyFRlHVcyMKaR3ajpn7yZLj-g3LYQk1SM-i9ejg3r4yH0rj9yZsBcy0ZiJV1L45w4jGXlgrvse68D5axixvDp7T7u6P6K-eOJj2SaKw8vBj156hBEyn4CQFJ0tVUjl5UPAN9Wt8hJmRNqULG3LoxYwLidLgPVjCtL-lF0YnUiSwbolVBzZAbyeYk1QSzX9xT5ms3sTQ4ESz42Bg9SQbc6kdlcWzvmQ_sO5GfrTY + http_version: + recorded_at: Thu, 15 Aug 2013 00:43:35 GMT +- request: + method: post + uri: https://www.google.com/accounts/ClientLogin + body: + encoding: UTF-8 + string: accountType=HOSTED_OR_GOOGLE&Email=user&Passwd=password&service=writely&source=Gimite-RubyGoogleDrive-1.00 + headers: + Content-Type: + - application/x-www-form-urlencoded + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - '*/*' + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - text/plain + Cache-Control: + - no-cache, no-store + Pragma: + - no-cache + Expires: + - Mon, 01-Jan-1990 00:00:00 GMT + Date: + - Thu, 15 Aug 2013 00:43:35 GMT + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '881' + Server: + - GSE + body: + encoding: UTF-8 + string: | + SID=DQAAAMkAAADzBWY1u2YIJ65CWCMcGU45anMr2oknuts_SHI6BUKE9_XcnpF9Cd3LEx3nEwj8BWT4VYJSYCLMHj7PRTnT8y3L1qbs6kVLocXDqMDfPiZGI199x7RIoxNTJm6h6eS1oWnHOJ2ap_TgHSrPLYiIzt-Ajlb2R8fciXwyJM2G1BbiB66BOGQzGd1GPiCWB5cEVzRDRAlF_FKF9tS89XKdMwSBaNQQmYvs8rhWwGew6g4bGk5j2YGQzCfQARBJR-RIP1P6grQKKk50RlQViCy289AQ + LSID=DQAAAMsAAAD6x-FEGLu8C22vipJ5KzJRieLdSnd-bxlIF6iewUK4s-DUIlBl9TXOzWxUby3siw_0s_CVXjDO-0eCpUqlDSr9bTK4Z97xboEkx3TAltwZ7rfidhhx1kKEPV6wLyEqQsxLuF58kMGxPneo1ohb9wdBx6019XMG_N_R2npslywmtJSjKeZUFCNhcIOxD3kDjRFOhU9zqTiPguvKGA1QvT8xr2GdUVGNBRH9Xz4XQzth4Pj0Q01Qow0EzOwTp9uCYf1mvf_dQVSpGnTHL3Srv7gH + Auth=DQAAAMwAAAD6x-FEGLu8C22vipJ5KzJRieLdSnd-bxlIF6iewUK4s-DUIlBl9TXOzWxUby3siw-4fXJ3tHBJ8XUfzqBe5HXc1vMlzuIPmM7yDOXBV2Jdp4c1hqIn08tfgZOkFH0F1WBpS6UqB3xBOyTZWwdT4ULLHi9fnLEjn8hE_FwnSzKf2YxezpuLbuTR6wlJI8xnXTP2s_hZDfRlr-UYS7OTr8G50beHZtGDgbFDAAEPr21TU_VsQmPBSz5frybOZ0MAbYnOi-zrV-ogwk6fIP6fI7EW + http_version: + recorded_at: Thu, 15 Aug 2013 00:43:35 GMT +- request: + method: get + uri: https://spreadsheets.google.com/feeds/worksheets/0AiokXJytm-hjdDhYbTNvZ3pDWm9oZm9yWURLX3ZoR2c/private/full + body: + encoding: US-ASCII + string: '' + headers: + Authorization: + - GoogleLogin auth=DQAAAMwAAADMWltQuejlYd78Px9RfXhcHnb7tlPHfKPY4i69F9Hi0dhIQbyFRlHVcyMKaR3ajpn7yZLj-g3LYQk1SM-i9ejg3r4yH0rj9yZsBcy0ZiJV1L45w4jGXlgrvse68D5axixvDp7T7u6P6K-eOJj2SaKw8vBj156hBEyn4CQFJ0tVUjl5UPAN9Wt8hJmRNqULG3LoxYwLidLgPVjCtL-lF0YnUiSwbolVBzZAbyeYk1QSzX9xT5ms3sTQ4ESz42Bg9SQbc6kdlcWzvmQ_sO5GfrTY + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - '*/*' + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/atom+xml; charset=UTF-8 + Expires: + - Thu, 15 Aug 2013 00:43:35 GMT + Date: + - Thu, 15 Aug 2013 00:43:35 GMT + Cache-Control: + - private, max-age=0, must-revalidate, no-transform + Vary: + - Accept, X-GData-Authorization, GData-Version + Gdata-Version: + - '1.0' + Last-Modified: + - Wed, 14 Aug 2013 23:58:45 GMT + Set-Cookie: + - NID=67=WgYgh5rhvD-JfsREiq1hlwTrGNEKfKnyUBpIGER1YFhlyyhT9BNfI6L1oLVMRz1vqOVUpZxR9HZYItza622-_uOnkfbvdqytSMRP9bHkJhMM-Wk6Y0u1KpKfIaUagmxb;Domain=.google.com;Path=/;Expires=Fri, + 14-Feb-2014 00:43:35 GMT;HttpOnly + P3p: + - CP="This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 + for more info." + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + Server: + - GSE + Transfer-Encoding: + - chunked + body: + encoding: UTF-8 + string: https://spreadsheets.google.com/feeds/worksheets/0AiokXJytm-hjdDhYbTNvZ3pDWm9oZm9yWURLX3ZoR2c/private/full2013-08-14T23:58:45.821ZTestcecillemanalangcecillemanalang@gmail.com11https://spreadsheets.google.com/feeds/worksheets/0AiokXJytm-hjdDhYbTNvZ3pDWm9oZm9yWURLX3ZoR2c/private/full/od62013-08-14T23:58:45.821ZSheet1Sheet110020 + http_version: + recorded_at: Thu, 15 Aug 2013 00:43:36 GMT +recorded_with: VCR 2.5.0 diff --git a/spec/fixtures/vcr_cassettes/google_drive_access_token.yml b/spec/fixtures/vcr_cassettes/google_drive_access_token.yml new file mode 100644 index 0000000..739cf5f --- /dev/null +++ b/spec/fixtures/vcr_cassettes/google_drive_access_token.yml @@ -0,0 +1,73 @@ +--- +http_interactions: +- request: + method: get + uri: https://spreadsheets.google.com/feeds/worksheets/0AiokXJytm-hjdDhYbTNvZ3pDWm9oZm9yWURLX3ZoR2c/private/full + body: + encoding: US-ASCII + string: '' + headers: + Authorization: + - Bearer ya29.AHES6ZR1kGjlmlLJG9skjpO0IjzQ6qDohXwFJclzD7mHI9xa-cFzlg + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - '*/*' + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/atom+xml; charset=UTF-8 + Expires: + - Thu, 15 Aug 2013 04:00:09 GMT + Date: + - Thu, 15 Aug 2013 04:00:09 GMT + Cache-Control: + - private, max-age=0, must-revalidate, no-transform + Vary: + - Accept, X-GData-Authorization, GData-Version + Gdata-Version: + - '1.0' + Last-Modified: + - Wed, 14 Aug 2013 23:58:45 GMT + Set-Cookie: + - NID=67=D_rMebxz1goCYPpOwOoQ0-aPMBQZeyMKudylvS2tIjwbMutBHnzJI57QMteOlIww8SWXXxkrak_-8SQ2RevOOV9ENC4we-6hR0LM_vRnbxPkAAqtkyaWtVgyNbCkAy4k;Domain=.google.com;Path=/;Expires=Fri, + 14-Feb-2014 04:00:09 GMT;HttpOnly + P3p: + - CP="This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 + for more info." + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + Server: + - GSE + Transfer-Encoding: + - chunked + body: + encoding: UTF-8 + string: https://spreadsheets.google.com/feeds/worksheets/0AiokXJytm-hjdDhYbTNvZ3pDWm9oZm9yWURLX3ZoR2c/private/full2013-08-14T23:58:45.821ZTestcecillemanalangcecillemanalang@gmail.com11https://spreadsheets.google.com/feeds/worksheets/0AiokXJytm-hjdDhYbTNvZ3pDWm9oZm9yWURLX3ZoR2c/private/full/od62013-08-14T23:58:45.821ZSheet1Sheet110020 + http_version: + recorded_at: Thu, 15 Aug 2013 04:00:09 GMT +recorded_with: VCR 2.5.0 diff --git a/spec/fixtures/vcr_cassettes/google_drive_set.yml b/spec/fixtures/vcr_cassettes/google_drive_set.yml new file mode 100644 index 0000000..4b1ba16 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/google_drive_set.yml @@ -0,0 +1,857 @@ +--- +http_interactions: +- request: + method: post + uri: https://www.google.com/accounts/ClientLogin + body: + encoding: UTF-8 + string: accountType=HOSTED_OR_GOOGLE&Email=user&Passwd=password&service=wise&source=Gimite-RubyGoogleDrive-1.00 + headers: + Content-Type: + - application/x-www-form-urlencoded + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - '*/*' + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - text/plain + X-Frame-Options: + - DENY + Cache-Control: + - no-cache, no-store + Pragma: + - no-cache + Expires: + - Mon, 01-Jan-1990 00:00:00 GMT + Date: + - Fri, 06 Dec 2013 18:42:35 GMT + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '1095' + Server: + - GSE + Alternate-Protocol: + - 443:quic + body: + encoding: UTF-8 + string: | + SID=DQAAAMoAAAA8IKlqi2aGAAGTzd6pCfMwqwabb79_cvhermJV2M78CNvpiYiujQEkQMienaye4SnKIV-oS6r6KEdGp46SZy5radXnkV5pxGSHLWvExZh7pGH7o3cgmvF8N3WX_FWdGQatg_-ypztq4tgHb_E3wlQtRmT1snh8lqVDIqoaXXdlQJ_WKvgPW8NBAOQBMsnb2fV0FX2abuth0DzS6t9gpR_f-1w8d8jI7rwgBhVg0PxxHPUJMnciPDaEjK3WxLj-zGgPCZfr6vBG8asFAjFzCDYO + LSID=DQAAAMsAAADMWltQuejlYd78Px9RfXhcHnb7tlPHfKPY4i69F9Hi0dhIQbyFRlHVcyMKaR3ajpm39Tx27o5qgddVcti2kZ3CoOB6bthhPlKls7s4G9nz8ObyHSilTTNP5tjNdNNz0--4NP9lacZ-UHhKoDGKnH6lgKFi6BaCAHpQzXo-vsvStxXqo0D1OE81zL2UOYRvN1rc9evr04qtlSvCHQ8THv7eH8SGwZrdf_okjtKQDyLaEJFn5d0_YP-CiM1JLNyNtjwk6E3cWEi8NUrZh459-Lif + Auth=DQAAAMwAAADMWltQuejlYd78Px9RfXhcHnb7tlPHfKPY4i69F9Hi0dhIQbyFRlHVcyMKaR3ajpn7yZLj-g3LYQk1SM-i9ejg3r4yH0rj9yZsBcy0ZiJV1L45w4jGXlgrvse68D5axixvDp7T7u6P6K-eOJj2SaKw8vBj156hBEyn4CQFJ0tVUjl5UPAN9Wt8hJmRNqULG3LoxYwLidLgPVjCtL-lF0YnUiSwbolVBzZAbyeYk1QSzX9xT5ms3sTQ4ESz42Bg9SQbc6kdlcWzvmQ_sO5GfrTY + http_version: + recorded_at: Fri, 06 Dec 2013 18:42:32 GMT +- request: + method: post + uri: https://www.google.com/accounts/ClientLogin + body: + encoding: UTF-8 + string: accountType=HOSTED_OR_GOOGLE&Email=user&Passwd=password&service=writely&source=Gimite-RubyGoogleDrive-1.00 + headers: + Content-Type: + - application/x-www-form-urlencoded + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - '*/*' + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - text/plain + X-Frame-Options: + - DENY + Cache-Control: + - no-cache, no-store + Pragma: + - no-cache + Expires: + - Mon, 01-Jan-1990 00:00:00 GMT + Date: + - Fri, 06 Dec 2013 18:42:35 GMT + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - 1; mode=block + Content-Length: + - '1073' + Server: + - GSE + Alternate-Protocol: + - 443:quic + body: + encoding: UTF-8 + string: | + SID=DQAAAMoAAAA8IKlqi2aGAAGTzd6pCfMwqwabb79_cvhermJV2M78CNvpiYiujQEkQMienaye4SnKIV-oS6r6KEdGp46SZy5radXnkV5pxGSHLWvExZh7pGH7o3cgmvF8N3WX_FWdGQatg_-ypztq4tgHb_E3wlQtRmT1snh8lqVDIqoaXXdlQJ_WKvgPW8NBAOQBMsnb2fV0FX2abuth0DzS6t9gpR_f-1w8d8jI7rwgBhVg0PxxHPUJMnciPDaEjK3WxLj-zGgPCZfr6vBG8asFAjFzCDYO + LSID=DQAAAMsAAADMWltQuejlYd78Px9RfXhcHnb7tlPHfKPY4i69F9Hi0dhIQbyFRlHVcyMKaR3ajpm39Tx27o5qgddVcti2kZ3CoOB6bthhPlKls7s4G9nz8ObyHSilTTNP5tjNdNNz0--4NP9lacZ-UHhKoDGKnH6lgKFi6BaCAHpQzXo-vsvStxXqo0D1OE81zL2UOYRvN1rc9evr04qtlSvCHQ8THv7eH8SGwZrdf_okjtKQDyLaEJFn5d0_YP-CiM1JLNyNtjwk6E3cWEi8NUrZh459-Lif + Auth=DQAAAMwAAADMWltQuejlYd78Px9RfXhcHnb7tlPHfKPY4i69F9Hi0dhIQbyFRlHVcyMKaR3ajpn7yZLj-g3LYQk1SM-i9ejg3r4yH0rj9yZsBcy0ZiJV1L45w4jGXlgrvse68D5axixvDp7T7u6P6K-eOJj2SaKw8vBj156hBEyn4CQFJ0tVUjl5UPAN9Wt8hJmRNqULG3LoxYwLidLgPVjCtL-lF0YnUiSwbolVBzZAbyeYk1QSzX9xT5ms3sTQ4ESz42Bg9SQbc6kdlcWzvmQ_sO5GfrTY + http_version: + recorded_at: Fri, 06 Dec 2013 18:42:32 GMT +- request: + method: get + uri: https://spreadsheets.google.com/feeds/worksheets/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/private/full + body: + encoding: US-ASCII + string: '' + headers: + Authorization: + Authorization: + - GoogleLogin auth=DQAAAMwAAADMWltQuejlYd78Px9RfXhcHnb7tlPHfKPY4i69F9Hi0dhIQbyFRlHVcyMKaR3ajpn7yZLj-g3LYQk1SM-i9ejg3r4yH0rj9yZsBcy0ZiJV1L45w4jGXlgrvse68D5axixvDp7T7u6P6K-eOJj2SaKw8vBj156hBEyn4CQFJ0tVUjl5UPAN9Wt8hJmRNqULG3LoxYwLidLgPVjCtL-lF0YnUiSwbolVBzZAbyeYk1QSzX9xT5ms3sTQ4ESz42Bg9SQbc6kdlcWzvmQ_sO5GfrTY + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - '*/*' + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/atom+xml; charset=UTF-8 + Expires: + - Fri, 06 Dec 2013 18:42:35 GMT + Date: + - Fri, 06 Dec 2013 18:42:35 GMT + Cache-Control: + - private, max-age=0, must-revalidate, no-transform + Vary: + - Accept, X-GData-Authorization, GData-Version + Gdata-Version: + - '1.0' + Last-Modified: + - Fri, 06 Dec 2013 18:42:13 GMT + Set-Cookie: + - NID=67=P6-qngqROR4Rd40ur5alzTcL4Ymf77hX1baonK7-UvwB4TfiXr0KHJipkoLhh9v2fsZJuF__XCss6QXQTYOJrhaalaHkDCjivh162BKtMvOZOQ__hqLgx3jynuNbXPTL;Domain=.google.com;Path=/;Expires=Sat, + 07-Jun-2014 18:42:35 GMT;HttpOnly + P3p: + - CP="This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 + for more info." + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + Server: + - GSE + Alternate-Protocol: + - 443:quic + Transfer-Encoding: + - chunked + body: + encoding: UTF-8 + string: https://spreadsheets.google.com/feeds/worksheets/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/private/full2013-12-06T18:42:13.795ZRoo testpaul.jungwirthpaul.jungwirth@gmail.com11https://spreadsheets.google.com/feeds/worksheets/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/private/full/od62013-12-06T18:42:13.795ZSheet1Sheet110020 + http_version: + recorded_at: Fri, 06 Dec 2013 18:42:33 GMT +- request: + method: get + uri: https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full + body: + encoding: US-ASCII + string: '' + headers: + Authorization: + Authorization: + - GoogleLogin auth=DQAAAMwAAADMWltQuejlYd78Px9RfXhcHnb7tlPHfKPY4i69F9Hi0dhIQbyFRlHVcyMKaR3ajpn7yZLj-g3LYQk1SM-i9ejg3r4yH0rj9yZsBcy0ZiJV1L45w4jGXlgrvse68D5axixvDp7T7u6P6K-eOJj2SaKw8vBj156hBEyn4CQFJ0tVUjl5UPAN9Wt8hJmRNqULG3LoxYwLidLgPVjCtL-lF0YnUiSwbolVBzZAbyeYk1QSzX9xT5ms3sTQ4ESz42Bg9SQbc6kdlcWzvmQ_sO5GfrTY + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - '*/*' + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/atom+xml; charset=UTF-8 + Expires: + - Fri, 06 Dec 2013 18:42:36 GMT + Date: + - Fri, 06 Dec 2013 18:42:36 GMT + Cache-Control: + - private, max-age=0, must-revalidate, no-transform + Vary: + - Accept, X-GData-Authorization, GData-Version + Gdata-Version: + - '1.0' + Last-Modified: + - Fri, 06 Dec 2013 18:42:13 GMT + Set-Cookie: + - NID=67=tZw2vXm2UjFtmkwMXxS9aO0pvNxSWLJpLAQ4exwsBXTAWB9zrS-HMztaLet6prwWCL1Tnb0jfQ2O84S4-Quoc_CZV7H8HgFM8wbXpHiBDzIAEx5MteO1NnCCvkBxWBdb;Domain=.google.com;Path=/;Expires=Sat, + 07-Jun-2014 18:42:36 GMT;HttpOnly + P3p: + - CP="This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 + for more info." + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + Server: + - GSE + Alternate-Protocol: + - 443:quic + Transfer-Encoding: + - chunked + body: + encoding: UTF-8 + string: https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full2013-12-06T18:42:13.795ZSheet1paul.jungwirthpaul.jungwirth@gmail.com4110020https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full/R1C12013-12-06T18:42:13.795ZA11x11x1https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full/R1C22013-12-06T18:42:13.795ZB11x21x2https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full/R2C12013-12-06T18:42:13.795ZA22x12x1https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full/R2C22013-12-06T18:42:13.795ZB22x22x2 + http_version: + recorded_at: Fri, 06 Dec 2013 18:42:33 GMT +- request: + method: get + uri: https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full?max-col=1&max-row=1&min-col=1&min-row=1&return-empty=true + body: + encoding: US-ASCII + string: '' + headers: + Authorization: + Authorization: + - GoogleLogin auth=DQAAAMwAAADMWltQuejlYd78Px9RfXhcHnb7tlPHfKPY4i69F9Hi0dhIQbyFRlHVcyMKaR3ajpn7yZLj-g3LYQk1SM-i9ejg3r4yH0rj9yZsBcy0ZiJV1L45w4jGXlgrvse68D5axixvDp7T7u6P6K-eOJj2SaKw8vBj156hBEyn4CQFJ0tVUjl5UPAN9Wt8hJmRNqULG3LoxYwLidLgPVjCtL-lF0YnUiSwbolVBzZAbyeYk1QSzX9xT5ms3sTQ4ESz42Bg9SQbc6kdlcWzvmQ_sO5GfrTY + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - '*/*' + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/atom+xml; charset=UTF-8 + Expires: + - Fri, 06 Dec 2013 18:42:36 GMT + Date: + - Fri, 06 Dec 2013 18:42:36 GMT + Cache-Control: + - private, max-age=0, must-revalidate, no-transform + Vary: + - Accept, X-GData-Authorization, GData-Version + Gdata-Version: + - '1.0' + Last-Modified: + - Fri, 06 Dec 2013 18:42:13 GMT + Set-Cookie: + - NID=67=daYpj77OMuRnSTCPbAE3O_WkWmcaH_CUTFTOfwSJmZCFCrAxhYtgPM0H6MK9HJaq21e3EPg0uvngJ94R_3QgYkCSgpC5tvmWHPpI4jraUD9K5TPt3O4KUfCfLMbJhG9z;Domain=.google.com;Path=/;Expires=Sat, + 07-Jun-2014 18:42:36 GMT;HttpOnly + P3p: + - CP="This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 + for more info." + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + Server: + - GSE + Alternate-Protocol: + - 443:quic + Transfer-Encoding: + - chunked + body: + encoding: UTF-8 + string: https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full2013-12-06T18:42:13.795ZSheet1paul.jungwirthpaul.jungwirth@gmail.com1110020https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full/R1C12013-12-06T18:42:13.795ZA11x11x1 + http_version: + recorded_at: Fri, 06 Dec 2013 18:42:33 GMT +- request: + method: post + uri: https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full/batch + body: + encoding: UTF-8 + string: |2 + + https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full + + 1,1 + + https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full/R1C1 + + + + + headers: + Authorization: + Authorization: + - GoogleLogin auth=DQAAAMwAAADMWltQuejlYd78Px9RfXhcHnb7tlPHfKPY4i69F9Hi0dhIQbyFRlHVcyMKaR3ajpn7yZLj-g3LYQk1SM-i9ejg3r4yH0rj9yZsBcy0ZiJV1L45w4jGXlgrvse68D5axixvDp7T7u6P6K-eOJj2SaKw8vBj156hBEyn4CQFJ0tVUjl5UPAN9Wt8hJmRNqULG3LoxYwLidLgPVjCtL-lF0YnUiSwbolVBzZAbyeYk1QSzX9xT5ms3sTQ4ESz42Bg9SQbc6kdlcWzvmQ_sO5GfrTY + Content-Type: + - application/atom+xml + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - '*/*' + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/atom+xml; charset=UTF-8 + Gdata-Version: + - '1.0' + Set-Cookie: + - NID=67=wQmh2rA0psG9Dw1Q5cz3waZRudK84WUs7qtSv2Y_ROVwI0U5uKu0S9AcWRO9rHVjjfxmb4F8S0YYLuh0SIPeDbWU25qHG0gwEsCyGEkV0eWewcz6qeT2vGQp3L6A8cBw;Domain=.google.com;Path=/;Expires=Sat, + 07-Jun-2014 18:42:36 GMT;HttpOnly + P3p: + - CP="This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 + for more info." + Date: + - Fri, 06 Dec 2013 18:42:36 GMT + Expires: + - Fri, 06 Dec 2013 18:42:36 GMT + Cache-Control: + - private, max-age=0 + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + Server: + - GSE + Alternate-Protocol: + - 443:quic + Transfer-Encoding: + - chunked + body: + encoding: UTF-8 + string: https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full/batch/13863553565442013-12-06T18:42:36.555ZBatch Feedhttps://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full/R1C12013-12-06T18:42:36.550ZA11x11x11,1 + http_version: + recorded_at: Fri, 06 Dec 2013 18:42:33 GMT +- request: + method: get + uri: https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full?max-col=2&max-row=1&min-col=2&min-row=1&return-empty=true + body: + encoding: US-ASCII + string: '' + headers: + Authorization: + Authorization: + - GoogleLogin auth=DQAAAMwAAADMWltQuejlYd78Px9RfXhcHnb7tlPHfKPY4i69F9Hi0dhIQbyFRlHVcyMKaR3ajpn7yZLj-g3LYQk1SM-i9ejg3r4yH0rj9yZsBcy0ZiJV1L45w4jGXlgrvse68D5axixvDp7T7u6P6K-eOJj2SaKw8vBj156hBEyn4CQFJ0tVUjl5UPAN9Wt8hJmRNqULG3LoxYwLidLgPVjCtL-lF0YnUiSwbolVBzZAbyeYk1QSzX9xT5ms3sTQ4ESz42Bg9SQbc6kdlcWzvmQ_sO5GfrTY + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - '*/*' + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/atom+xml; charset=UTF-8 + Expires: + - Fri, 06 Dec 2013 18:42:36 GMT + Date: + - Fri, 06 Dec 2013 18:42:36 GMT + Cache-Control: + - private, max-age=0, must-revalidate, no-transform + Vary: + - Accept, X-GData-Authorization, GData-Version + Gdata-Version: + - '1.0' + Last-Modified: + - Fri, 06 Dec 2013 18:42:36 GMT + Set-Cookie: + - NID=67=hhR3BKtLhLtG5S2t0nQaY4JGPepDUM1oEg9hVFPsovK6AmMJUZT2qFNPlAPMQh3hNeekREIDFd8mJrRKbQObDz1j1cSgeaEXQfqG5kojHxLDhIi8vppQ4CSYiprjxa_p;Domain=.google.com;Path=/;Expires=Sat, + 07-Jun-2014 18:42:36 GMT;HttpOnly + P3p: + - CP="This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 + for more info." + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + Server: + - GSE + Alternate-Protocol: + - 443:quic + Transfer-Encoding: + - chunked + body: + encoding: UTF-8 + string: https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full2013-12-06T18:42:36.550ZSheet1paul.jungwirthpaul.jungwirth@gmail.com1110020https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full/R1C22013-12-06T18:42:36.550ZB11x21x2 + http_version: + recorded_at: Fri, 06 Dec 2013 18:42:34 GMT +- request: + method: post + uri: https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full/batch + body: + encoding: UTF-8 + string: |2 + + https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full + + 1,2 + + https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full/R1C2 + + + + + headers: + Authorization: + Authorization: + - GoogleLogin auth=DQAAAMwAAADMWltQuejlYd78Px9RfXhcHnb7tlPHfKPY4i69F9Hi0dhIQbyFRlHVcyMKaR3ajpn7yZLj-g3LYQk1SM-i9ejg3r4yH0rj9yZsBcy0ZiJV1L45w4jGXlgrvse68D5axixvDp7T7u6P6K-eOJj2SaKw8vBj156hBEyn4CQFJ0tVUjl5UPAN9Wt8hJmRNqULG3LoxYwLidLgPVjCtL-lF0YnUiSwbolVBzZAbyeYk1QSzX9xT5ms3sTQ4ESz42Bg9SQbc6kdlcWzvmQ_sO5GfrTY + Content-Type: + - application/atom+xml + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - '*/*' + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/atom+xml; charset=UTF-8 + Gdata-Version: + - '1.0' + Set-Cookie: + - NID=67=WJlvr-zjLEBTHM3AILcNGXJCtQU7Ws80r_fjKRTUlZu7Thu-BXXbTT-uPjMuwwlh4TB5RBo26S6SsFmR6roLsMqKYIECSGxbxul99InG1vOqjS4Ee7f3t46uZ-ypq-Ge;Domain=.google.com;Path=/;Expires=Sat, + 07-Jun-2014 18:42:37 GMT;HttpOnly + P3p: + - CP="This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 + for more info." + Date: + - Fri, 06 Dec 2013 18:42:37 GMT + Expires: + - Fri, 06 Dec 2013 18:42:37 GMT + Cache-Control: + - private, max-age=0 + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + Server: + - GSE + Alternate-Protocol: + - 443:quic + Transfer-Encoding: + - chunked + body: + encoding: UTF-8 + string: https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full/batch/13863553571702013-12-06T18:42:37.181ZBatch Feedhttps://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full/R1C22013-12-06T18:42:37.175ZB11x21x21,2 + http_version: + recorded_at: Fri, 06 Dec 2013 18:42:34 GMT +- request: + method: get + uri: https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full?max-col=1&max-row=2&min-col=1&min-row=2&return-empty=true + body: + encoding: US-ASCII + string: '' + headers: + Authorization: + Authorization: + - GoogleLogin auth=DQAAAMwAAADMWltQuejlYd78Px9RfXhcHnb7tlPHfKPY4i69F9Hi0dhIQbyFRlHVcyMKaR3ajpn7yZLj-g3LYQk1SM-i9ejg3r4yH0rj9yZsBcy0ZiJV1L45w4jGXlgrvse68D5axixvDp7T7u6P6K-eOJj2SaKw8vBj156hBEyn4CQFJ0tVUjl5UPAN9Wt8hJmRNqULG3LoxYwLidLgPVjCtL-lF0YnUiSwbolVBzZAbyeYk1QSzX9xT5ms3sTQ4ESz42Bg9SQbc6kdlcWzvmQ_sO5GfrTY + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - '*/*' + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/atom+xml; charset=UTF-8 + Expires: + - Fri, 06 Dec 2013 18:42:37 GMT + Date: + - Fri, 06 Dec 2013 18:42:37 GMT + Cache-Control: + - private, max-age=0, must-revalidate, no-transform + Vary: + - Accept, X-GData-Authorization, GData-Version + Gdata-Version: + - '1.0' + Last-Modified: + - Fri, 06 Dec 2013 18:42:37 GMT + Set-Cookie: + - NID=67=qlpkP4soWbj82eIRnnuyRBgS2Dhtnme752d7DANDieb5DLamkoMJ2l6DeLbIpgqK2Li1Qd-Ere-TGYfc0D9p2i-JnezagCE1Hc_YzPX9Ln2zsSVSjMLMP6f_sRowsHSJ;Domain=.google.com;Path=/;Expires=Sat, + 07-Jun-2014 18:42:37 GMT;HttpOnly + P3p: + - CP="This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 + for more info." + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + Server: + - GSE + Alternate-Protocol: + - 443:quic + Transfer-Encoding: + - chunked + body: + encoding: UTF-8 + string: https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full2013-12-06T18:42:37.175ZSheet1paul.jungwirthpaul.jungwirth@gmail.com1110020https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full/R2C12013-12-06T18:42:37.175ZA22x12x1 + http_version: + recorded_at: Fri, 06 Dec 2013 18:42:34 GMT +- request: + method: post + uri: https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full/batch + body: + encoding: UTF-8 + string: |2 + + https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full + + 2,1 + + https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full/R2C1 + + + + + headers: + Authorization: + Authorization: + - GoogleLogin auth=DQAAAMwAAADMWltQuejlYd78Px9RfXhcHnb7tlPHfKPY4i69F9Hi0dhIQbyFRlHVcyMKaR3ajpn7yZLj-g3LYQk1SM-i9ejg3r4yH0rj9yZsBcy0ZiJV1L45w4jGXlgrvse68D5axixvDp7T7u6P6K-eOJj2SaKw8vBj156hBEyn4CQFJ0tVUjl5UPAN9Wt8hJmRNqULG3LoxYwLidLgPVjCtL-lF0YnUiSwbolVBzZAbyeYk1QSzX9xT5ms3sTQ4ESz42Bg9SQbc6kdlcWzvmQ_sO5GfrTY + Content-Type: + - application/atom+xml + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - '*/*' + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/atom+xml; charset=UTF-8 + Gdata-Version: + - '1.0' + Set-Cookie: + - NID=67=glsIXLsUxvEjIZeV_caboBdJfweLOgsi15nO8M-4es2Wu32kx35phIfTTDp9ujhK_HyC8n1AeREHBwh3IH1Nmq4MovOypQI3q1XdTPWvPC7Q-3WfiUFQ-YljhIrbI8KE;Domain=.google.com;Path=/;Expires=Sat, + 07-Jun-2014 18:42:38 GMT;HttpOnly + P3p: + - CP="This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 + for more info." + Date: + - Fri, 06 Dec 2013 18:42:38 GMT + Expires: + - Fri, 06 Dec 2013 18:42:38 GMT + Cache-Control: + - private, max-age=0 + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + Server: + - GSE + Alternate-Protocol: + - 443:quic + Transfer-Encoding: + - chunked + body: + encoding: UTF-8 + string: https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full/batch/13863553583392013-12-06T18:42:38.351ZBatch Feedhttps://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full/R2C12013-12-06T18:42:38.344ZA22x12x12,1 + http_version: + recorded_at: Fri, 06 Dec 2013 18:42:35 GMT +- request: + method: get + uri: https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full?max-col=2&max-row=2&min-col=2&min-row=2&return-empty=true + body: + encoding: US-ASCII + string: '' + headers: + Authorization: + Authorization: + - GoogleLogin auth=DQAAAMwAAADMWltQuejlYd78Px9RfXhcHnb7tlPHfKPY4i69F9Hi0dhIQbyFRlHVcyMKaR3ajpn7yZLj-g3LYQk1SM-i9ejg3r4yH0rj9yZsBcy0ZiJV1L45w4jGXlgrvse68D5axixvDp7T7u6P6K-eOJj2SaKw8vBj156hBEyn4CQFJ0tVUjl5UPAN9Wt8hJmRNqULG3LoxYwLidLgPVjCtL-lF0YnUiSwbolVBzZAbyeYk1QSzX9xT5ms3sTQ4ESz42Bg9SQbc6kdlcWzvmQ_sO5GfrTY + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - '*/*' + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/atom+xml; charset=UTF-8 + Expires: + - Fri, 06 Dec 2013 18:42:40 GMT + Date: + - Fri, 06 Dec 2013 18:42:40 GMT + Cache-Control: + - private, max-age=0, must-revalidate, no-transform + Vary: + - Accept, X-GData-Authorization, GData-Version + Gdata-Version: + - '1.0' + Last-Modified: + - Fri, 06 Dec 2013 18:42:38 GMT + Set-Cookie: + - NID=67=cQbD3pRJf1bzd_ftYzzrk1sCcdgkDT-b4GGscg8WBm-bIuyOYxIZL86VrMvC0wDSAjQeKiaH65AVd2Q_Ve5YxvWinnnZdg30pktLVmFxwHFkJ-pVnk0xtjyoM_QHg219;Domain=.google.com;Path=/;Expires=Sat, + 07-Jun-2014 18:42:40 GMT;HttpOnly + P3p: + - CP="This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 + for more info." + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + Server: + - GSE + Alternate-Protocol: + - 443:quic + Transfer-Encoding: + - chunked + body: + encoding: UTF-8 + string: https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full2013-12-06T18:42:38.344ZSheet1paul.jungwirthpaul.jungwirth@gmail.com1110020https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full/R2C22013-12-06T18:42:38.344ZB22x22x2 + http_version: + recorded_at: Fri, 06 Dec 2013 18:42:37 GMT +- request: + method: post + uri: https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full/batch + body: + encoding: UTF-8 + string: |2 + + https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full + + 2,2 + + https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full/R2C2 + + + + + headers: + Authorization: + - GoogleLogin auth=DQAAAMwAAADMWltQuejlYd78Px9RfXhcHnb7tlPHfKPY4i69F9Hi0dhIQbyFRlHVcyMKaR3ajpn7yZLj-g3LYQk1SM-i9ejg3r4yH0rj9yZsBcy0ZiJV1L45w4jGXlgrvse68D5axixvDp7T7u6P6K-eOJj2SaKw8vBj156hBEyn4CQFJ0tVUjl5UPAN9Wt8hJmRNqULG3LoxYwLidLgPVjCtL-lF0YnUiSwbolVBzZAbyeYk1QSzX9xT5ms3sTQ4ESz42Bg9SQbc6kdlcWzvmQ_sO5GfrTY + Content-Type: + - application/atom+xml + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - '*/*' + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/atom+xml; charset=UTF-8 + Gdata-Version: + - '1.0' + Set-Cookie: + - NID=67=O0n3ybyFFr3VP3s97FT61XHlZhk4M01SSuzeiYHZIy0xktykBbJeWQwthVsIRXZsU41IoB59PhzsYpjGc88JTzvOKlSeNHNahUXdz-Q3XUG26k7j3OJJTJMfCPt-hn1d;Domain=.google.com;Path=/;Expires=Sat, + 07-Jun-2014 18:42:42 GMT;HttpOnly + P3p: + - CP="This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 + for more info." + Date: + - Fri, 06 Dec 2013 18:42:42 GMT + Expires: + - Fri, 06 Dec 2013 18:42:42 GMT + Cache-Control: + - private, max-age=0 + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + Server: + - GSE + Alternate-Protocol: + - 443:quic + Transfer-Encoding: + - chunked + body: + encoding: UTF-8 + string: https://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full/batch/13863553624672013-12-06T18:42:42.478ZBatch Feedhttps://spreadsheets.google.com/feeds/cells/0AiVSev9-0p-PdEVrQldEY1I4dDJjVlpEQUkwblprcnc/od6/private/full/R2C22013-12-06T18:42:42.472ZB22x22x22,2 + http_version: + recorded_at: Fri, 06 Dec 2013 18:42:39 GMT +recorded_with: VCR 2.5.0 diff --git a/spec/helpers.rb b/spec/helpers.rb new file mode 100644 index 0000000..f140659 --- /dev/null +++ b/spec/helpers.rb @@ -0,0 +1,5 @@ +module Helpers + def yaml_entry(row,col,type,value) + "cell_#{row}_#{col}: \n row: #{row} \n col: #{col} \n celltype: #{type} \n value: #{value} \n" + end +end diff --git a/spec/lib/roo/base_spec.rb b/spec/lib/roo/base_spec.rb new file mode 100644 index 0000000..d00025d --- /dev/null +++ b/spec/lib/roo/base_spec.rb @@ -0,0 +1,233 @@ +require 'spec_helper' + +describe Roo::Base do + let(:klass) do + Class.new(Roo::Base) do + def initialize(filename, data = {}) + super(filename) + @data ||= data + end + + def read_cells(sheet = default_sheet) + return if @cells_read[sheet] + type_map = { String => :string, Date => :date, Numeric => :float } + + @cell[sheet] = @data + @cell_type[sheet] = Hash[@data.map { |k, v| [k, type_map.find {|type,_| v.is_a?(type) }.last ] }] + @first_row[sheet] = @data.map { |k, _| k[0] }.min + @last_row[sheet] = @data.map { |k, _| k[0] }.max + @first_column[sheet] = @data.map { |k, _| k[1] }.min + @last_column[sheet] = @data.map { |k, _| k[1] }.max + @cells_read[sheet] = true + end + + def cell(row, col, sheet = nil) + sheet ||= default_sheet + read_cells(sheet) + @cell[sheet][[row, col]] + end + + def celltype(row, col, sheet = nil) + sheet ||= default_sheet + read_cells(sheet) + @cell_type[sheet][[row, col]] + end + + def sheets + ['my_sheet', 'blank sheet'] + end + end + end + + let(:spreadsheet_data) do + { + [3, 1] => 'Header', + + [5, 1] => Date.civil(1961, 11, 21), + + [8, 3] => 'thisisc8', + [8, 7] => 'thisisg8', + + [12, 1] => 41.0, + [12, 2] => 42.0, + [12, 3] => 43.0, + [12, 4] => 44.0, + [12, 5] => 45.0, + + [15, 3] => 43.0, + [15, 4] => 44.0, + [15, 5] => 45.0, + + [16, 2] => '"Hello world!"', + [16, 3] => 'forty-three', + [16, 4] => 'forty-four', + [16, 5] => 'forty-five' + } + end + + let(:spreadsheet) { klass.new('some_file', spreadsheet_data) } + + describe '#uri?' do + it 'should return true when passed a filename starting with http(s)://' do + expect(spreadsheet.send(:uri?, 'http://example.com/')).to be_truthy + expect(spreadsheet.send(:uri?, 'https://example.com/')).to be_truthy + end + + it 'should return false when passed a filename which does not start with http(s)://' do + expect(spreadsheet.send(:uri?, 'example.com')).to be_falsy + end + + it 'should return false when passed non-String object such as Tempfile' do + expect(spreadsheet.send(:uri?, Tempfile.new('test'))).to be_falsy + end + end + + describe '#set' do + it 'should not update cell when setting an invalid type' do + spreadsheet.set(1, 1, 1) + expect { spreadsheet.set(1, 1, :invalid_type) }.to raise_error(ArgumentError) + expect(spreadsheet.cell(1, 1)).to eq(1) + expect(spreadsheet.celltype(1, 1)).to eq(:float) + end + end + + describe '#first_row' do + it 'should return the first row' do + expect(spreadsheet.first_row).to eq(3) + end + end + + describe '#last_row' do + it 'should return the last row' do + expect(spreadsheet.last_row).to eq(16) + end + end + + describe '#first_column' do + it 'should return the first column' do + expect(spreadsheet.first_column).to eq(1) + end + end + + describe '#first_column_as_letter' do + it 'should return the first column as a letter' do + expect(spreadsheet.first_column_as_letter).to eq('A') + end + end + + describe '#last_column' do + it 'should return the last column' do + expect(spreadsheet.last_column).to eq(7) + end + end + + describe '#last_column_as_letter' do + it 'should return the last column as a letter' do + expect(spreadsheet.last_column_as_letter).to eq('G') + end + end + + describe '#row' do + it 'should return the specified row' do + expect(spreadsheet.row(12)).to eq([41.0, 42.0, 43.0, 44.0, 45.0, nil, nil]) + expect(spreadsheet.row(16)).to eq([nil, '"Hello world!"', 'forty-three', 'forty-four', 'forty-five', nil, nil]) + end + end + + describe '#row_with' do + context 'with a matching header row' do + it 'returns the row number' do + expect(spreadsheet.row_with([/Header/])). to eq 3 + end + end + + context 'without a matching header row' do + it 'raises an error' do + expect { spreadsheet.row_with([/Missing Header/]) }.to \ + raise_error(Roo::HeaderRowNotFoundError) + end + end + end + + describe '#empty?' do + it 'should return true when empty' do + expect(spreadsheet.empty?(1, 1)).to be_truthy + expect(spreadsheet.empty?(8, 3)).to be_falsy + expect(spreadsheet.empty?('A', 11)).to be_truthy + expect(spreadsheet.empty?('A', 12)).to be_falsy + end + end + + describe '#reload' do + it 'should return reinitialize the spreadsheet' do + spreadsheet.reload + expect(spreadsheet.instance_variable_get(:@cell).empty?).to be_truthy + end + end + + describe '#each' do + it 'should return an enumerator with all the rows' do + each = spreadsheet.each + expect(each).to be_a(Enumerator) + expect(each.to_a.last).to eq([nil, '"Hello world!"', 'forty-three', 'forty-four', 'forty-five', nil, nil]) + end + end + + describe '#to_yaml' do + it 'should convert the spreadsheet to yaml' do + expect(spreadsheet.to_yaml({}, 5, 1, 5, 1)).to eq("--- \n" + yaml_entry(5, 1, 'date', '1961-11-21')) + expect(spreadsheet.to_yaml({}, 8, 3, 8, 3)).to eq("--- \n" + yaml_entry(8, 3, 'string', 'thisisc8')) + + expect(spreadsheet.to_yaml({}, 12, 3, 12, 3)).to eq("--- \n" + yaml_entry(12, 3, 'float', 43.0)) + + expect(spreadsheet.to_yaml({}, 12, 3, 12)).to eq( + "--- \n" + yaml_entry(12, 3, 'float', 43.0) + + yaml_entry(12, 4, 'float', 44.0) + + yaml_entry(12, 5, 'float', 45.0)) + + expect(spreadsheet.to_yaml({}, 12, 3)).to eq( + "--- \n" + yaml_entry(12, 3, 'float', 43.0) + + yaml_entry(12, 4, 'float', 44.0) + + yaml_entry(12, 5, 'float', 45.0) + + yaml_entry(15, 3, 'float', 43.0) + + yaml_entry(15, 4, 'float', 44.0) + + yaml_entry(15, 5, 'float', 45.0) + + yaml_entry(16, 3, 'string', 'forty-three') + + yaml_entry(16, 4, 'string', 'forty-four') + + yaml_entry(16, 5, 'string', 'forty-five')) + end + end + + let(:expected_csv) do + < :float, + '0' => :float, + '0.00' => :float, + '#,##0' => :float, + '#,##0.00' => :float, + '0%' => :percentage, + '0.00%' => :percentage, + '0.00E+00' => :float, + '# ?/?' => :float, # ??? TODO: + '# ??/??' => :float, # ??? TODO: + 'mm-dd-yy' => :date, + 'd-mmm-yy' => :date, + 'd-mmm' => :date, + 'mmm-yy' => :date, + 'h:mm AM/PM' => :date, + 'h:mm:ss AM/PM' => :date, + 'h:mm' => :time, + 'h:mm:ss' => :time, + 'm/d/yy h:mm' => :datetime, + '#,##0 ;(#,##0)' => :float, + '#,##0 ;[Red](#,##0)' => :float, + '#,##0.00;(#,##0.00)' => :float, + '#,##0.00;[Red](#,##0.00)' => :float, + '#,##0_);[Red](#,##0)' => :float, + 'mm:ss' => :time, + '[h]:mm:ss' => :time, + 'mmss.0' => :time, + '##0.0E+0' => :float, + '@' => :float, + #-- zusaetzliche Formate, die nicht standardmaessig definiert sind: + 'yyyy\\-mm\\-dd' => :date, + 'dd/mm/yy' => :date, + 'hh:mm:ss' => :time, + 'dd/mm/yy\\ hh:mm' => :datetime, + 'dd/mmm/yy\\ hh:mm' => :datetime, + 'dd/mmm/yy' => :date, # 2011-05-21 + 'yyyy-mm-dd' => :date, # 2011-09-16 + 'yyyy-mm-dd;@' => :date, + '#0_);[Red]\(0\)' => :float + }.each do |format, type| + it "translates #{format} to #{type}" do + expect(Roo::Excelx::Format.to_type(format)).to eq(type) + end + end + end +end diff --git a/spec/lib/roo/excelx_spec.rb b/spec/lib/roo/excelx_spec.rb new file mode 100755 index 0000000..0ef0f19 --- /dev/null +++ b/spec/lib/roo/excelx_spec.rb @@ -0,0 +1,537 @@ +# encoding: utf-8 +require 'spec_helper' + +describe Roo::Excelx do + subject(:xlsx) do + Roo::Excelx.new(path) + end + + describe 'Constants' do + describe 'ERROR_VALUES' do + it 'returns all possible errorr values' do + expect(described_class::ERROR_VALUES).to eq(%w(#N/A #REF! #NAME? #DIV/0! #NULL! #VALUE! #NUM!).to_set) + end + + it 'is a set' do + expect(described_class::ERROR_VALUES).to be_an_instance_of(Set) + end + end + end + + describe '.new' do + let(:path) { 'test/files/numeric-link.xlsx' } + + it 'creates an instance' do + expect(subject).to be_a(Roo::Excelx) + end + + context 'given a file with missing rels' do + let(:path) { 'test/files/file_item_error.xlsx' } + + it 'creates an instance' do + expect(subject).to be_a(Roo::Excelx) + end + end + + context 'with more cells than specified max' do + let(:path) { 'test/files/only_one_sheet.xlsx' } + + it 'raises an appropriate error' do + expect { Roo::Excelx.new(path, cell_max: 1) }.to raise_error(Roo::Excelx::ExceedsMaxError) + end + end + + context 'with fewer cells than specified max' do + let(:path) { 'test/files/only_one_sheet.xlsx' } + + it 'creates an instance' do + expect(Roo::Excelx.new(path, cell_max: 100)).to be_a(Roo::Excelx) + end + end + + context 'file path is a Pathname' do + let(:path) { Pathname.new('test/files/file_item_error.xlsx') } + + it 'creates an instance' do + expect(subject).to be_a(Roo::Excelx) + end + end + end + + describe '#cell' do + context 'for a link cell' do + context 'with numeric contents' do + let(:path) { 'test/files/numeric-link.xlsx' } + + subject do + xlsx.cell('A', 1) + end + + it 'returns a link with the number as a string value' do + expect(subject).to be_a(Roo::Link) + # FIXME: Because Link inherits from String, it is a String, + # But in theory, it shouldn't have to be a String. + # NOTE: This test is broken becase Cell::Numeric formats numbers + # more intelligently. + # expect(subject).to eq('8675309.0') + end + end + end + + context 'for a non-existent cell' do + let(:path) { 'test/files/numeric-link.xlsx' } + it 'return nil' do + expect(xlsx.cell('AAA', 999)).to eq nil + end + end + end + + describe '#parse' do + let(:path) { 'test/files/numeric-link.xlsx' } + + context 'with a columns hash' do + context 'when not present in the sheet' do + it 'does not raise' do + expect do + xlsx.sheet(0).parse( + this: 'This', + that: 'That' + ) + end.to raise_error(Roo::HeaderRowNotFoundError) + end + end + end + end + + describe '#parse_with_clean_option' do + let(:path) { 'test/files/parse_with_clean_option.xlsx' } + let(:options) { {clean: true} } + + context 'with clean: true' do + + it 'does not raise' do + expect do + xlsx.parse(options) + end.not_to raise_error + end + end + end + + describe '#parse_unicode_with_clean_option' do + let(:path) { 'test/files/parse_clean_with_unicode.xlsx' } + let(:options) { {clean: true, name: 'Name'} } + + context 'with clean: true' do + it 'returns a non empty string' do + expect(xlsx.parse(options).last[:name]).to eql('凯') + end + end + end + + describe '#sheets' do + let(:path) { 'test/files/numbers1.xlsx' } + + it 'returns the expected result' do + expect(subject.sheets).to eq ["Tabelle1", "Name of Sheet 2", "Sheet3", "Sheet4", "Sheet5"] + end + + describe 'only showing visible sheets' do + let(:path) { 'test/files/hidden_sheets.xlsx' } + + it 'returns the expected result' do + expect(Roo::Excelx.new(path, only_visible_sheets: true).sheets).to eq ["VisibleSheet1"] + end + end + end + + describe '#sheet_for' do + let(:path) { 'test/files/numbers1.xlsx' } + + # This is kinda gross + it 'returns the expected result' do + expect(subject.sheet_for("Tabelle1").instance_variable_get("@name")).to eq "Tabelle1" + end + end + + describe '#row' do + let(:path) { 'test/files/numbers1.xlsx' } + + it 'returns the expected result' do + expect(subject.row(1, "Sheet5")).to eq [1.0, 5.0, 5.0, nil, nil] + end + end + + describe '#column' do + let(:path) { 'test/files/numbers1.xlsx' } + + it 'returns the expected result' do + expect(subject.column(1, "Sheet5")).to eq [1.0, 2.0, 3.0, Date.new(2007,11,21), 42.0, "ABC"] + end + end + + describe '#first_row' do + let(:path) { 'test/files/numbers1.xlsx' } + + it 'returns the expected result' do + expect(subject.first_row("Sheet5")).to eq 1 + end + end + + describe '#last_row' do + let(:path) { 'test/files/numbers1.xlsx' } + + it 'returns the expected result' do + expect(subject.last_row("Sheet5")).to eq 6 + end + end + + describe '#first_column' do + let(:path) { 'test/files/numbers1.xlsx' } + + it 'returns the expected result' do + expect(subject.first_column("Sheet5")).to eq 1 + end + end + + describe '#last_column' do + let(:path) { 'test/files/numbers1.xlsx' } + + it 'returns the expected result' do + expect(subject.last_column("Sheet5")).to eq 5 + end + end + + describe '#set' do + before do + subject.set(1, 2, "Foo", "Sheet5") + end + + let(:path) { 'test/files/numbers1.xlsx' } + let(:cell) { subject.cell(1, 2, "Sheet5") } + + it 'returns the expected result' do + expect(cell).to eq "Foo" + end + end + + describe '#formula' do + let(:path) { 'test/files/formula.xlsx' } + + it 'returns the expected result' do + expect(subject.formula(1, 1, "Sheet1")).to eq nil + expect(subject.formula(7, 2, "Sheet1")).to eq "SUM($A$1:B6)" + expect(subject.formula(1000, 2000, "Sheet1")).to eq nil + end + end + + describe '#formula?' do + let(:path) { 'test/files/formula.xlsx' } + + it 'returns the expected result' do + expect(subject.formula?(1, 1, "Sheet1")).to eq false + expect(subject.formula?(7, 2, "Sheet1")).to eq true + expect(subject.formula?(1000, 2000, "Sheet1")).to eq false + end + end + + describe '#formulas' do + let(:path) { 'test/files/formula.xlsx' } + + it 'returns the expected result' do + expect(subject.formulas("Sheet1")).to eq [[7, 1, "SUM(A1:A6)"], [7, 2, "SUM($A$1:B6)"]] + end + end + + describe '#font' do + let(:path) { 'test/files/style.xlsx' } + + it 'returns the expected result' do + expect(subject.font(1, 1).bold?).to eq true + expect(subject.font(1, 1).italic?).to eq false + expect(subject.font(1, 1).underline?).to eq false + + expect(subject.font(7, 1).bold?).to eq false + expect(subject.font(7, 1).italic?).to eq true + expect(subject.font(7, 1).underline?).to eq true + expect(subject.font(1000, 2000)).to eq nil + end + end + + describe '#celltype' do + let(:path) { 'test/files/numbers1.xlsx' } + + it 'returns the expected result' do + expect(subject.celltype(1, 1, "Sheet4")).to eq :date + expect(subject.celltype(1, 2, "Sheet4")).to eq :float + expect(subject.celltype(6, 2, "Sheet5")).to eq :string + expect(subject.celltype(1000, 2000, "Sheet5")).to eq nil + end + end + + describe '#excelx_type' do + let(:path) { 'test/files/numbers1.xlsx' } + + it 'returns the expected result' do + expect(subject.excelx_type(1, 1, "Sheet5")).to eq [:numeric_or_formula, "General"] + expect(subject.excelx_type(6, 2, "Sheet5")).to eq :string + expect(subject.excelx_type(1000, 2000, "Sheet5")).to eq nil + end + end + + # FIXME: IMO, these tests don't provide much value. Under what circumstances + # will a user require the "index" value for the shared strings table? + # Excel value should be the raw unformatted value for the cell. + describe '#excelx_value' do + let(:path) { 'test/files/numbers1.xlsx' } + + it 'returns the expected result' do + # These values are the index in the shared strings table, might be a better + # way to get these rather than hardcoding. + + # expect(subject.excelx_value(1, 1, "Sheet5")).to eq "1" # passes by accident + # expect(subject.excelx_value(6, 2, "Sheet5")).to eq "16" + # expect(subject.excelx_value(6000, 2000, "Sheet5")).to eq nil + end + end + + describe '#formatted_value' do + context 'contains zero-padded numbers' do + let(:path) { 'test/files/zero-padded-number.xlsx' } + + it 'returns a zero-padded number' do + expect(subject.formatted_value(4, 1)).to eq '05010' + end + end + end + + describe '#excelx_format' do + let(:path) { 'test/files/style.xlsx' } + + it 'returns the expected result' do + # These are the index of the style for a given document + # might be more reliable way to get this info. + expect(subject.excelx_format(1, 1)).to eq "General" + expect(subject.excelx_format(2, 2)).to eq "0.00" + expect(subject.excelx_format(5000, 1000)).to eq nil + end + end + + describe '#empty?' do + let(:path) { 'test/files/style.xlsx' } + + it 'returns the expected result' do + # These are the index of the style for a given document + # might be more reliable way to get this info. + expect(subject.empty?(1, 1)).to eq false + expect(subject.empty?(13, 1)).to eq true + end + end + + describe '#label' do + let(:path) { 'test/files/named_cells.xlsx' } + + it 'returns the expected result' do + expect(subject.label("berta")).to eq [4, 2, "Sheet1"] + expect(subject.label("dave")).to eq [nil, nil, nil] + end + end + + describe '#labels' do + let(:path) { 'test/files/named_cells.xlsx' } + + it 'returns the expected result' do + expect(subject.labels).to eq [["anton", [5, 3, "Sheet1"]], ["berta", [4, 2, "Sheet1"]], ["caesar", [7, 2, "Sheet1"]]] + end + end + + describe '#hyperlink?' do + let(:path) { 'test/files/link.xlsx' } + + it 'returns the expected result' do + expect(subject.hyperlink?(1, 1)).to eq true + expect(subject.hyperlink?(1, 2)).to eq false + end + end + + describe '#hyperlink' do + let(:path) { 'test/files/link.xlsx' } + + it 'returns the expected result' do + expect(subject.hyperlink(1, 1)).to eq "http://www.google.com" + expect(subject.hyperlink(1, 2)).to eq nil + end + end + + describe '#comment' do + let(:path) { 'test/files/comments.xlsx' } + + it 'returns the expected result' do + expect(subject.comment(4, 2)).to eq "Kommentar fuer B4" + expect(subject.comment(1, 2)).to eq nil + end + end + + describe '#comment?' do + let(:path) { 'test/files/comments.xlsx' } + + it 'returns the expected result' do + expect(subject.comment?(4, 2)).to eq true + expect(subject.comment?(1, 2)).to eq false + end + end + + describe '#comments' do + let(:path) { 'test/files/comments.xlsx' } + + it 'returns the expected result' do + expect(subject.comments).to eq [[4, 2, "Kommentar fuer B4"], [5, 2, "Kommentar fuer B5"]] + end + end + + # nil, nil, nil, nil, nil + # nil, nil, nil, nil, nil + # Date Start time End time Pause Sum Comment + # 2007-05-07 9.25 10.25 0 1 Task 1 + # 2007-05-07 10.75 12.50 0 1.75 Task 1 + # 2007-05-07 18.00 19.00 0 1 Task 2 + # 2007-05-08 9.25 10.25 0 1 Task 2 + # 2007-05-08 14.50 15.50 0 1 Task 3 + # 2007-05-08 8.75 9.25 0 0.5 Task 3 + # 2007-05-14 21.75 22.25 0 0.5 Task 3 + # 2007-05-14 22.50 23.00 0 0.5 Task 3 + # 2007-05-15 11.75 12.75 0 1 Task 3 + # 2007-05-07 10.75 10.75 0 0 Task 1 + # nil + describe '#each_row_streaming' do + let(:path) { 'test/files/simple_spreadsheet.xlsx' } + + let(:expected_rows) do + [ + [nil, nil, nil, nil, nil], + [nil, nil, nil, nil, nil], + ["Date", "Start time", "End time", "Pause", "Sum", "Comment", nil, nil], + [Date.new(2007, 5, 7), 9.25, 10.25, 0.0, 1.0, "Task 1"], + [Date.new(2007, 5, 7), 10.75, 12.50, 0.0, 1.75, "Task 1"], + [Date.new(2007, 5, 7), 18.0, 19.0, 0.0, 1.0, "Task 2"], + [Date.new(2007, 5, 8), 9.25, 10.25, 0.0, 1.0, "Task 2"], + [Date.new(2007, 5, 8), 14.5, 15.5, 0.0, 1.0, "Task 3"], + [Date.new(2007, 5, 8), 8.75, 9.25, 0.0, 0.5, "Task 3"], + [Date.new(2007, 5, 14), 21.75, 22.25, 0.0, 0.5, "Task 3"], + [Date.new(2007, 5, 14), 22.5, 23.0, 0.0, 0.5, "Task 3"], + [Date.new(2007, 5, 15), 11.75, 12.75, 0.0, 1.0, "Task 3"], + [Date.new(2007, 5, 7), 10.75, 10.75, 0.0, 0.0, "Task 1"], + [nil] + ] + end + + it 'returns the expected result' do + index = 0 + subject.each_row_streaming do |row| + expect(row.map(&:value)).to eq expected_rows[index] + index += 1 + end + end + + context 'with max_rows options' do + it 'returns the expected result' do + index = 0 + subject.each_row_streaming(max_rows: 3) do |row| + expect(row.map(&:value)).to eq expected_rows[index] + index += 1 + end + # Expect this to get incremented one time more than max (because of the increment at the end of the block) + # but it should not be near expected_rows.size + expect(index).to eq 4 + end + end + + context 'with offset option' do + let(:offset) { 3 } + + it 'returns the expected result' do + index = 0 + subject.each_row_streaming(offset: offset) do |row| + expect(row.map(&:value)).to eq expected_rows[index + offset] + index += 1 + end + expect(index).to eq 11 + end + end + + context 'with offset and max_rows options' do + let(:offset) { 3 } + let(:max_rows) { 3 } + + it 'returns the expected result' do + index = 0 + subject.each_row_streaming(offset: offset, max_rows: max_rows) do |row| + expect(row.map(&:value)).to eq expected_rows[index + offset] + index += 1 + end + expect(index).to eq 4 + end + end + + context 'without block passed' do + it 'returns an enumerator' do + expect(subject.each_row_streaming).to be_a(Enumerator) + end + end + end + + describe '#html_strings' do + let(:path) { 'test/files/html_strings_formatting.xlsx' } + + it 'returns the expected result' do + expect(subject.excelx_value(1, 1, "Sheet1")).to eq "This has no formatting." + expect(subject.excelx_value(2, 1, "Sheet1")).to eq "This has bold formatting." + expect(subject.excelx_value(2, 2, "Sheet1")).to eq "This has italics formatting." + expect(subject.excelx_value(2, 3, "Sheet1")).to eq "This has underline format." + expect(subject.excelx_value(2, 4, "Sheet1")).to eq "Superscript. x123" + expect(subject.excelx_value(2, 5, "Sheet1")).to eq "SubScript. Tj" + + expect(subject.excelx_value(3, 1, "Sheet1")).to eq "Bold, italics together." + expect(subject.excelx_value(3, 2, "Sheet1")).to eq "Bold, Underline together." + expect(subject.excelx_value(3, 3, "Sheet1")).to eq "Bold, Superscript. xN" + expect(subject.excelx_value(3, 4, "Sheet1")).to eq "Bold, Subscript. Tabc" + expect(subject.excelx_value(3, 5, "Sheet1")).to eq "Italics, Underline together." + expect(subject.excelx_value(3, 6, "Sheet1")).to eq "Italics, Superscript. Xabc" + expect(subject.excelx_value(3, 7, "Sheet1")).to eq "Italics, Subscript. Befg" + expect(subject.excelx_value(4, 1, "Sheet1")).to eq "Bold, italics underline, together." + expect(subject.excelx_value(4, 2, "Sheet1")).to eq "Bold, italics, superscript. Xabc123" + expect(subject.excelx_value(4, 3, "Sheet1")).to eq "Bold, Italics, subscript. Mgha2" + expect(subject.excelx_value(4, 4, "Sheet1")).to eq "Bold, Underline, superscript. ABC123" + expect(subject.excelx_value(4, 5, "Sheet1")).to eq "Bold, Underline, subscript. GoodXYZ" + expect(subject.excelx_value(4, 6, "Sheet1")).to eq "Italics, Underline, superscript. Upswing" + expect(subject.excelx_value(4, 7, "Sheet1")).to eq "Italics, Underline, subscript. Tswing" + expect(subject.excelx_value(5, 1, "Sheet1")).to eq "Bold, italics, underline, superscript. GHJK1904" + expect(subject.excelx_value(5, 2, "Sheet1")).to eq "Bold, italics, underline, subscript. Mikedrop" + expect(subject.excelx_value(6, 1, "Sheet1")).to eq "See that regular html tags do not create html tags.\n
    \n
  1. Denver Broncos
  2. \n
  3. Carolina Panthers
  4. \n
  5. New England Patriots
  6. \n
  7. Arizona Panthers
  8. \n
" + expect(subject.excelx_value(7, 1, "Sheet1")).to eq "Does create html tags when formatting is used..\n
    \n
  1. Denver Broncos
  2. \n
  3. Carolina Panthers
  4. \n
  5. New England Patriots
  6. \n
  7. Arizona Panthers
  8. \n
" + end + end + + describe '_x000D_' do + let(:path) { 'test/files/x000D.xlsx' } + it 'does not contain _x000D_' do + expect(subject.cell(2, 9)).not_to include('_x000D_') + end + end + + describe 'opening a file with a chart sheet' do + let(:path) { 'test/files/chart_sheet.xlsx' } + it 'should not raise' do + expect{ subject }.to_not raise_error + end + end + + describe 'opening a file with white space in the styles.xml' do + let(:path) { 'test/files/style_nodes_with_white_spaces.xlsx' } + subject(:xlsx) do + Roo::Spreadsheet.open(path, expand_merged_ranges: true, extension: :xlsx) + end + it 'should properly recognize formats' do + expect(subject.sheet(0).excelx_format(2,1)).to eq 'm/d/yyyy" "h:mm:ss" "AM/PM' + end + end +end diff --git a/spec/lib/roo/libreoffice_spec.rb b/spec/lib/roo/libreoffice_spec.rb new file mode 100644 index 0000000..3a64744 --- /dev/null +++ b/spec/lib/roo/libreoffice_spec.rb @@ -0,0 +1,29 @@ +require 'spec_helper' + +describe Roo::LibreOffice do + describe '.new' do + subject do + Roo::LibreOffice.new('test/files/numbers1.ods') + end + + it 'creates an instance' do + expect(subject).to be_a(Roo::LibreOffice) + end + end + + describe '#sheets' do + let(:path) { 'test/files/hidden_sheets.ods' } + + describe 'showing all sheets' do + it 'returns the expected result' do + expect(Roo::LibreOffice.new(path).sheets).to eq ["HiddenSheet1", "VisibleSheet1", "HiddenSheet2"] + end + end + + describe 'only showing visible sheets' do + it 'returns the expected result' do + expect(Roo::LibreOffice.new(path, only_visible_sheets: true).sheets).to eq ["VisibleSheet1"] + end + end + end +end diff --git a/spec/lib/roo/openoffice_spec.rb b/spec/lib/roo/openoffice_spec.rb new file mode 100644 index 0000000..9810f45 --- /dev/null +++ b/spec/lib/roo/openoffice_spec.rb @@ -0,0 +1,43 @@ +require 'spec_helper' + +describe Roo::OpenOffice do + describe '.new' do + subject do + Roo::OpenOffice.new('test/files/numbers1.ods') + end + + it 'creates an instance' do + expect(subject).to be_a(Roo::OpenOffice) + end + + context 'for float/integer values' do + context 'integer without point' do + it { expect(subject.cell(3,"A","Sheet4")).to eq(1234) } + it { expect(subject.cell(3,"A","Sheet4")).to be_a(Integer) } + end + + context 'float with point' do + it { expect(subject.cell(3,"B","Sheet4")).to eq(1234.00) } + it { expect(subject.cell(3,"B","Sheet4")).to be_a(Float) } + end + + context 'float with point' do + it { expect(subject.cell(3,"C","Sheet4")).to eq(1234.12) } + it { expect(subject.cell(3,"C","Sheet4")).to be_a(Float) } + end + end + + context 'file path is a Pathname' do + subject do + Roo::OpenOffice.new(Pathname.new('test/files/numbers1.ods')) + end + + it 'creates an instance' do + expect(subject).to be_a(Roo::OpenOffice) + end + end + + end + + # OpenOffice is an alias of LibreOffice. See libreoffice_spec. +end diff --git a/spec/lib/roo/spreadsheet_spec.rb b/spec/lib/roo/spreadsheet_spec.rb new file mode 100644 index 0000000..19fb8a7 --- /dev/null +++ b/spec/lib/roo/spreadsheet_spec.rb @@ -0,0 +1,108 @@ +require 'spec_helper' + +describe Roo::Spreadsheet do + describe '.open' do + context 'when the file name includes a space' do + let(:filename) { 'great scott.xlsx' } + + it 'loads the proper type' do + expect(Roo::Excelx).to receive(:new).with(filename, {}) + Roo::Spreadsheet.open(filename) + end + end + + context 'when the file extension is uppercase' do + let(:filename) { 'file.XLSX' } + + it 'loads the proper type' do + expect(Roo::Excelx).to receive(:new).with(filename, {}) + Roo::Spreadsheet.open(filename) + end + end + + context 'for a tempfile' do + let(:tempfile) { Tempfile.new('foo.csv') } + let(:filename) { tempfile.path } + + it 'loads the proper type' do + expect(Roo::CSV).to receive(:new).with(filename, file_warning: :ignore).and_call_original + expect(Roo::Spreadsheet.open(tempfile, extension: :csv)).to be_a(Roo::CSV) + end + end + + context 'for a url' do + context 'that is csv' do + let(:filename) { 'http://example.com/file.csv?with=params#and=anchor' } + + it 'treats the url as CSV' do + expect(Roo::CSV).to receive(:new).with(filename, {}) + Roo::Spreadsheet.open(filename) + end + end + end + + context 'for a windows path' do + context 'that is xlsx' do + let(:filename) { 'c:\Users\Joe\Desktop\myfile.xlsx' } + + it 'loads the proper type' do + expect(Roo::Excelx).to receive(:new).with(filename, {}) + Roo::Spreadsheet.open(filename) + end + end + end + + context 'for a xlsm file' do + let(:filename) { 'macros spreadsheet.xlsm' } + + it 'loads the proper type' do + expect(Roo::Excelx).to receive(:new).with(filename, {}) + Roo::Spreadsheet.open(filename) + end + end + + context 'for a csv file' do + let(:filename) { 'file.csv' } + let(:options) { { csv_options: { col_sep: '"' } } } + + context 'with csv_options' do + it 'passes the csv_options through' do + expect(Roo::CSV).to receive(:new).with(filename, options) + Roo::Spreadsheet.open(filename, options) + end + end + end + + context 'with a file extension option' do + let(:filename) { 'file.xls' } + + context ':xlsx' do + let(:options) { { extension: :xlsx } } + + it 'loads with xls extension options' do + expect(Roo::Excelx).to receive(:new).with(filename, options) + Roo::Spreadsheet.open(filename, options) + end + end + + context 'xlsx' do + let(:options) { { extension: 'xlsx' } } + + it 'loads with xls extension options' do + expect(Roo::Excelx).to receive(:new).with(filename, options) + Roo::Spreadsheet.open(filename, options) + end + end + + context '.xlsx' do + let(:options) { { extension: '.xlsx' } } + + it 'loads with .xls extension options' do + expect(Roo::Excelx).to receive(:new).with(filename, options) + Roo::Spreadsheet.open(filename, options) + end + end + + end + end +end diff --git a/spec/lib/roo/utils_spec.rb b/spec/lib/roo/utils_spec.rb new file mode 100644 index 0000000..ffe93d4 --- /dev/null +++ b/spec/lib/roo/utils_spec.rb @@ -0,0 +1,106 @@ +require 'spec_helper' + +RSpec.describe ::Roo::Utils do + subject { described_class } + + context '#number_to_letter' do + described_class::LETTERS.each_with_index do |letter, index| + it "should return '#{ letter }' when passed #{ index + 1 }" do + expect(described_class.number_to_letter(index + 1)).to eq(letter) + end + end + + { + 27 => 'AA', 26*2 => 'AZ', 26*3 => 'BZ', 26**2 + 26 => 'ZZ', 26**2 + 27 => 'AAA', + 26**3 + 26**2 + 26 => 'ZZZ', 1.0 => 'A', 676 => 'YZ', 677 => 'ZA' + }.each do |key, value| + it "should return '#{value}' when passed #{key}" do + expect(described_class.number_to_letter(key)).to eq(value) + end + end + end + + context '#letter_to_number' do + it "should give 1 for 'A' and 'a'" do + expect(described_class.letter_to_number('A')).to eq(1) + expect(described_class.letter_to_number('a')).to eq(1) + end + + it "should give the correct value for 'Z'" do + expect(described_class.letter_to_number('Z')).to eq(26) + end + + it "should give the correct value for 'AA' regardless of case mixing" do + %w(AA aA Aa aa).each do |key| + expect(described_class.letter_to_number(key)).to eq(27) + end + end + + { 'AB' => 28, 'AZ' => 26*2, 'BZ' => 26*3, 'ZZ' => 26**2 + 26 }.each do |key, value| + it "should give the correct value for '#{key}'" do + expect(described_class.letter_to_number(key)).to eq(value) + end + end + end + + context '.split_coordinate' do + it "returns the expected result" do + expect(described_class.split_coordinate('A1')).to eq [1, 1] + expect(described_class.split_coordinate('B2')).to eq [2, 2] + expect(described_class.split_coordinate('R2')).to eq [2, 18] + expect(described_class.split_coordinate('AR31')).to eq [31, 18 + 26] + end + end + + context '.split_coord' do + it "returns the expected result" do + expect(described_class.split_coord('A1')).to eq ["A", 1] + expect(described_class.split_coord('B2')).to eq ["B", 2] + expect(described_class.split_coord('R2')).to eq ["R", 2] + expect(described_class.split_coord('AR31')).to eq ["AR", 31] + end + + it "raises an error when appropriate" do + expect { described_class.split_coord('A') }.to raise_error(ArgumentError) + expect { described_class.split_coord('2') }.to raise_error(ArgumentError) + end + end + + + context '.num_cells_in_range' do + it "returns the expected result" do + expect(described_class.num_cells_in_range('A1:B2')).to eq 4 + expect(described_class.num_cells_in_range('B2:E3')).to eq 8 + expect(described_class.num_cells_in_range('R2:Z10')).to eq 81 + expect(described_class.num_cells_in_range('AR31:AR32')).to eq 2 + expect(described_class.num_cells_in_range('A1')).to eq 1 + end + + it "raises an error when appropriate" do + expect { described_class.num_cells_in_range('A1:B1:B2') }.to raise_error(ArgumentError) + end + end + + context '.load_xml' do + it 'returns the expected result' do + expect(described_class.load_xml('test/files/sheet1.xml')).to be_a(Nokogiri::XML::Document) + expect(described_class.load_xml('test/files/sheet1.xml'). + remove_namespaces!.xpath("/worksheet/dimension").map do |dim| + dim.attributes["ref"].value end.first).to eq "A1:B11" + end + end + + context '.each_element' do + it 'returns the expected result' do + described_class.each_element('test/files/sheet1.xml', 'dimension') do |dim| + expect(dim.attributes["ref"].value).to eq "A1:B11" + end + rows = [] + described_class.each_element('test/files/sheet1.xml', 'row') do |row| + rows << row + end + expect(rows.size).to eq 11 + expect(rows[2].attributes["r"].value).to eq "3" + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..a093008 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,9 @@ +require 'simplecov' +require 'roo' +require 'helpers' + +RSpec.configure do |c| + c.include Helpers + c.color = true + c.formatter = :documentation if ENV["USE_REPORTERS"] +end -- cgit v1.2.3