PageRenderTime 50ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/README.markdown

https://github.com/cmeiklejohn/ripple
Markdown | 297 lines | 225 code | 72 blank | 0 comment | 0 complexity | ac204ff932aaa703634b191e6e93f4b0 MD5 | raw file
  1. # ripple [![Build Status](https://secure.travis-ci.org/seancribbs/ripple.png)](http://travis-ci.org/seancribbs/ripple)
  2. ripple is a rich Ruby toolkit for Riak, Basho's distributed
  3. database. It consists of three gems:
  4. * `riak-client` (`Riak` namespace) contains a basic wrapper around
  5. typical operations, including bucket manipulation, object CRUD,
  6. link-walking, and map-reduce.
  7. * `ripple` (`Ripple` namespace) contains an ActiveModel-compatible
  8. modeling layer that is inspired by ActiveRecord, DataMapper, and
  9. MongoMapper.
  10. * `riak-sessions` contains session stores for Rack and Rails 3
  11. applications.
  12. ## Dependencies
  13. `riak-client` requires i18n and either json or yajl-ruby. For higher
  14. performance on HTTP requests, install the 'curb' or 'excon' gems. The
  15. cache store implementation requires ActiveSupport 3 or later.
  16. `ripple` requires Ruby 1.8.7 or later and versions 3 or above of
  17. ActiveModel and ActiveSupport (and their dependencies, including
  18. i18n).
  19. `riak-sessions` requires Rack (any version > 1.0), and Rails 3.0 if
  20. you want the Rails-specific session store.
  21. Development dependencies are handled with bundler. Install bundler
  22. (`gem install bundler`) and run this command in each sub-project to
  23. get started:
  24. ``` bash
  25. $ bundle install
  26. ```
  27. Run the RSpec suite using `bundle exec`:
  28. ``` bash
  29. $ bundle exec rake spec
  30. ```
  31. ## Basic Example
  32. ``` ruby
  33. require 'riak'
  34. # Create a client interface
  35. client = Riak::Client.new
  36. # Create a client interface that uses Excon
  37. client = Riak::Client.new(:http_backend => :Excon)
  38. # Create a client that uses Protocol Buffers
  39. client = Riak::Client.new(:protocol => "pbc")
  40. # Automatically balance between multiple nodes
  41. client = Riak::Client.new(:nodes => [
  42. {:host => '10.0.0.1'},
  43. {:host => '10.0.0.2', :pb_port => 1234},
  44. {:host => '10.0.0.3', :http_port => 5678}
  45. ])
  46. # Retrieve a bucket
  47. bucket = client.bucket("doc") # a Riak::Bucket
  48. # Get an object from the bucket
  49. object = bucket.get_or_new("index.html") # a Riak::RObject
  50. # Change the object's data and save
  51. object.data = "<html><body>Hello, world!</body></html>"
  52. object.content_type = "text/html"
  53. object.store
  54. # Reload an object you already have
  55. object.reload # Works if you have the key and vclock, using conditional GET
  56. object.reload :force => true # Reloads whether you have the vclock or not
  57. # Access more like a hash, client[bucket][key]
  58. client['doc']['index.html'] # the Riak::RObject
  59. # Create a new object
  60. new_one = Riak::RObject.new(bucket, "application.js")
  61. new_one.content_type = "application/javascript" # You must set the content type.
  62. new_one.data = "alert('Hello, World!')"
  63. new_one.store
  64. ```
  65. ## Map-Reduce Example
  66. ``` ruby
  67. # Assuming you've already instantiated a client, get the album titles for The Beatles
  68. results = Riak::MapReduce.new(client).
  69. add("artists","Beatles").
  70. link(:bucket => "albums").
  71. map("function(v){ return [JSON.parse(v.values[0].data).title]; }", :keep => true).run
  72. p results # => ["Please Please Me", "With The Beatles", "A Hard Day's Night",
  73. # "Beatles For Sale", "Help!", "Rubber Soul",
  74. # "Revolver", "Sgt. Pepper's Lonely Hearts Club Band", "Magical Mystery Tour",
  75. # "The Beatles", "Yellow Submarine", "Abbey Road", "Let It Be"]
  76. ```
  77. ## Riak Search Examples
  78. For more information about Riak Search, see [the Basho wiki](http://wiki.basho.com/Riak-Search.html).
  79. ``` ruby
  80. # Create a client, specifying the Solr-compatible endpoint
  81. client = Riak::Client.new :solr => "/solr"
  82. # Search the default index for documents
  83. result = client.search("title:Yesterday") # Returns a vivified JSON object
  84. # containing 'responseHeaders' and 'response' keys
  85. result['response']['numFound'] # total number of results
  86. result['response']['start'] # offset into the total result set
  87. result['response']['docs'] # the list of indexed documents
  88. # Search the 'users' index for documents
  89. client.search("users", "name:Sean")
  90. # Add a document to an index
  91. client.index("users", {:id => "sean@basho.com", :name => "Sean Cribbs"}) # adds to the 'users' index
  92. client.index({:id => "index.html", :content => "Hello, world!"}) # adds to the default index
  93. client.index({:id => 1, :name => "one"}, {:id => 2, :name => "two"}) # adds multiple docs
  94. # Remove document(s) from an index
  95. client.remove({:id => 1}) # removes the document with ID 1
  96. client.remove({:query => "archived"}) # removes all documents matching query
  97. client.remove({:id => 1}, {:id => 5}) # removes multiple docs
  98. client.remove("users", {:id => "sean@basho.com"}) # removes from the 'users' index
  99. # Seed MapReduce with search results
  100. Riak::MapReduce.new(client).
  101. search("users","email:basho").
  102. map("Riak.mapValuesJson", :keep => true).
  103. run
  104. # Detect whether a bucket has auto-indexing
  105. client['users'].is_indexed?
  106. # Enable auto-indexing on a bucket
  107. client['users'].enable_index!
  108. # Disable auto-indexing on a bucket
  109. client['users'].disable_index!
  110. ```
  111. ## Document Model Examples
  112. ``` ruby
  113. require 'ripple'
  114. # Documents are stored as JSON objects in Riak but have rich
  115. # semantics, including validations and associations.
  116. class Email
  117. include Ripple::Document
  118. property :from, String, :presence => true
  119. property :to, String, :presence => true
  120. property :sent, Time, :default => proc { Time.now }
  121. property :body, String
  122. end
  123. email = Email.find("37458abc752f8413e") # GET /riak/emails/37458abc752f8413e
  124. email.from = "someone@nowhere.net"
  125. email.save # PUT /riak/emails/37458abc752f8413e
  126. reply = Email.new
  127. reply.from = "justin@bashoooo.com"
  128. reply.to = "sean@geeemail.com"
  129. reply.body = "Riak is a good fit for scalable Ruby apps."
  130. reply.save # POST /riak/emails (Riak-assigned key)
  131. # Documents can contain embedded documents, and link to other standalone documents
  132. # via associations using the many and one class methods.
  133. class Person
  134. include Ripple::Document
  135. property :name, String
  136. many :addresses
  137. many :friends, :class_name => "Person"
  138. one :account
  139. end
  140. # Account and Address are embeddable documents
  141. class Account
  142. include Ripple::EmbeddedDocument
  143. property :paid_until, Time
  144. embedded_in :person # Adds "person" method to get parent document
  145. end
  146. class Address
  147. include Ripple::EmbeddedDocument
  148. property :street, String
  149. property :city, String
  150. property :state, String
  151. property :zip, String
  152. end
  153. person = Person.find("adamhunter")
  154. person.friends << Person.find("seancribbs") # Links to people/seancribbs with tag "friend"
  155. person.addresses << Address.new(:street => "100 Main Street") # Adds an embedded address
  156. person.account.paid_until = 3.months.from_now
  157. ```
  158. ## Configuration Example
  159. When using Ripple with Rails 3, add ripple to your Gemfile and then run the `ripple` generator. This will generate a test harness, some MapReduce functions and a configuration file. Example:
  160. ```
  161. $ rails g ripple
  162. create config/ripple.yml
  163. create app/mapreduce
  164. create app/mapreduce/contrib.js
  165. create app/mapreduce/ripple.js
  166. create test/ripple_test_helper.rb
  167. insert test/test_helper.rb
  168. insert test/test_helper.rb
  169. ```
  170. `config/ripple.yml` should contain your Riak connection information, and settings for the test server. Example:
  171. ``` yaml
  172. # Configure Riak connections for the Ripple library.
  173. development:
  174. http_port: 8098
  175. pb_port: 8087
  176. host: localhost
  177. # The test environment has additional keys for configuring the
  178. # Riak::TestServer for your test/spec suite:
  179. #
  180. # * bin_dir specifies the path to the "riak" script that you use to
  181. # start Riak (just the directory)
  182. # * js_source_dir specifies where your custom Javascript functions for
  183. # MapReduce should be loaded from. Usually app/mapreduce.
  184. test:
  185. http_port: 9000
  186. pb_port: 9002
  187. host: localhost
  188. bin_dir: /usr/local/bin # Default for Homebrew.
  189. js_source_dir: <%%= Rails.root + "app/mapreduce" %>
  190. production:
  191. http_port: 8098
  192. pb_port: 8087
  193. host: localhost
  194. ```
  195. `require 'ripple/railtie'` from your `config/application.rb` file to complete the integration.
  196. ## How to Contribute
  197. * Fork the project on [Github](http://github.com/seancribbs/ripple). If you have already forked, use `git pull --rebase` to reapply your changes on top of the mainline. Example:
  198. ``` bash
  199. $ git checkout master
  200. $ git pull --rebase seancribbs master
  201. ```
  202. * Create a topic branch. If you've already created a topic branch, rebase it on top of changes from the mainline "master" branch. Examples:
  203. * New branch:
  204. ``` bash
  205. $ git checkout -b topic
  206. ```
  207. * Existing branch:
  208. ``` bash
  209. $ git rebase master
  210. ```
  211. * Write an RSpec example or set of examples that demonstrate the necessity and validity of your changes. **Patches without specs will most often be ignored. Just do it, you'll thank me later.** Documentation patches need no specs, of course.
  212. * Make your feature addition or bug fix. Make your specs and stories pass (green).
  213. * Run the suite using multiruby or rvm to ensure cross-version compatibility.
  214. * Cleanup any trailing whitespace in your code (try @whitespace-mode@ in Emacs, or "Remove Trailing Spaces in Document" in the "Text" bundle in Textmate).
  215. * Commit, do not mess with Rakefile or VERSION. If related to an existing issue in the [tracker](http://github.com/seancribbs/ripple/issues), include "Closes #X" in the commit message (where X is the issue number).
  216. * Send me a pull request.
  217. ## License & Copyright
  218. Copyright &copy;2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
  219. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
  220. [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
  221. Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
  222. ## Auxillary Licenses
  223. The included photo (spec/fixtures/cat.jpg) is Copyright &copy;2009 [Sean Cribbs](http://seancribbs.com/), and is licensed under the [Creative Commons Attribution Non-Commercial 3.0](http://creativecommons.org/licenses/by-nc/3.0) license.
  224. !["Creative Commons"](http://i.creativecommons.org/l/by-nc/3.0/88x31.png)
  225. The "Poor Man's Fibers" implementation (lib/riak/util/fiber1.8.rb) is Copyright &copy;2008 Aman Gupta.