opium 1.0.0.beta
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.
- checksums.yaml +7 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +24 -0
- data/.travis.yml +17 -0
- data/Gemfile +4 -0
- data/Guardfile +11 -0
- data/LICENSE.txt +22 -0
- data/README.md +71 -0
- data/Rakefile +10 -0
- data/lib/generators/opium/config_generator.rb +15 -0
- data/lib/generators/opium/model_generator.rb +33 -0
- data/lib/generators/opium/templates/config.yml +27 -0
- data/lib/generators/opium/templates/model.rb +10 -0
- data/lib/opium/config.rb +44 -0
- data/lib/opium/extensions/array.rb +10 -0
- data/lib/opium/extensions/boolean.rb +13 -0
- data/lib/opium/extensions/date.rb +18 -0
- data/lib/opium/extensions/date_time.rb +18 -0
- data/lib/opium/extensions/false_class.rb +7 -0
- data/lib/opium/extensions/float.rb +13 -0
- data/lib/opium/extensions/geo_point.rb +37 -0
- data/lib/opium/extensions/hash.rb +43 -0
- data/lib/opium/extensions/integer.rb +13 -0
- data/lib/opium/extensions/numeric.rb +7 -0
- data/lib/opium/extensions/object.rb +15 -0
- data/lib/opium/extensions/pointer.rb +20 -0
- data/lib/opium/extensions/regexp.rb +12 -0
- data/lib/opium/extensions/string.rb +20 -0
- data/lib/opium/extensions/time.rb +19 -0
- data/lib/opium/extensions/true_class.rb +7 -0
- data/lib/opium/extensions.rb +16 -0
- data/lib/opium/model/attributable.rb +37 -0
- data/lib/opium/model/callbacks.rb +38 -0
- data/lib/opium/model/connectable.rb +155 -0
- data/lib/opium/model/criteria.rb +123 -0
- data/lib/opium/model/dirty.rb +35 -0
- data/lib/opium/model/field.rb +31 -0
- data/lib/opium/model/fieldable.rb +57 -0
- data/lib/opium/model/findable.rb +20 -0
- data/lib/opium/model/kaminari/queryable.rb +46 -0
- data/lib/opium/model/kaminari/scopable.rb +15 -0
- data/lib/opium/model/kaminari.rb +4 -0
- data/lib/opium/model/persistable.rb +153 -0
- data/lib/opium/model/queryable.rb +150 -0
- data/lib/opium/model/scopable.rb +58 -0
- data/lib/opium/model/serialization.rb +13 -0
- data/lib/opium/model.rb +47 -0
- data/lib/opium/railtie.rb +14 -0
- data/lib/opium/user.rb +44 -0
- data/lib/opium/version.rb +3 -0
- data/lib/opium.rb +9 -0
- data/opium.gemspec +40 -0
- data/spec/opium/config/opium.yml +5 -0
- data/spec/opium/config_spec.rb +56 -0
- data/spec/opium/extensions/array_spec.rb +34 -0
- data/spec/opium/extensions/boolean_spec.rb +28 -0
- data/spec/opium/extensions/date_spec.rb +55 -0
- data/spec/opium/extensions/date_time_spec.rb +55 -0
- data/spec/opium/extensions/float_spec.rb +42 -0
- data/spec/opium/extensions/geo_point_spec.rb +55 -0
- data/spec/opium/extensions/hash_spec.rb +76 -0
- data/spec/opium/extensions/integer_spec.rb +42 -0
- data/spec/opium/extensions/object_spec.rb +24 -0
- data/spec/opium/extensions/pointer_spec.rb +28 -0
- data/spec/opium/extensions/regexp_spec.rb +23 -0
- data/spec/opium/extensions/string_spec.rb +65 -0
- data/spec/opium/extensions/time_spec.rb +55 -0
- data/spec/opium/model/attributable_spec.rb +45 -0
- data/spec/opium/model/callbacks_spec.rb +59 -0
- data/spec/opium/model/connectable_spec.rb +218 -0
- data/spec/opium/model/criteria_spec.rb +285 -0
- data/spec/opium/model/dirty_spec.rb +39 -0
- data/spec/opium/model/fieldable_spec.rb +133 -0
- data/spec/opium/model/findable_spec.rb +57 -0
- data/spec/opium/model/kaminari/queryable_spec.rb +22 -0
- data/spec/opium/model/kaminari/scopable_spec.rb +20 -0
- data/spec/opium/model/kaminari_spec.rb +104 -0
- data/spec/opium/model/persistable_spec.rb +367 -0
- data/spec/opium/model/queryable_spec.rb +338 -0
- data/spec/opium/model/scopable_spec.rb +115 -0
- data/spec/opium/model/serialization_spec.rb +51 -0
- data/spec/opium/model_spec.rb +49 -0
- data/spec/opium/user_spec.rb +195 -0
- data/spec/opium_spec.rb +5 -0
- data/spec/spec_helper.rb +25 -0
- metadata +400 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7949dfc491925078b8d64f4b093524530d183608
|
4
|
+
data.tar.gz: d9949725cb81e568d62bd46c1be3fb28af0c2b08
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 012d1e38fab68ab65636e981b5c06861dd6acdee6e4d0d025ee9ac72b6a9c7216e3fd15e4a9b999adff35fcb706253520f78d5fda386430240ad31511d67b6a3
|
7
|
+
data.tar.gz: 496fd7162e76f218f08caaa37cb300bb3662843577c4c77f4cb31ab98e00f8f34606cab80540ba482c9bda15fc0069c429284f584c5f98bd7db0cb36e50ed462
|
data/.coveralls.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
service_name: travis-ci
|
data/.gitignore
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
23
|
+
.DS_Store
|
24
|
+
local/
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Joshua Bowers
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
# Opium
|
2
|
+
|
3
|
+
Provides an intuitive, Mongoid-inspired mapping layer between your application's object space and Parse.
|
4
|
+
|
5
|
+
[](https://travis-ci.org/joshuabowers/opium)
|
6
|
+
[](https://coveralls.io/r/joshuabowers/opium)
|
7
|
+
[](https://codeclimate.com/github/joshuabowers/opium)
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
gem 'opium'
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install opium
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
### Within Rails
|
26
|
+
|
27
|
+
Opium will automatically establish itself as the default ORM for Rails.
|
28
|
+
|
29
|
+
#### ORM Configuration
|
30
|
+
|
31
|
+
Create a config file to communicate with your Parse database by running the config generator:
|
32
|
+
|
33
|
+
```bash
|
34
|
+
$ rails g opium:config
|
35
|
+
```
|
36
|
+
|
37
|
+
See the generated file at `config/opium.yml` for more details
|
38
|
+
|
39
|
+
#### Model Generator
|
40
|
+
|
41
|
+
A generator exists for creating new models; this should be invoked whenever `rails g model` gets invoked.
|
42
|
+
|
43
|
+
```bash
|
44
|
+
$ rails g model game title:string price:float
|
45
|
+
```
|
46
|
+
|
47
|
+
### Specifying a model
|
48
|
+
|
49
|
+
Models are defined by mixing in `Opium::Model` into a new class. Class names should match the names of the
|
50
|
+
classes defined within Parse. You can define fields on your model which mirror the columns within a Parse
|
51
|
+
class.
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
class Game
|
55
|
+
include Opium::Model
|
56
|
+
|
57
|
+
field :title, type: String
|
58
|
+
field :price, type: Float
|
59
|
+
end
|
60
|
+
```
|
61
|
+
|
62
|
+
All models automatically come with three fields: *:id*, *:created_at*, and *:updated_at*. Field names are
|
63
|
+
converted from a native ruby snake_case naming convention to a Parse lowerCamel convention.
|
64
|
+
|
65
|
+
## Contributing
|
66
|
+
|
67
|
+
1. Fork it ( https://github.com/[my-github-username]/opium/fork )
|
68
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
69
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
70
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
71
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'rspec/core/rake_task'
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
|
4
|
+
# Default directory to look in is `/specs`
|
5
|
+
# Run with `rake spec`
|
6
|
+
RSpec::Core::RakeTask.new(:spec) do |task|
|
7
|
+
task.rspec_opts = %w[--color --format documentation]
|
8
|
+
end
|
9
|
+
|
10
|
+
task default: :spec
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
|
3
|
+
module Opium
|
4
|
+
module Generators
|
5
|
+
class ConfigGenerator < ::Rails::Generators::Base
|
6
|
+
source_root File.expand_path( "../templates/", __FILE__ )
|
7
|
+
|
8
|
+
desc "Creates an Opium configuration file at config/opium.yml"
|
9
|
+
|
10
|
+
def create_config_file
|
11
|
+
copy_file 'config.yml', File.join( 'config', 'opium.yml' )
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rails/generators/named_base'
|
2
|
+
|
3
|
+
module Rails
|
4
|
+
module Generators
|
5
|
+
class GeneratedAttribute
|
6
|
+
def type_class
|
7
|
+
type.to_s.camelcase
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module Opium
|
14
|
+
module Generators
|
15
|
+
class ModelGenerator < ::Rails::Generators::NamedBase
|
16
|
+
source_root File.expand_path( "../templates/", __FILE__ )
|
17
|
+
|
18
|
+
desc "Creates an Opium model"
|
19
|
+
|
20
|
+
argument :attributes, type: :array, default: [], banner: "field:type field:type"
|
21
|
+
|
22
|
+
check_class_collision
|
23
|
+
|
24
|
+
class_option :parent, type: :string, desc: "The parent model for the generated model when using STI"
|
25
|
+
|
26
|
+
def create_model_file
|
27
|
+
template "model.rb", File.join( "app/models", class_path, "#{file_name}.rb" )
|
28
|
+
end
|
29
|
+
|
30
|
+
hook_for :test_framework
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
development:
|
2
|
+
# The Application ID for your Parse app. Mandatory
|
3
|
+
app_id: PARSE-APP-ID
|
4
|
+
|
5
|
+
# The REST API key for your Parse app. Mandatory
|
6
|
+
api_key: PARSE-API-KEY
|
7
|
+
|
8
|
+
# Your Parse app's master key setting. You may omit this,
|
9
|
+
# but you will be unable to edit Users except by ACL rules
|
10
|
+
master_key: PARSE-MASTER-KEY
|
11
|
+
|
12
|
+
# Any communications done with parse will either be (true) displayed or (false) silenced
|
13
|
+
log_network_responses: true
|
14
|
+
|
15
|
+
test:
|
16
|
+
app_id: PARSE-TEST-APP-ID
|
17
|
+
api_key: PARSE-TEST-API-KEY
|
18
|
+
master_key: PARSE-TEST-MASTER-KEY
|
19
|
+
log_network_responses: true
|
20
|
+
|
21
|
+
# You could hardcode the values for the production Parse app here, but it is suggested
|
22
|
+
# you set these through the suggested environment variables.
|
23
|
+
production:
|
24
|
+
app_id: <%= ENV['PARSE_APP_ID'] %>
|
25
|
+
api_key: <%= ENV['PARSE_API_KEY'] %>
|
26
|
+
master_key: <%= ENV['PARSE_MASTER_KEY'] %>
|
27
|
+
log_network_responses: false
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<% module_namespacing do -%>
|
2
|
+
class <%= class_name %><%= " < #{options[:parent].classify}" if options[:parent] %>
|
3
|
+
<% unless options[:parent] -%>
|
4
|
+
include Opium::Model
|
5
|
+
<% end -%>
|
6
|
+
<% attributes.reject {|attr| attr.reference?}.each do |attribute| -%>
|
7
|
+
field :<%= attribute.name %><%= ", type: #{ attribute.type_class }" if attribute.type_class %>
|
8
|
+
<% end -%>
|
9
|
+
end
|
10
|
+
<% end -%>
|
data/lib/opium/config.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
module Opium
|
2
|
+
extend self
|
3
|
+
|
4
|
+
def configure
|
5
|
+
yield config
|
6
|
+
end
|
7
|
+
|
8
|
+
def config
|
9
|
+
@config ||= Opium::Config.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def load!( path, environment = nil )
|
13
|
+
settings = load_yaml( path, environment )
|
14
|
+
configure do |config|
|
15
|
+
settings.each do |key, value|
|
16
|
+
config.send("#{key}=", value)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def reset
|
22
|
+
@config = nil
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def load_yaml( path, environment = nil )
|
28
|
+
env = environment ? environment.to_s : env_name
|
29
|
+
YAML.load(ERB.new(File.new(path).read).result)[env]
|
30
|
+
end
|
31
|
+
|
32
|
+
def env_name
|
33
|
+
defined?( Rails ) ? Rails.env : ( ENV["RACK_ENV"] || ENV["OPIUM_ENV"] || raise( "Could not determine environment" ) )
|
34
|
+
end
|
35
|
+
|
36
|
+
class Config
|
37
|
+
include ActiveSupport::Configurable
|
38
|
+
|
39
|
+
config_accessor( :app_id ) { 'PARSE_APP_ID' }
|
40
|
+
config_accessor( :api_key ) { 'PARSE_API_KEY' }
|
41
|
+
config_accessor( :master_key ){ 'PARSE_MASTER_KEY' }
|
42
|
+
config_accessor( :log_network_responses ) { false }
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class Date
|
2
|
+
def to_parse
|
3
|
+
{
|
4
|
+
'__type' => 'Date',
|
5
|
+
'iso' => self.iso8601
|
6
|
+
}
|
7
|
+
end
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def to_ruby(object)
|
11
|
+
object.to_date if object
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_parse(object)
|
15
|
+
object.to_date.to_parse if object
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class DateTime < Date
|
2
|
+
def to_parse
|
3
|
+
{
|
4
|
+
'__type' => 'Date',
|
5
|
+
'iso' => self.iso8601
|
6
|
+
}
|
7
|
+
end
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def to_ruby(object)
|
11
|
+
object.to_datetime if object
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_parse(object)
|
15
|
+
object.to_datetime.to_parse if object
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class GeoPoint
|
2
|
+
def initialize( value )
|
3
|
+
self.latitude, self.longitude = *
|
4
|
+
case value
|
5
|
+
when Hash
|
6
|
+
[value[:latitude] || value['latitude'], value[:longitude] || value['longitude']]
|
7
|
+
when Array
|
8
|
+
[value.first, value.last]
|
9
|
+
else
|
10
|
+
raise ArgumentError.new( "invalid value for GeoPoint: \"#{value}\"" )
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_accessor :latitude, :longitude
|
15
|
+
|
16
|
+
def to_geo_point
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_parse
|
21
|
+
{ "__type" => "GeoPoint", "latitude" => self.latitude, "longitude" => self.longitude }
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_s
|
25
|
+
"#{self.latitude},#{self.longitude}"
|
26
|
+
end
|
27
|
+
|
28
|
+
class << self
|
29
|
+
def to_ruby(object)
|
30
|
+
object.to_geo_point unless object.nil?
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_parse(object)
|
34
|
+
object.to_geo_point.to_parse
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
class Hash
|
2
|
+
def to_geo_point
|
3
|
+
return GeoPoint.new(self) if [:latitude, :longitude].all? {|required| self.key? required}
|
4
|
+
raise ArgumentError.new( "invalid value for GeoPoint: \"#{self}\"" )
|
5
|
+
end
|
6
|
+
|
7
|
+
def to_datetime
|
8
|
+
retrieve_iso_key.to_datetime
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_date
|
12
|
+
retrieve_iso_key.to_date
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_time
|
16
|
+
retrieve_iso_key.to_time
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_parse
|
20
|
+
Hash[ *self.flat_map {|key, value| [key, value.to_parse]} ]
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def retrieve_iso_key
|
26
|
+
validates_keys_present( '__type', 'iso' )
|
27
|
+
validate_key_equals( '__type', 'Date' )
|
28
|
+
value_for_indifferent_key('iso')
|
29
|
+
end
|
30
|
+
|
31
|
+
def validates_keys_present(*expected_keys)
|
32
|
+
result = expected_keys - self.keys.map(&:to_s)
|
33
|
+
raise ArgumentError, "expected key(s): #{result}" unless result.empty?
|
34
|
+
end
|
35
|
+
|
36
|
+
def validate_key_equals( key, value )
|
37
|
+
raise ArgumentError, "conversion to Date/Time expectes a #{key} of #{value}" unless value_for_indifferent_key( key ) == value
|
38
|
+
end
|
39
|
+
|
40
|
+
def value_for_indifferent_key( key )
|
41
|
+
self[key] || self[key.to_sym]
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Opium
|
2
|
+
class Pointer
|
3
|
+
def initialize( attributes = {} )
|
4
|
+
self.class_name = attributes[:class_name] || attributes[:model_name] || (attributes[:class] || attributes[:model]).model_name
|
5
|
+
self.id = attributes[:id]
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :class_name, :id
|
9
|
+
alias_method :model_name, :class_name
|
10
|
+
|
11
|
+
def to_parse
|
12
|
+
{ __type: 'Pointer', className: class_name, objectId: id }.with_indifferent_access
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
attr_writer :class_name, :id
|
18
|
+
alias_method :model_name=, :class_name=
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class Regexp
|
2
|
+
def to_parse
|
3
|
+
{ '$regex' => self.source }.tap do |h|
|
4
|
+
ops = ''
|
5
|
+
{ IGNORECASE => 'i', MULTILINE => 'm', EXTENDED => 'x' }.each do |option, value|
|
6
|
+
ops += value unless ( self.options & option ) == 0
|
7
|
+
end
|
8
|
+
|
9
|
+
h['$options'] = ops unless ops.blank?
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class ::String
|
2
|
+
def to_bool
|
3
|
+
return true if self == true || self =~ (/^(true|t|yes|y|1)$/i)
|
4
|
+
return false if self == false || self.blank? || self =~ (/^(false|f|no|n|0)$/i)
|
5
|
+
raise ArgumentError.new("invalid value for Boolean: \"#{self}\"")
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_geo_point
|
9
|
+
return GeoPoint.new( self.split(',').map {|c| c.to_f} ) if self =~ /^[+-]?\d+(\.\d+)?\s*,\s*[+-]?\d+(\.\d+)?$/
|
10
|
+
raise ArgumentError.new("invalid value for GeoPoint: \"#{self}\"")
|
11
|
+
end
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def to_ruby(object)
|
15
|
+
object.to_s if object
|
16
|
+
end
|
17
|
+
|
18
|
+
alias_method :to_parse, :to_ruby
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class Time
|
2
|
+
def to_parse
|
3
|
+
{
|
4
|
+
'__type' => 'Date',
|
5
|
+
'iso' => self.iso8601
|
6
|
+
}
|
7
|
+
end
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def to_ruby(object)
|
11
|
+
object = object.utc if object.respond_to? :utc
|
12
|
+
object.to_time if object
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_parse(object)
|
16
|
+
object.to_time.to_parse if object
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'opium/extensions/object'
|
2
|
+
require 'opium/extensions/string'
|
3
|
+
require 'opium/extensions/numeric'
|
4
|
+
require 'opium/extensions/float'
|
5
|
+
require 'opium/extensions/integer'
|
6
|
+
require 'opium/extensions/boolean'
|
7
|
+
require 'opium/extensions/true_class'
|
8
|
+
require 'opium/extensions/false_class'
|
9
|
+
require 'opium/extensions/geo_point'
|
10
|
+
require 'opium/extensions/hash'
|
11
|
+
require 'opium/extensions/array'
|
12
|
+
require 'opium/extensions/date_time'
|
13
|
+
require 'opium/extensions/date'
|
14
|
+
require 'opium/extensions/time'
|
15
|
+
require 'opium/extensions/regexp'
|
16
|
+
require 'opium/extensions/pointer'
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Opium
|
2
|
+
module Model
|
3
|
+
module Attributable
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
include ActiveModel::ForbiddenAttributesProtection
|
8
|
+
end
|
9
|
+
|
10
|
+
def attributes
|
11
|
+
@attributes ||= self.class.default_attributes
|
12
|
+
end
|
13
|
+
|
14
|
+
def attributes=(values)
|
15
|
+
sanitize_for_mass_assignment( rubyize_field_names( values ) ).each do |k, v|
|
16
|
+
field_info = self.class.fields[k]
|
17
|
+
if field_info.present?
|
18
|
+
send( "#{k}=", v )
|
19
|
+
else
|
20
|
+
attributes[k] = v
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def attributes_to_parse( options = {} )
|
26
|
+
options[:except] ||= self.class.fields.values.select {|f| f.readonly? }.map {|f| f.name} if options[:not_readonly]
|
27
|
+
Hash[*self.as_json( options ).map {|k, v| [self.class.fields[k].name_to_parse, v.to_parse]}.flatten]
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def rubyize_field_names( hash )
|
33
|
+
Hash[*hash.map {|k, v| [self.class.ruby_canonical_field_names[k] || k, v]}.flatten]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|