tumblr_client 0.6.11 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +10 -1
- data/.travis.yml +10 -0
- data/README.md +30 -11
- data/lib/tumblr/blog.rb +50 -64
- data/lib/tumblr/client.rb +8 -6
- data/lib/tumblr/config.rb +7 -9
- data/lib/tumblr/connection.rb +12 -7
- data/lib/tumblr/helpers.rb +14 -9
- data/lib/tumblr/post.rb +96 -99
- data/lib/tumblr/request.rb +13 -0
- data/lib/tumblr/request/oauth.rb +21 -21
- data/lib/tumblr/tagged.rb +9 -14
- data/lib/tumblr/user.rb +37 -36
- data/lib/tumblr/version.rb +5 -0
- data/lib/tumblr_client.rb +7 -2
- data/spec/examples/blog_spec.rb +185 -0
- data/spec/examples/client_spec.rb +46 -0
- data/spec/examples/post_spec.rb +186 -0
- data/spec/examples/tagged_spec.rb +31 -0
- data/spec/examples/user_spec.rb +114 -0
- data/spec/spec_helper.rb +7 -0
- data/{tumblr.gemspec → tumblr_client.gemspec} +4 -2
- metadata +34 -10
- data/.path +0 -1
- data/Gemfile.lock +0 -43
data/.gitignore
CHANGED
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# Tumblr Ruby Gem
|
2
2
|
|
3
|
+
[](http://travis-ci.org/codingjester/tumblr_client)
|
4
|
+
|
3
5
|
This is a ruby wrapper for the Tumblr v2 API. There should be support for all endpoints
|
4
6
|
currently available on the [Tumblr API](http://www.tumblr.com/docs/en/api/v2).
|
5
7
|
|
@@ -18,10 +20,10 @@ your life easier when using the v2 api. If you need to do the full oauth workflo
|
|
18
20
|
Configuration for the gem is actually pretty easy:
|
19
21
|
|
20
22
|
Tumblr.configure do |config|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
23
|
+
config.consumer_key = "consumer_key"
|
24
|
+
config.consumer_secret = "consumer_secret"
|
25
|
+
config.oauth_token = "access_token"
|
26
|
+
config.oauth_token_secret = "access_token_secret"
|
25
27
|
end
|
26
28
|
|
27
29
|
Once you have your configuration squared away it's time to make some requests!
|
@@ -33,27 +35,31 @@ That's it! You now have a client that can make any request to the Tumblr API.
|
|
33
35
|
### Some quick examples
|
34
36
|
|
35
37
|
Getting user information:
|
36
|
-
|
38
|
+
|
37
39
|
>> client.info
|
38
40
|
|
39
41
|
Getting a specific blog's posts and type:
|
40
|
-
|
42
|
+
|
41
43
|
#Grabbing a specific blogs posts
|
42
44
|
>> client.posts("codingjester.tumblr.com")
|
43
|
-
|
44
|
-
#Grabbing only the last 10 photos off the blog
|
45
|
+
|
46
|
+
#Grabbing only the last 10 photos off the blog
|
45
47
|
>> client.posts("codingjester.tumblr.com", :type => "photo", :limit => 10)
|
46
48
|
|
47
49
|
|
48
50
|
Posting some photos to Tumblr:
|
49
51
|
|
50
|
-
#Uploads a great photoset
|
52
|
+
# Uploads a great photoset
|
51
53
|
>> client.photo("codingjester.tumblr.com", {:data => ['/path/to/pic.jpg', '/path/to/pic.jpg']})
|
52
54
|
|
55
|
+
# You can also post with the raw data
|
56
|
+
>> raw = File.open('/path/to/pic.jpg', 'rb').read
|
57
|
+
>> client.photo('codingjester.tumblr.com', :data_raw => [raw]
|
58
|
+
|
53
59
|
### The irb Console
|
54
60
|
|
55
61
|
Finally, there is an irb console packaged with the gem that should help you test any calls you want to make.
|
56
|
-
The magic here is that you have a
|
62
|
+
The magic here is that you have a `.tumblr` file in your home directory. Inside this file it's just a basic
|
57
63
|
YAML layout with four lines:
|
58
64
|
|
59
65
|
consumer_key: "your_consumer_key"
|
@@ -61,12 +67,25 @@ YAML layout with four lines:
|
|
61
67
|
oauth_token: "your_access_token"
|
62
68
|
oauth_token_secret: "your_access_token_secret"
|
63
69
|
|
64
|
-
From there, you should be able to run any of the above commands, with no problem! Just fire off the command
|
70
|
+
From there, you should be able to run any of the above commands, with no problem! Just fire off the command `tumblr`
|
65
71
|
from the terminal and you should be dropped into a console.
|
66
72
|
|
73
|
+
---
|
74
|
+
|
75
|
+
The first time that you go to use the irb console, if you have no `.tumblr`
|
76
|
+
file, it will walk you through the process of generating one. You will
|
77
|
+
be prompted for your consumer_key and consumer_secret (which you can get
|
78
|
+
here: http://www.tumblr.com/oauth/register) and then sent out to the site
|
79
|
+
to verify your account. Once you verify, you will be redirected to your
|
80
|
+
redirect URL (localhost by default) and copy the `oauth_verifier` back into the
|
81
|
+
console. Then you're all set!
|
67
82
|
|
68
83
|
### Contributions and Pull Requests
|
69
84
|
|
70
85
|
No request is too small and I encourage everyone to get involved. As you can see, we're sorely lacking in tests! So
|
71
86
|
please if you would like to contribute, let me know and throw me a pull request!
|
72
87
|
|
88
|
+
|
89
|
+
### Requirements
|
90
|
+
|
91
|
+
* Ruby >= 1.9.2
|
data/lib/tumblr/blog.rb
CHANGED
@@ -1,73 +1,59 @@
|
|
1
1
|
module Tumblr
|
2
|
-
|
3
|
-
module Blog
|
4
|
-
|
5
|
-
@@standard_options = [:type, :id, :tag, :limit, :offset, :reblog_info, :notes_info, :filter]
|
6
|
-
#
|
7
|
-
#Gets the info about the blog
|
8
|
-
#
|
9
|
-
def blog_info(blog_name)
|
10
|
-
get("v2/blog/#{blog_name}/info", {:api_key => @consumer_key})
|
11
|
-
end
|
2
|
+
module Blog
|
12
3
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
response = get_response("v2/blog/#{blog_name}/avatar", :size => size)
|
18
|
-
if response.status == 301
|
19
|
-
response.headers['Location']
|
20
|
-
end
|
21
|
-
end
|
4
|
+
# Gets the info about the blog
|
5
|
+
def blog_info(blog_name)
|
6
|
+
get("v2/blog/#{blog_name}/info", :api_key => @consumer_key)
|
7
|
+
end
|
22
8
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
#
|
33
|
-
# Gets the list of likes for the blog
|
34
|
-
#
|
35
|
-
def blog_likes(blog_name, options={})
|
36
|
-
if valid_options([:limit, :offset], options)
|
37
|
-
url = "v2/blog/#{blog_name}/likes"
|
38
|
-
params = {:api_key => @consumer_key}
|
39
|
-
unless options.empty?
|
40
|
-
params.merge!(options)
|
41
|
-
end
|
42
|
-
get(url, params)
|
43
|
-
end
|
44
|
-
end
|
9
|
+
# Gets the avatar URL of specified size
|
10
|
+
def avatar(blog_name, size = nil)
|
11
|
+
url = "v2/blog/#{blog_name}/avatar"
|
12
|
+
url = "#{url}/#{size}" if size
|
13
|
+
get_redirect_url(url)
|
14
|
+
end
|
45
15
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
end
|
52
|
-
|
53
|
-
params = {:api_key => @consumer_key}
|
54
|
-
unless options.empty?
|
55
|
-
params.merge!(options)
|
56
|
-
end
|
57
|
-
get(url, params)
|
58
|
-
end
|
16
|
+
# Gets the list of followers for the blog
|
17
|
+
def followers(blog_name, options = {})
|
18
|
+
validate_options([:limit, :offset], options)
|
19
|
+
get("v2/blog/#{blog_name}/followers", options)
|
20
|
+
end
|
59
21
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
22
|
+
# Gets the list of likes for the blog
|
23
|
+
def blog_likes(blog_name, options = {})
|
24
|
+
validate_options([:limit, :offset], options)
|
25
|
+
url = "v2/blog/#{blog_name}/likes"
|
26
|
+
|
27
|
+
params = { :api_key => @consumer_key }
|
28
|
+
params.merge! options
|
29
|
+
get(url, params)
|
30
|
+
end
|
31
|
+
|
32
|
+
def posts(blog_name, options = {})
|
33
|
+
url = "v2/blog/#{blog_name}/posts"
|
34
|
+
if options.has_key?(:type)
|
35
|
+
url = "#{url}/#{options[:type]}"
|
70
36
|
end
|
37
|
+
|
38
|
+
params = { :api_key => @consumer_key }
|
39
|
+
params.merge! options
|
40
|
+
get(url, params)
|
41
|
+
end
|
42
|
+
|
43
|
+
def queue(blog_name, options = {})
|
44
|
+
validate_options([:limit, :offset], options)
|
45
|
+
get("v2/blog/#{blog_name}/posts/queue", options)
|
71
46
|
end
|
47
|
+
|
48
|
+
def draft(blog_name, options = {})
|
49
|
+
validate_options([:limit, :offset], options)
|
50
|
+
get("v2/blog/#{blog_name}/posts/draft", options)
|
51
|
+
end
|
52
|
+
|
53
|
+
def submissions(blog_name, options = {})
|
54
|
+
validate_options([:limit, :offset], options)
|
55
|
+
get("v2/blog/#{blog_name}/posts/submission", options)
|
56
|
+
end
|
57
|
+
|
72
58
|
end
|
73
59
|
end
|
data/lib/tumblr/client.rb
CHANGED
@@ -8,14 +8,15 @@ require 'tumblr/helpers'
|
|
8
8
|
|
9
9
|
module Tumblr
|
10
10
|
class Client
|
11
|
+
|
11
12
|
include Tumblr::Request
|
12
|
-
include Tumblr::
|
13
|
-
include Tumblr::
|
14
|
-
include Tumblr::
|
15
|
-
include Tumblr::
|
16
|
-
include Tumblr::
|
13
|
+
include Tumblr::Blog
|
14
|
+
include Tumblr::User
|
15
|
+
include Tumblr::Post
|
16
|
+
include Tumblr::Tagged
|
17
|
+
include Tumblr::Helper
|
17
18
|
include Tumblr::Connection
|
18
|
-
|
19
|
+
|
19
20
|
def initialize(attrs= {})
|
20
21
|
attrs = Tumblr.options.merge(attrs)
|
21
22
|
Config::VALID_OPTIONS_KEYS.each do |key|
|
@@ -35,5 +36,6 @@ module Tumblr
|
|
35
36
|
:token_secret => @oauth_token_secret
|
36
37
|
}
|
37
38
|
end
|
39
|
+
|
38
40
|
end
|
39
41
|
end
|
data/lib/tumblr/config.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
module Tumblr
|
2
|
-
|
3
2
|
module Config
|
4
3
|
|
5
4
|
VALID_OPTIONS_KEYS = [
|
@@ -8,29 +7,28 @@ module Tumblr
|
|
8
7
|
:oauth_token,
|
9
8
|
:oauth_token_secret
|
10
9
|
]
|
11
|
-
|
10
|
+
|
12
11
|
attr_accessor *VALID_OPTIONS_KEYS
|
13
12
|
|
14
13
|
def configure
|
15
14
|
yield self
|
16
15
|
self
|
17
16
|
end
|
18
|
-
|
17
|
+
|
19
18
|
def options
|
20
19
|
options = {}
|
21
|
-
VALID_OPTIONS_KEYS.each{ |
|
20
|
+
VALID_OPTIONS_KEYS.each{ |pname| options[pname] = send(pname) }
|
22
21
|
options
|
23
22
|
end
|
24
23
|
|
25
24
|
def credentials
|
26
25
|
{
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
26
|
+
:consumer_key => consumer_key,
|
27
|
+
:consumer_secret => consumer_secret,
|
28
|
+
:token => oauth_token,
|
29
|
+
:token_secret => oauth_token_secret
|
31
30
|
}
|
32
31
|
end
|
33
32
|
|
34
33
|
end
|
35
|
-
|
36
34
|
end
|
data/lib/tumblr/connection.rb
CHANGED
@@ -4,21 +4,26 @@ require 'tumblr/request/oauth'
|
|
4
4
|
|
5
5
|
module Tumblr
|
6
6
|
module Connection
|
7
|
+
|
7
8
|
def connection(options={})
|
9
|
+
host = api_host
|
8
10
|
default_options = {
|
9
11
|
:headers => {
|
10
|
-
:accept =>
|
11
|
-
:user_agent => "Tumblr
|
12
|
+
:accept => 'application/json',
|
13
|
+
:user_agent => "tumblr_client (ruby) - #{Tumblr::VERSION}"
|
12
14
|
},
|
13
|
-
:url => "http://#{
|
15
|
+
:url => "http://#{host}/"
|
14
16
|
}
|
15
|
-
Faraday.new("http://#{
|
16
|
-
data = { :api_host =>
|
17
|
-
|
17
|
+
Faraday.new("http://#{host}/", default_options.merge(options)) do |builder|
|
18
|
+
data = { :api_host => host }.merge(credentials)
|
19
|
+
unless credentials.empty?
|
20
|
+
builder.use Tumblr::Request::TumblrOAuth, data
|
21
|
+
end
|
18
22
|
builder.use Faraday::Request::UrlEncoded
|
19
|
-
builder.use FaradayMiddleware::ParseJson, :content_type =>
|
23
|
+
builder.use FaradayMiddleware::ParseJson, :content_type => 'application/json'
|
20
24
|
builder.use Faraday::Adapter::NetHttp
|
21
25
|
end
|
22
26
|
end
|
27
|
+
|
23
28
|
end
|
24
29
|
end
|
data/lib/tumblr/helpers.rb
CHANGED
@@ -1,14 +1,19 @@
|
|
1
1
|
module Tumblr
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
raise Exception, "Invalid options passed, Only #{valid_opts} allowed."
|
9
|
-
end
|
10
|
-
return true
|
2
|
+
module Helper
|
3
|
+
|
4
|
+
def validate_options(valid_opts, opts)
|
5
|
+
bad_opts = opts.select { |val| !valid_opts.include?(val) }
|
6
|
+
if bad_opts.any?
|
7
|
+
raise ArgumentError.new "Invalid options (#{bad_opts.keys.join(', ')}) passed, only #{valid_opts} allowed."
|
11
8
|
end
|
12
9
|
end
|
10
|
+
|
11
|
+
def validate_no_collision(options, attributes)
|
12
|
+
count = attributes.count { |attr| options.has_key?(attr) }
|
13
|
+
if count > 1
|
14
|
+
raise ArgumentError.new "Can only use one of: #{attributes.join(', ')} (Found #{count})"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
13
18
|
end
|
14
19
|
end
|
data/lib/tumblr/post.rb
CHANGED
@@ -1,113 +1,110 @@
|
|
1
1
|
module Tumblr
|
2
|
-
|
3
|
-
module Post
|
4
|
-
|
5
|
-
@@standard_post_options = [:state, :tags, :tweet, :date, :markdown, :slug, :format]
|
6
|
-
|
7
|
-
def edit(blog_name, options={})
|
8
|
-
post("v2/blog/#{blog_name}/post/edit", options)
|
9
|
-
end
|
2
|
+
module Post
|
10
3
|
|
11
|
-
|
12
|
-
def reblog(blog_name, options={})
|
13
|
-
post("v2/blog/#{blog_name}/post/reblog", options)
|
14
|
-
end
|
15
|
-
|
16
|
-
def delete(blog_name, id)
|
17
|
-
post("v2/blog/#{blog_name}/post/delete", {:id => id})
|
18
|
-
end
|
4
|
+
STANDARD_POST_OPTIONS = [:state, :tags, :tweet, :date, :markdown, :slug, :format]
|
19
5
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
options[:type] = "photo"
|
24
|
-
if (options.has_key?(:data) && options.has_key?(:source))
|
25
|
-
raise Exception, "You can only use one parameter, either source or data."
|
26
|
-
end
|
27
|
-
if options.has_key?(:source) && options[:source].kind_of?(Array)
|
28
|
-
count = 0
|
29
|
-
options[:source].each do |src|
|
30
|
-
options["source[#{count}]"] = src
|
31
|
-
count += 1
|
32
|
-
end
|
33
|
-
options.delete(:source)
|
34
|
-
end
|
35
|
-
if options.has_key?(:data)
|
36
|
-
#Probably can be refactored
|
37
|
-
if options[:data].kind_of?(Array)
|
38
|
-
count = 0
|
39
|
-
options[:data].each do |filepath|
|
40
|
-
options["data[#{count}]"] = File.open(filepath, 'rb').read()
|
41
|
-
count += 1
|
42
|
-
end
|
43
|
-
options.delete(:data)
|
44
|
-
else
|
45
|
-
options[:data] = File.open(options[:data],'rb').read()
|
46
|
-
end
|
47
|
-
end
|
48
|
-
post("v2/blog/#{blog_name}/post", options)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def quote(blog_name, options={})
|
53
|
-
valid_opts = @@standard_post_options + [:quote, :source]
|
54
|
-
if valid_options(valid_opts, options)
|
55
|
-
options[:type] = "quote"
|
56
|
-
post("v2/blog/#{blog_name}/post", options)
|
57
|
-
end
|
58
|
-
end
|
6
|
+
def edit(blog_name, options = {})
|
7
|
+
post("v2/blog/#{blog_name}/post/edit", options)
|
8
|
+
end
|
59
9
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
options[:type] = "text"
|
64
|
-
post("v2/blog/#{blog_name}/post", options)
|
65
|
-
end
|
66
|
-
end
|
10
|
+
def reblog(blog_name, options = {})
|
11
|
+
post("v2/blog/#{blog_name}/post/reblog", options)
|
12
|
+
end
|
67
13
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
14
|
+
def delete(blog_name, id)
|
15
|
+
post("v2/blog/#{blog_name}/post/delete", :id => id)
|
16
|
+
end
|
17
|
+
|
18
|
+
def photo(blog_name, options = {})
|
19
|
+
valid_opts = STANDARD_POST_OPTIONS + [:caption, :link, :data, :data_raw, :source, :photoset_layout]
|
20
|
+
validate_options(valid_opts, options)
|
21
|
+
validate_no_collision options, [:data, :source]
|
75
22
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
options[
|
80
|
-
post("v2/blog/#{blog_name}/post", options)
|
23
|
+
# Allow source to be passed as an Array
|
24
|
+
if options.has_key?(:source) && options[:source].kind_of?(Array)
|
25
|
+
options[:source].each.with_index do |src, idx|
|
26
|
+
options["source[#{idx}]"] = src
|
81
27
|
end
|
28
|
+
options.delete(:source)
|
82
29
|
end
|
83
30
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
31
|
+
options[:type] = 'photo'
|
32
|
+
extract_data!(options)
|
33
|
+
post("v2/blog/#{blog_name}/post", options)
|
34
|
+
end
|
35
|
+
|
36
|
+
def quote(blog_name, options = {})
|
37
|
+
valid_opts = STANDARD_POST_OPTIONS + [:quote, :source]
|
38
|
+
validate_options(valid_opts, options)
|
39
|
+
|
40
|
+
options[:type] = 'quote'
|
41
|
+
post("v2/blog/#{blog_name}/post", options)
|
42
|
+
end
|
43
|
+
|
44
|
+
def text(blog_name, options = {})
|
45
|
+
valid_opts = STANDARD_POST_OPTIONS + [:title, :body]
|
46
|
+
validate_options(valid_opts, options)
|
47
|
+
|
48
|
+
options[:type] = 'text'
|
49
|
+
post("v2/blog/#{blog_name}/post", options)
|
50
|
+
end
|
51
|
+
|
52
|
+
def link(blog_name, options = {})
|
53
|
+
valid_opts = STANDARD_POST_OPTIONS + [:title, :url, :description]
|
54
|
+
validate_options(valid_opts, options)
|
55
|
+
|
56
|
+
options[:type] = 'link'
|
57
|
+
post("v2/blog/#{blog_name}/post", options)
|
58
|
+
end
|
59
|
+
|
60
|
+
def chat(blog_name, options = {})
|
61
|
+
valid_opts = STANDARD_POST_OPTIONS + [:title, :conversation]
|
62
|
+
validate_options(valid_opts, options)
|
63
|
+
|
64
|
+
options[:type] = 'chat'
|
65
|
+
post("v2/blog/#{blog_name}/post", options)
|
66
|
+
end
|
67
|
+
|
68
|
+
def audio(blog_name, options = {})
|
69
|
+
valid_opts = STANDARD_POST_OPTIONS + [:data, :data_raw, :caption, :external_url]
|
70
|
+
validate_options(valid_opts, options)
|
71
|
+
validate_no_collision options, [:data, :external_url]
|
72
|
+
|
73
|
+
options[:type] = 'audio'
|
74
|
+
extract_data!(options)
|
75
|
+
post("v2/blog/#{blog_name}/post", options)
|
76
|
+
end
|
77
|
+
|
78
|
+
def video(blog_name, options = {})
|
79
|
+
valid_opts = STANDARD_POST_OPTIONS + [:data, :data_raw, :embed, :caption]
|
80
|
+
validate_options(valid_opts, options)
|
81
|
+
validate_no_collision options, [:data, :embed]
|
82
|
+
|
83
|
+
options[:type] = 'video'
|
84
|
+
extract_data!(options)
|
85
|
+
post("v2/blog/#{blog_name}/post", options)
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
# Look for the various ways that data can be passed, and normalize
|
91
|
+
# the result in this hash
|
92
|
+
def extract_data!(options)
|
93
|
+
validate_no_collision options, [:data, :data_raw]
|
94
|
+
if options.has_key?(:data)
|
95
|
+
data = options.delete :data
|
96
|
+
data = [data] unless Array === data
|
97
|
+
data.each.with_index do |filepath, idx|
|
98
|
+
options["data[#{idx}]"] = File.open(filepath, 'rb').read
|
95
99
|
end
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
options[:type] = "video"
|
102
|
-
if (options.has_key?(:data) && options.has_key?(:embed))
|
103
|
-
raise Exception, "You can only use one parameter, either data or embed."
|
104
|
-
end
|
105
|
-
if(options.has_key?(:data))
|
106
|
-
options[:data] = File.open(options[:data],'rb').read()
|
107
|
-
end
|
108
|
-
post("v2/blog/#{blog_name}/post", options)
|
100
|
+
elsif options.has_key?(:data_raw)
|
101
|
+
data_raw = options.delete :data_raw
|
102
|
+
data_raw = [data_raw] unless Array === data_raw
|
103
|
+
data_raw.each.with_index do |dr, idx|
|
104
|
+
options["data[#{idx}]"] = dr
|
109
105
|
end
|
110
106
|
end
|
111
107
|
end
|
112
|
-
|
108
|
+
|
109
|
+
end
|
113
110
|
end
|