README.md in kredis-1.5.0 vs README.md in kredis-1.6.0
- old
+ new
@@ -19,15 +19,15 @@
integer = Kredis.integer "myinteger"
integer.value = 5 # => SET myinteger "5"
5 == integer.value # => GET myinteger
decimal = Kredis.decimal "mydecimal" # accuracy!
-decimal.value = "%.47f" % (1.0/10) # => SET mydecimal "0.10000000000000000555111512312578270211815834045"
+decimal.value = "%.47f" % (1.0 / 10) # => SET mydecimal "0.10000000000000000555111512312578270211815834045"
BigDecimal("0.10000000000000000555111512312578270211815834045e0") == decimal.value # => GET mydecimal
float = Kredis.float "myfloat" # speed!
-float.value = 1.0/10 # => SET myfloat "0.1"
+float.value = 1.0 / 10 # => SET myfloat "0.1"
0.1 == float.value # => GET myfloat
boolean = Kredis.boolean "myboolean"
boolean.value = true # => SET myboolean "t"
true == boolean.value # => GET myboolean
@@ -47,14 +47,14 @@
```ruby
list = Kredis.list "mylist"
list << "hello world!" # => RPUSH mylist "hello world!"
[ "hello world!" ] == list.elements # => LRANGE mylist 0, -1
-integer_list = Kredis.list "myintegerlist", typed: :integer
-integer_list.append([ 1, 2, 3 ]) # => RPUSH myintegerlist "1" "2" "3"
-integer_list << 4 # => RPUSH myintegerlist "4"
-[ 1, 2, 3, 4 ] == integer_list.elements # => LRANGE myintegerlist 0 -1
+integer_list = Kredis.list "myintegerlist", typed: :integer, default: [ 1, 2, 3 ] # => EXISTS? myintegerlist, RPUSH myintegerlist "1" "2" "3"
+integer_list.append([ 4, 5, 6 ]) # => RPUSH myintegerlist "4" "5" "6"
+integer_list << 7 # => RPUSH myintegerlist "7"
+[ 1, 2, 3, 4, 5, 6, 7 ] == integer_list.elements # => LRANGE myintegerlist 0 -1
unique_list = Kredis.unique_list "myuniquelist"
unique_list.append(%w[ 2 3 4 ]) # => LREM myuniquelist 0, "2" + LREM myuniquelist 0, "3" + LREM myuniquelist 0, "4" + RPUSH myuniquelist "2", "3", "4"
unique_list.prepend(%w[ 1 2 3 4 ]) # => LREM myuniquelist 0, "1" + LREM myuniquelist 0, "2" + LREM myuniquelist 0, "3" + LREM myuniquelist 0, "4" + LPUSH myuniquelist "1", "2", "3", "4"
unique_list.append([])
@@ -161,20 +161,12 @@
true == flag.marked? #=> EXISTS myflag
sleep 0.6.seconds
false == flag.marked? #=> EXISTS myflag
```
-And using structures on a different than the default `shared` redis instance, relying on `config/redis/secondary.yml`:
+### Models
-```ruby
-one_string = Kredis.string "mystring"
-two_string = Kredis.string "mystring", config: :secondary
-
-one_string.value = "just on shared"
-two_string.value != one_string.value
-```
-
You can use all these structures in models:
```ruby
class Person < ApplicationRecord
kredis_list :names
@@ -195,10 +187,33 @@
true == person.morning.bright? # => GET people:5:morning
person.morning.value = "blue" # => SET people:5:morning
true == person.morning.blue? # => GET people:5:morning
```
+### Default values
+
+You can set a default value for all types. For example:
+
+```ruby
+list = Kredis.list "favorite_colors", default: [ "red", "green", "blue" ]
+
+# or, in a model
+class Person < ApplicationRecord
+ kredis_string :name, default: "Unknown"
+ kredis_list :favorite_colors, default: [ "red", "green", "blue" ]
+end
+```
+
+There's a performance overhead to consider though. When you first read or write an attribute in a model, Kredis will
+check if the underlying Redis key exists, while watching for concurrent changes, and if it does not,
+write the specified default value.
+
+This means that using default values in a typical Rails app additional Redis calls (WATCH, EXISTS, UNWATCH) will be
+executed for each Kredis attribute with a default value read or written during a request.
+
+### Callbacks
+
You can also define `after_change` callbacks that trigger on mutations:
```ruby
class Person < ApplicationRecord
kredis_list :names, after_change: ->(p) { }
@@ -207,10 +222,22 @@
def skillset_changed
end
end
```
+### Multiple Redis servers
+
+And using structures on a different than the default `shared` redis instance, relying on `config/redis/secondary.yml`:
+
+```ruby
+one_string = Kredis.string "mystring"
+two_string = Kredis.string "mystring", config: :secondary
+
+one_string.value = "just on shared"
+two_string.value != one_string.value
+```
+
## Installation
1. Run `./bin/bundle add kredis`
2. Run `./bin/rails kredis:install` to add a default configuration at [`config/redis/shared.yml`](lib/install/shared.yml)
@@ -226,18 +253,18 @@
If you need to connect to Redis with SSL, the recommended approach is to set your Redis instance manually by adding an entry to the `Kredis::Connections.connections` hash. Below an example showing how to connect to Redis using Client Authentication:
```ruby
Kredis::Connections.connections[:shared] = Redis.new(
- url: ENV['REDIS_URL'],
+ url: ENV["REDIS_URL"],
ssl_params: {
cert_store: OpenSSL::X509::Store.new.tap { |store|
- store.add_file(Rails.root.join('config', 'ca_cert.pem').to_s)
+ store.add_file(Rails.root.join("config", "ca_cert.pem").to_s)
},
cert: OpenSSL::X509::Certificate.new(File.read(
- Rails.root.join('config', 'client.crt')
+ Rails.root.join("config", "client.crt")
)),
key: OpenSSL::PKey::RSA.new(
Rails.application.credentials.redis[:client_key]
),
@@ -256,9 +283,32 @@
```ruby
config.kredis.connector = ->(config) { SomeRedisProxy.new(config) }
```
By default Kredis will use `Redis.new(config)`.
+
+## Development
+
+A development console is available by running `bin/console`.
+
+From there, you can experiment with Kredis. e.g.
+
+```erb
+>> str = Kredis.string "mystring"
+ Kredis (0.1ms) Connected to shared
+=>
+#<Kredis::Types::Scalar:0x0000000134c7d938
+...
+>> str.value = "hello, world"
+ Kredis Proxy (2.4ms) SET mystring ["hello, world"]
+=> "hello, world"
+>> str.value
+```
+
+Run tests with `bin/test`.
+
+[`debug`](https://github.com/ruby/debug) can be used in the development console and in the test suite by inserting a
+breakpoint, e.g. `debugger`.
## License
Kredis is released under the [MIT License](https://opensource.org/licenses/MIT).