ohm-scope 0.1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 47bf355b27124d30d8e908b38b136a6ca3bdb20c
4
+ data.tar.gz: 690faf13bc68a01e92797baeb1ef471404eb80a6
5
+ SHA512:
6
+ metadata.gz: c664eccb72e07bb3216747ed10fdacc27123507f14a0af01a08e4500e65833a046722e0a07eca5b2a5220ecfa44adba52925469b368c00ba2badb0de51188368
7
+ data.tar.gz: a5bf96adecca02db629dddb969b1f5a4cac3edb3e20d29596e81665dbe7850477068aacc41e999e0c84cae1fb3d75c091113a82cf9b697347487494ad3ebc34c
data/.gems ADDED
@@ -0,0 +1,2 @@
1
+ cutest -v 1.2.3
2
+ ohm -v 3.1.1
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ .gs/
2
+ .DS_Store
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2017 Steven Weiss
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Makefile ADDED
@@ -0,0 +1,10 @@
1
+ .PHONY: test
2
+
3
+ install: .gems
4
+ gs dep install
5
+
6
+ test:
7
+ gs cutest -r ./test/all.rb
8
+
9
+ .gems:
10
+ mkdir -p .gs
data/README.md ADDED
@@ -0,0 +1,81 @@
1
+ # Ohm::Scope
2
+
3
+ Ohm::Scope wraps Ohm::Model to let you work with user
4
+ input in a way that is both safe and familiar to Ohm users.
5
+
6
+ ## Installation
7
+
8
+ `$ gem install ohm-scope`
9
+
10
+ ## Usage
11
+
12
+ Ohm::Scope implements all of Ohm::Model's public class methods while maintaining
13
+ the same contract as using Ohm::Model directly. If you're comfortable with Ohm::Model,
14
+ you should feel at home using Ohm::Scope. The one method new to Ohm::Scope
15
+ is the `#build` method. It is a factory method that delegates
16
+ to the scope's model class `::new` method by default, but also lets us
17
+ pass an argument for a different class if we want to construct something other
18
+ than a model.
19
+
20
+ ### Example
21
+
22
+ ```ruby
23
+ require 'syro'
24
+ require 'ohm'
25
+ require 'ohm/scope'
26
+
27
+ class User < Ohm::Model
28
+ collection :posts, :Post
29
+ end
30
+
31
+ class Post < Ohm::Model
32
+ attribute :title
33
+
34
+ unique :title
35
+
36
+ reference :user, :User
37
+ end
38
+
39
+ class Deck < Syro::Deck
40
+ # A convenience helper for initializing scopes.
41
+ def scope(model, user)
42
+ Ohm::Scope.new(model, { user_id: user.id })
43
+ end
44
+
45
+ # A pretend authentication solution.
46
+ def curent_user
47
+ User.with(:auth_token, req.session[:auth_token])
48
+ end
49
+ end
50
+
51
+ App = Syro.new(Deck) do
52
+ on 'posts' do
53
+ # Create a new scope that will allow the `current_user` to
54
+ # have access to only their posts.
55
+ @posts = scope(Post, current_user)
56
+
57
+ post do
58
+ # With our `@posts` scope, we can safely create new records via request params.
59
+ # The params should probably still be validated for correctness,
60
+ # but the scope protects us from the params containing a `:user_id` field
61
+ # with an id other than that of the authenticated user.
62
+ res.json @posts.create(params)
63
+ end
64
+
65
+ on :id do
66
+ # Finders are also scoped. If the url param `:id` contains
67
+ # an id for a post that doesn't belong to the authenticated user,
68
+ # our scope will return nil as if it doesn't exist.
69
+ @post = @posts[inbox[:id]]
70
+
71
+ patch do
72
+ ...
73
+ end
74
+
75
+ delete do
76
+ ...
77
+ end
78
+ end
79
+ end
80
+ end
81
+ ruby```
data/lib/ohm/scope.rb ADDED
@@ -0,0 +1,55 @@
1
+ module Ohm
2
+ class Scope
3
+ VERSION = '0.1.0'.freeze
4
+
5
+ def initialize(model, dict)
6
+ @model, @dict = model, dict
7
+ end
8
+
9
+ def create(**attributes)
10
+ build(**attributes).save
11
+ end
12
+
13
+ def build(klass = model, **attributes)
14
+ klass.new(scoped(attributes))
15
+ end
16
+
17
+ def [](id)
18
+ all[id]
19
+ end
20
+
21
+ def fetch(ids)
22
+ all.fetch(ids.select { |id| exists?(id) })
23
+ end
24
+
25
+ def with(key, val)
26
+ instance = model.with(key, val)
27
+
28
+ if instance && exists?(instance.id)
29
+ instance
30
+ else
31
+ nil
32
+ end
33
+ end
34
+
35
+ def exists?(id)
36
+ !!all[id]
37
+ end
38
+
39
+ def all
40
+ find({})
41
+ end
42
+
43
+ def find(attributes)
44
+ model.find(scoped(attributes))
45
+ end
46
+
47
+ protected
48
+
49
+ attr_reader :model, :dict
50
+
51
+ def scoped(attributes = {})
52
+ attributes.merge(dict)
53
+ end
54
+ end
55
+ end
data/ohm-scope.gemspec ADDED
@@ -0,0 +1,14 @@
1
+ require './lib/ohm/scope'
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'ohm-scope'
5
+ s.summary = 'Ohm::Scope'
6
+ s.version = Ohm::Scope::VERSION
7
+ s.authors = ['Steve Weiss']
8
+ s.email = ['weissst@mail.gvsu.edu']
9
+ s.homepage = 'https://github.com/sirscriptalot/ohm-scope'
10
+ s.license = 'MIT'
11
+ s.files = `git ls-files`.split("\n")
12
+
13
+ s.add_dependency 'ohm', '~> 3.0'
14
+ end
data/test/all.rb ADDED
@@ -0,0 +1,141 @@
1
+ require 'ostruct'
2
+ require 'ohm'
3
+ require_relative '../lib/ohm/scope'
4
+
5
+ class User < Ohm::Model
6
+ collection :posts, :Post
7
+ end
8
+
9
+ class Post < Ohm::Model
10
+ attribute :title
11
+ attribute :body
12
+
13
+ unique :title
14
+
15
+ index :body
16
+
17
+ reference :user, :User
18
+
19
+ collection :likes, :Like
20
+ end
21
+
22
+ prepare do
23
+ Ohm.flush
24
+ end
25
+
26
+ setup do
27
+ user = User.create
28
+
29
+ [Ohm::Scope.new(Post, user_id: user.id), user]
30
+ end
31
+
32
+ test '#create saves model with overridden attributes' do |posts, user|
33
+ title = 'overrides references'
34
+ post = posts.create(title: title, user: User.create)
35
+
36
+ assert post.id
37
+ assert_equal post.title, title
38
+ assert_equal post.user, user
39
+ assert_equal post.user_id, user.id
40
+
41
+ title = 'overrides ids'
42
+ post = posts.create(title: title, user_id: User.create.id)
43
+
44
+ assert post.id
45
+ assert_equal post.title, title
46
+ assert_equal post.user, user
47
+ assert_equal post.user_id, user.id
48
+ end
49
+
50
+ test '#build initializes a new instance of klass arg' do |posts, user|
51
+ klass = OpenStruct
52
+ title = 'in scope'
53
+ post = posts.build(klass, title: title)
54
+
55
+ assert !post.id
56
+ assert_equal post.class, klass
57
+ assert_equal post.title, title
58
+
59
+ post = posts.build(title: title) # klass should default to model
60
+
61
+ assert !post.id
62
+ assert_equal post.class, Post
63
+ assert_equal post.title, title
64
+ end
65
+
66
+ test '#[] queries for single record by id in scope' do |posts, user|
67
+ post = posts.create(title: 'in scope')
68
+
69
+ assert_equal posts[post.id], post
70
+
71
+ post = Post.create(title: 'out of scope')
72
+
73
+ assert_equal posts[post.id], nil
74
+ end
75
+
76
+ test '#fetch queries for many records by id in scope' do |posts, user|
77
+ collection = []
78
+
79
+ 2.times { |i| collection << posts.create(title: "in scope #{i}") }
80
+
81
+ assert_equal posts.fetch(collection.collect(&:id)), collection
82
+
83
+ collection << Post.create(title: 'out of scope')
84
+
85
+ assert posts.fetch(collection.collect(&:id)) != collection
86
+ end
87
+
88
+ test '#with queries single record by unique index in scope' do |posts, user|
89
+ title = 'in scope'
90
+ post = posts.create(title: title)
91
+
92
+ assert_equal posts.with(:title, title), post
93
+
94
+ title = 'out of scope'
95
+ Post.create(title: title)
96
+
97
+ assert_equal posts.with(:title, title), nil
98
+ end
99
+
100
+ test '#with raises for non-unique index' do |posts, user|
101
+ assert_raise(Ohm::IndexNotFound) do
102
+ posts.with(:body, 'body')
103
+ end
104
+ end
105
+
106
+ test '#exists? checks if record with id exists in scope' do |posts, user|
107
+ post = posts.create(title: 'in scope')
108
+
109
+ assert posts.exists?(post.id)
110
+
111
+ post = Post.create(title: 'out of scope')
112
+
113
+ assert !posts.exists?(post.id)
114
+ end
115
+
116
+ test '#all returns all records in scope' do |posts, user|
117
+ 2.times { |i| posts.create(title: "in scope #{i}") }
118
+
119
+ Post.create(title: 'out of scope')
120
+
121
+ assert posts.all.count > 0
122
+
123
+ posts.all.each do |post|
124
+ assert_equal post.user, user
125
+ end
126
+ end
127
+
128
+ test '#find queries for records by indexes in scope' do |posts, user|
129
+ body = 'correct body'
130
+
131
+ 2.times { |i| posts.create(title: "in scope #{i}", body: body) }
132
+
133
+ posts.create(title: 'in scope wrong body', body: 'wrong')
134
+
135
+ Post.create(title: 'out of scope correct body', body: body)
136
+
137
+ posts.find(body: body).each do |post|
138
+ assert_equal post.body, body
139
+ assert_equal post.user, user
140
+ end
141
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ohm-scope
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Steve Weiss
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-05-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ohm
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ description:
28
+ email:
29
+ - weissst@mail.gvsu.edu
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - ".gems"
35
+ - ".gitignore"
36
+ - LICENSE
37
+ - Makefile
38
+ - README.md
39
+ - lib/ohm/scope.rb
40
+ - ohm-scope.gemspec
41
+ - test/all.rb
42
+ homepage: https://github.com/sirscriptalot/ohm-scope
43
+ licenses:
44
+ - MIT
45
+ metadata: {}
46
+ post_install_message:
47
+ rdoc_options: []
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ requirements: []
61
+ rubyforge_project:
62
+ rubygems_version: 2.6.11
63
+ signing_key:
64
+ specification_version: 4
65
+ summary: Ohm::Scope
66
+ test_files: []