betty_resource 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +8 -0
- data/CHANGELOG.rdoc +16 -0
- data/Gemfile +15 -0
- data/README.md +93 -0
- data/Rakefile +77 -0
- data/betty_resource.gemspec +27 -0
- data/lib/betty_resource/api.rb +10 -0
- data/lib/betty_resource/configuration.rb +20 -0
- data/lib/betty_resource/meta_data.rb +13 -0
- data/lib/betty_resource/model/property.rb +23 -0
- data/lib/betty_resource/model/record.rb +101 -0
- data/lib/betty_resource/model.rb +68 -0
- data/lib/betty_resource/version.rb +7 -0
- data/lib/betty_resource.rb +39 -0
- data/script/console +11 -0
- data/test/test_helper.rb +18 -0
- data/test/unit/model/test_record.rb +116 -0
- data/test/unit/test_base.rb +41 -0
- data/test/unit/test_configuration.rb +26 -0
- data/test/unit/test_model.rb +54 -0
- metadata +173 -0
data/.gitignore
ADDED
data/CHANGELOG.rdoc
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
= BettyResource CHANGELOG
|
2
|
+
|
3
|
+
=== Version 0.0.5 / 2012-03-01
|
4
|
+
|
5
|
+
* Created by Chiel
|
6
|
+
|
7
|
+
=== Version 0.0.6 / 2013-01-22
|
8
|
+
|
9
|
+
=== Version 0.0.7 / 2013-01-22
|
10
|
+
|
11
|
+
* 5 improvements:
|
12
|
+
|
13
|
+
* Add changelog generation script
|
14
|
+
* Adjust author information
|
15
|
+
* Remove some sensitive details
|
16
|
+
* We have a hard dependency on multi_json
|
data/Gemfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
gemspec
|
4
|
+
|
5
|
+
group :gem_default do
|
6
|
+
gem "betty_resource", :path => "."
|
7
|
+
gem "colorize"
|
8
|
+
gem "pry"
|
9
|
+
end
|
10
|
+
|
11
|
+
group :gem_test do
|
12
|
+
gem "minitest"
|
13
|
+
gem "mocha", :require => "mocha/setup"
|
14
|
+
gem "simplecov", ">= 0.4.0"
|
15
|
+
end
|
data/README.md
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
# BettyResource
|
2
|
+
|
3
|
+
Map Betty5 application resources to Ruby objects through the JSON API!
|
4
|
+
|
5
|
+
## Introduction
|
6
|
+
|
7
|
+
This gem is created to map resources directly to the Betty5 API with ease. Just include the gem in your Gemfile, configure the Betty5 API credentials and your good to go!
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
### Add `BettyResource` to your Gemfile
|
12
|
+
|
13
|
+
gem "betty_resource"
|
14
|
+
|
15
|
+
### Install the gem dependencies
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
### Configure the Betty5 API credentials
|
20
|
+
|
21
|
+
At first, you will need to create a user within the Betty5 application provided with an `api_password`. Ask one of the BettyBlocks developers for more information.
|
22
|
+
|
23
|
+
Afterwards, add the following in a Ruby file which gets required at startup of the application (e.g. within an `initializer`).
|
24
|
+
|
25
|
+
BettyResource.configure do |config|
|
26
|
+
config.host = "https://<identifier>.bettyblocks.com"
|
27
|
+
config.user = <user email>
|
28
|
+
config.password = <user api password>
|
29
|
+
end
|
30
|
+
|
31
|
+
## Usage
|
32
|
+
|
33
|
+
Using `BettyResource` is pretty straightforward. Let's say you want to load, edit and save a record of the `Relation` model with ID 1:
|
34
|
+
|
35
|
+
$ relation = BettyResource::Relation.get 1
|
36
|
+
$ relation.first_name = "Paul"
|
37
|
+
$ relation.save #=> true
|
38
|
+
|
39
|
+
## Using the console
|
40
|
+
|
41
|
+
The BettyResource repo is provided with `script/console` which you can use for development / testing purposes.
|
42
|
+
|
43
|
+
Run the following command in your console:
|
44
|
+
|
45
|
+
$ script/console
|
46
|
+
Loading BettyResource development environment
|
47
|
+
Configured connection
|
48
|
+
[1] pry(main)> r = BettyResource::Relation.get 1
|
49
|
+
=> #<Relation id: 1, last_name: "Willemse", first_name: "Daniel">
|
50
|
+
[2] pry(main)> r.dirty?
|
51
|
+
=> false
|
52
|
+
[3] pry(main)> r.first_name = "Paul"
|
53
|
+
=> "Paul"
|
54
|
+
[4] pry(main)> r.dirty?
|
55
|
+
=> true
|
56
|
+
[5] pry(main)> r.changes
|
57
|
+
=> {"first_name"=>["Daniel", "Paul"]}
|
58
|
+
[6] pry(main)> r.first_name_changed?
|
59
|
+
=> true
|
60
|
+
[7] pry(main)> r.first_name_change
|
61
|
+
=> ["Daniel", "Paul"]
|
62
|
+
[8] pry(main)> r.first_name_was
|
63
|
+
=> "Daniel"
|
64
|
+
[9] pry(main)> r.save
|
65
|
+
=> true
|
66
|
+
[10] pry(main)> r.dirty?
|
67
|
+
=> false
|
68
|
+
[11] pry(main)> BettyResource::Relation.get(r.id).first_name
|
69
|
+
=> "Paul"
|
70
|
+
|
71
|
+
## Testing
|
72
|
+
|
73
|
+
Run the following command for testing:
|
74
|
+
|
75
|
+
$ rake
|
76
|
+
|
77
|
+
You can also run a single test:
|
78
|
+
|
79
|
+
$ ruby test/unit/model/test_record.rb
|
80
|
+
|
81
|
+
## TODO
|
82
|
+
|
83
|
+
* Typecasting of attributes
|
84
|
+
|
85
|
+
## Contact us
|
86
|
+
|
87
|
+
For support, remarks and requests, please mail us at [support@bettyblocks.com](mailto:support@bettyblocks.com).
|
88
|
+
|
89
|
+
## License
|
90
|
+
|
91
|
+
Copyright (c) 2013 BettyBlocks B.V.
|
92
|
+
|
93
|
+
[http://bettyblocks.com](http://bettyblocks.com) - [info@bettyblocks.com](mailto:info@bettyblocks.com)
|
data/Rakefile
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rake/testtask"
|
3
|
+
|
4
|
+
task :default => :test
|
5
|
+
|
6
|
+
Rake::TestTask.new do |t|
|
7
|
+
t.test_files = FileList["test/**/test_*.rb"]
|
8
|
+
end
|
9
|
+
|
10
|
+
desc "Changelog"
|
11
|
+
task :changelog do
|
12
|
+
tag = ENV["FROM"] || `git describe --abbrev=0 --tags`.strip
|
13
|
+
range = [tag, "HEAD"].compact.join ".."
|
14
|
+
cmd = "git log --no-merges #{range} '--format=tformat:%B|||%aN|||%aE|||'"
|
15
|
+
now = Time.new.strftime "%Y-%m-%d"
|
16
|
+
|
17
|
+
changes = `#{cmd}`.split(/\|\|\|/).each_slice(3).map do |msg, author, email|
|
18
|
+
msg.split(/\n/).reject { |s| s.empty? }
|
19
|
+
end
|
20
|
+
|
21
|
+
changes = changes.flatten
|
22
|
+
|
23
|
+
next if changes.empty?
|
24
|
+
|
25
|
+
$changes = Hash.new { |h,k| h[k] = [] }
|
26
|
+
|
27
|
+
codes = {
|
28
|
+
"!" => :major,
|
29
|
+
"+" => :minor,
|
30
|
+
"*" => :minor,
|
31
|
+
"-" => :bug,
|
32
|
+
"?" => :unknown,
|
33
|
+
}
|
34
|
+
|
35
|
+
codes_re = Regexp.escape codes.keys.join
|
36
|
+
|
37
|
+
changes.each do |change|
|
38
|
+
if change =~ /^\s*([#{codes_re}])\s*(.*)/ then
|
39
|
+
code, line = codes[$1], $2
|
40
|
+
else
|
41
|
+
code, line = codes["?"], change.chomp
|
42
|
+
end
|
43
|
+
|
44
|
+
$changes[code] << line
|
45
|
+
end
|
46
|
+
|
47
|
+
puts "=== #{ENV['VERSION'] || 'NEXT'} / #{now}"
|
48
|
+
puts
|
49
|
+
changelog_section :major
|
50
|
+
changelog_section :minor
|
51
|
+
changelog_section :bug
|
52
|
+
changelog_section :unknown
|
53
|
+
puts
|
54
|
+
end
|
55
|
+
|
56
|
+
def changelog_section code
|
57
|
+
name = {
|
58
|
+
:major => "major enhancement",
|
59
|
+
:minor => "minor enhancement",
|
60
|
+
:bug => "bug fix",
|
61
|
+
:unknown => "unknown",
|
62
|
+
}[code]
|
63
|
+
|
64
|
+
changes = $changes[code]
|
65
|
+
count = changes.size
|
66
|
+
name += "s" if count > 1
|
67
|
+
name.sub!(/fixs/, 'fixes')
|
68
|
+
|
69
|
+
return if count < 1
|
70
|
+
|
71
|
+
puts "* #{count} #{name}:"
|
72
|
+
puts
|
73
|
+
changes.sort.each do |line|
|
74
|
+
puts " * #{line}"
|
75
|
+
end
|
76
|
+
puts
|
77
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'betty_resource/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "betty_resource"
|
8
|
+
gem.version = BettyResource::VERSION
|
9
|
+
gem.authors = ["Chiel Wester", "Stephan Kaag", "Daniel Willemse", "Paul Engel"]
|
10
|
+
gem.email = ["chiel.wester@holder.nl", "stephan.kaag@bettyblocks.com", "daniel.willemse@holder.nl", "paul.engel@bettyblocks.com"]
|
11
|
+
gem.description = %q{Map Betty5 application resources to Ruby objects through the JSON API}
|
12
|
+
gem.summary = %q{Map Betty5 application resources to Ruby objects}
|
13
|
+
gem.homepage = "https://github.com/bettyblocks/betty_resource"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
gem.platform = Gem::Platform::RUBY
|
20
|
+
|
21
|
+
gem.add_dependency "httparty"
|
22
|
+
gem.add_dependency "activesupport"
|
23
|
+
gem.add_dependency "crack"
|
24
|
+
gem.add_dependency "dirty_hashy", "0.1.3"
|
25
|
+
gem.add_dependency "multi_json"
|
26
|
+
gem.add_development_dependency "minitest"
|
27
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require "singleton"
|
2
|
+
|
3
|
+
module BettyResource
|
4
|
+
class Configuration
|
5
|
+
def initialize(args = {})
|
6
|
+
args.each do |key, value|
|
7
|
+
self.send("#{key}=", value) if [:host, :user, :password].include?(key.to_sym)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class InvalidError < StandardError; end
|
12
|
+
|
13
|
+
attr_accessor :host, :user, :password
|
14
|
+
|
15
|
+
def validate!
|
16
|
+
raise InvalidError if [:host, :user, :password].any?{|option| send(option).to_s.strip.empty?}
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module BettyResource
|
2
|
+
class Model
|
3
|
+
class Property
|
4
|
+
attr_accessor :id, :name, :kind, :options
|
5
|
+
|
6
|
+
def self.parse(input)
|
7
|
+
input.collect do |row|
|
8
|
+
Property.new(row["id"], row["name"], row["kind"], row["options"])
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(id, name, kind, options)
|
13
|
+
@id, @name, @kind, @options = id, name, kind, options
|
14
|
+
end
|
15
|
+
|
16
|
+
# TODO: Clean this up as this is a dirty quick fix for loading belongs_to properties at the moment
|
17
|
+
def model
|
18
|
+
BettyResource.meta_data.models.values.detect{|x| x.id == options["model"]} if kind == "belongs_to"
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module BettyResource
|
2
|
+
class Model
|
3
|
+
class Record
|
4
|
+
|
5
|
+
include DirtyAttributes::InstanceMethods
|
6
|
+
include MethodMap
|
7
|
+
attr_reader :id, :model
|
8
|
+
|
9
|
+
alias :_class :class
|
10
|
+
def class
|
11
|
+
model
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(model, attributes = {})
|
15
|
+
@model = model
|
16
|
+
@id = attributes.delete(:id) || attributes.delete("id")
|
17
|
+
@errors = {}
|
18
|
+
super()
|
19
|
+
self.attributes = Hash[model.attributes.collect{|x| [x, nil]}].merge attributes
|
20
|
+
end
|
21
|
+
|
22
|
+
def new_record?
|
23
|
+
@id.nil?
|
24
|
+
end
|
25
|
+
|
26
|
+
# TODO: Test this
|
27
|
+
def attributes=(other)
|
28
|
+
other.each do |key, value|
|
29
|
+
send "#{key}=", value
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def errors
|
34
|
+
@errors.dup
|
35
|
+
end
|
36
|
+
|
37
|
+
def save
|
38
|
+
@errors.clear
|
39
|
+
|
40
|
+
result = begin
|
41
|
+
if new_record?
|
42
|
+
Api.post("/models/#{model.id}/records/new", to_params)
|
43
|
+
else
|
44
|
+
Api.put("/models/#{model.id}/records/#{id}", to_params)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
(result.code.to_s[0..1] == "20").tap do |success|
|
49
|
+
if success
|
50
|
+
model.send :load, result.parsed_response, self
|
51
|
+
else
|
52
|
+
@errors = result.parsed_response ? result.parsed_response["errors"] : {"" => ["Er is iets mis gegaan met het verwerken van het formulier. Probeer u het later nog eens. Onze excuses voor het ongemak"]}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def inspect
|
58
|
+
inspection = "id: #{id.inspect}, #{attributes.collect{|key, value| "#{key}: #{value.inspect}"}.join(", ")}"
|
59
|
+
"#<#{model.name} #{inspection}>"
|
60
|
+
end
|
61
|
+
alias :to_s :inspect
|
62
|
+
|
63
|
+
# TODO: Test this update
|
64
|
+
def as_json(options = {})
|
65
|
+
attributes_as_json(options).merge! "id" => id
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
# TODO: Clean this mess up as this is a dirty quick fix for loading belongs_to properties at the moment
|
71
|
+
def method_missing(method, *args)
|
72
|
+
if method.to_s.match(/^(\w+).id=$/)
|
73
|
+
if model.attributes.include?($1)
|
74
|
+
instance = attributes[$1] ||= begin
|
75
|
+
if property = model.properties.detect{|x| x.name == $1}
|
76
|
+
property.model.new
|
77
|
+
end
|
78
|
+
end
|
79
|
+
if instance
|
80
|
+
return instance.instance_variable_set :@id, args.first
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
super
|
85
|
+
end
|
86
|
+
|
87
|
+
def to_params
|
88
|
+
{:body => {:record => attributes_as_json}}
|
89
|
+
end
|
90
|
+
|
91
|
+
# TODO: Test this update
|
92
|
+
def attributes_as_json(options = {})
|
93
|
+
attributes.inject({}) do |h, (k, v)|
|
94
|
+
h.merge! k => (v.respond_to?(:as_json) ? v.as_json(options) : v) if v
|
95
|
+
h
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module BettyResource
|
2
|
+
class Model
|
3
|
+
autoload :Record, "betty_resource/model/record"
|
4
|
+
autoload :Property, "betty_resource/model/property"
|
5
|
+
|
6
|
+
attr_accessor :id, :name, :properties
|
7
|
+
|
8
|
+
def self.parse(input)
|
9
|
+
input.inject({}) do |hash, row|
|
10
|
+
hash.merge(row["name"] => Model.new(row["id"], row["name"], Property.parse(row["properties"])))
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(id, name, properties = [])
|
15
|
+
@id, @name, @properties = id, name, properties
|
16
|
+
end
|
17
|
+
|
18
|
+
def attributes
|
19
|
+
properties.collect(&:name)
|
20
|
+
end
|
21
|
+
|
22
|
+
# TODO: Refactor this method in order to handle formatted view JSON correctly
|
23
|
+
def all(options = {})
|
24
|
+
begin
|
25
|
+
response = Api.get("/models/#{id}/records", :body => options).parsed_response
|
26
|
+
((view_id = options.delete(:view_id) || options.delete("view_id")).nil? ? response : response["records"]).collect do |data|
|
27
|
+
load data
|
28
|
+
end
|
29
|
+
rescue MultiJson::DecodeError
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def get(record_id)
|
34
|
+
begin
|
35
|
+
load Api.get("/models/#{id}/records/#{record_id}").parsed_response
|
36
|
+
rescue MultiJson::DecodeError
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def new(attributes = {})
|
41
|
+
BettyResource::Model::Record.new(self, attributes)
|
42
|
+
end
|
43
|
+
|
44
|
+
def create(attributes = {})
|
45
|
+
new(attributes).tap do |record|
|
46
|
+
record.save
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_s
|
51
|
+
name
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def load(data, record = nil)
|
57
|
+
if data
|
58
|
+
id = data.delete "id"
|
59
|
+
(record || BettyResource::Model::Record.new(self)).tap do |record|
|
60
|
+
record.instance_variable_set :@id, id
|
61
|
+
record.attributes = data
|
62
|
+
record.clean_up!
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require "active_support/core_ext/hash/indifferent_access" # See https://gist.github.com/1075643
|
2
|
+
|
3
|
+
require "httparty"
|
4
|
+
require "crack/json"
|
5
|
+
require "dirty_hashy"
|
6
|
+
|
7
|
+
module BettyResource
|
8
|
+
autoload :Api, "betty_resource/api"
|
9
|
+
autoload :Configuration, "betty_resource/configuration"
|
10
|
+
autoload :MetaData, "betty_resource/meta_data"
|
11
|
+
autoload :Model, "betty_resource/model"
|
12
|
+
|
13
|
+
def self.const_missing(name)
|
14
|
+
meta_data.model(name).tap do |model|
|
15
|
+
const_set(name, model)
|
16
|
+
end || super
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.meta_data
|
20
|
+
@meta_data ||= MetaData.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.config(validate = true)
|
24
|
+
(@configuration ||= Configuration.new).tap do |config|
|
25
|
+
config.validate! if validate
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.configure(configuration = nil)
|
30
|
+
if configuration
|
31
|
+
@configuration = Configuration.new(configuration).tap do |config|
|
32
|
+
config.validate!
|
33
|
+
end
|
34
|
+
else
|
35
|
+
yield config(false)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
data/script/console
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "rubygems"
|
3
|
+
require "bundler/setup"
|
4
|
+
|
5
|
+
Bundler.require :gem_default
|
6
|
+
|
7
|
+
BettyResource.configure(MultiJson.decode(File.read(File.expand_path('../../.credentials', __FILE__))))
|
8
|
+
|
9
|
+
puts "Loading BettyResource development environment (#{BettyResource::VERSION})"
|
10
|
+
puts "Configured connection with #{BettyResource.config.host}".yellow
|
11
|
+
Pry.start
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
ENV["RACK_ENV"] = "test"
|
2
|
+
ENV["TESTOPTS"] = "-v"
|
3
|
+
|
4
|
+
require "rubygems"
|
5
|
+
require "bundler/setup"
|
6
|
+
|
7
|
+
require "minitest/unit"
|
8
|
+
require "minitest/autorun"
|
9
|
+
|
10
|
+
require "simplecov"
|
11
|
+
|
12
|
+
SimpleCov.start do
|
13
|
+
coverage_dir "coverage"
|
14
|
+
add_filter "/test/"
|
15
|
+
end
|
16
|
+
|
17
|
+
Bundler.require :gem_default, :gem_test
|
18
|
+
BettyResource.configure(MultiJson.decode(File.read(File.expand_path('../../.credentials', __FILE__))))
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require_relative "../../test_helper"
|
2
|
+
|
3
|
+
module Unit
|
4
|
+
module Record
|
5
|
+
class TestRecord < MiniTest::Unit::TestCase
|
6
|
+
|
7
|
+
describe BettyResource::Model::Record do
|
8
|
+
it "should return its model" do
|
9
|
+
assert_equal BettyResource::Relation, BettyResource::Relation.new.model
|
10
|
+
assert_equal BettyResource::Relation, BettyResource::Relation.new.class
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should return its attributes" do
|
14
|
+
relation = BettyResource::Relation.new
|
15
|
+
assert_equal %w(first_name id last_name), relation.attributes.keys.sort
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should create a method for writing each attribute" do
|
19
|
+
relation = BettyResource::Relation.new
|
20
|
+
assert relation.first_name = "my_first_name"
|
21
|
+
assert relation.last_name = "my_last_name"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should create a method for reading each attribute" do
|
25
|
+
relation = BettyResource::Relation.new
|
26
|
+
relation.first_name = "my_first_name"
|
27
|
+
assert_equal "my_first_name", relation.first_name
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should store its values in the @attributes instance variable" do
|
31
|
+
relation = BettyResource::Relation.new
|
32
|
+
relation.first_name = "my_first_name"
|
33
|
+
assert_equal "my_first_name", relation.attributes[:first_name]
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should allow mass-assignment when initializing" do
|
37
|
+
relation = BettyResource::Relation.new(:first_name => "my_first_name", :last_name => "my_last_name")
|
38
|
+
assert_equal "my_first_name", relation.first_name
|
39
|
+
assert_equal "my_last_name", relation.last_name
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should allow mass-assignment when already initialized" do
|
43
|
+
relation = BettyResource::Relation.new
|
44
|
+
relation.attributes = {:first_name => "my_first_name", :last_name => "my_last_name"}
|
45
|
+
assert_equal "my_first_name", relation.first_name
|
46
|
+
assert_equal "my_last_name", relation.last_name
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should not allow setting of id" do
|
50
|
+
relation = BettyResource::Relation.get(1)
|
51
|
+
assert_equal 1, relation.id
|
52
|
+
assert relation.id = 2
|
53
|
+
assert_equal 1, relation.id
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should be able to represent itself as JSON" do
|
57
|
+
relation = BettyResource::Relation.new(:first_name => "Paul", :last_name => "Engel")
|
58
|
+
assert_equal({"id" => nil, "first_name" => "Paul", "last_name" => "Engel"}, relation.as_json)
|
59
|
+
|
60
|
+
relation = BettyResource::Relation.get(1)
|
61
|
+
assert_equal({"id" => 1, "first_name" => "Daniel", "last_name" => "Willemse"}, relation.as_json)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should save itself" do
|
65
|
+
relation = BettyResource::Relation.new(:first_name => "Stephan", :last_name => "Kaag")
|
66
|
+
assert relation.save
|
67
|
+
assert relation.id > 0
|
68
|
+
|
69
|
+
relation = BettyResource::Relation.get(relation.id)
|
70
|
+
assert_equal "Stephan", relation.first_name
|
71
|
+
assert_equal "Kaag", relation.last_name
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should not save itself when invalid (first_name is required)" do
|
75
|
+
relation = BettyResource::Relation.new
|
76
|
+
assert !relation.save
|
77
|
+
assert_equal({"first_name"=>["is_required"]}, relation.errors)
|
78
|
+
|
79
|
+
relation.first_name = "Stephan"
|
80
|
+
assert relation.save
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should have read-only errors messages" do
|
84
|
+
relation = BettyResource::Relation.create
|
85
|
+
assert_equal({"first_name"=>["is_required"]}, relation.errors)
|
86
|
+
|
87
|
+
relation.errors.clear
|
88
|
+
assert_equal({"first_name"=>["is_required"]}, relation.errors)
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should not resave itself when invalid" do
|
92
|
+
relation = BettyResource::Relation.new :first_name => "Piet"
|
93
|
+
assert relation.save
|
94
|
+
|
95
|
+
relation.first_name = ""
|
96
|
+
assert !relation.save
|
97
|
+
assert relation.id > 0
|
98
|
+
|
99
|
+
assert_equal "Piet", BettyResource::Relation.get(relation.id).first_name
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should update itself" do
|
103
|
+
relation = BettyResource::Relation.new(:first_name => "Stefan", :last_name => "Kaag")
|
104
|
+
relation.save
|
105
|
+
|
106
|
+
relation.first_name = "Stephan"
|
107
|
+
relation.save
|
108
|
+
|
109
|
+
relation = BettyResource::Relation.get(relation.id)
|
110
|
+
assert_equal "Stephan", relation.first_name
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require_relative "../test_helper"
|
2
|
+
|
3
|
+
module Unit
|
4
|
+
class TestBase < MiniTest::Unit::TestCase
|
5
|
+
|
6
|
+
describe BettyResource do
|
7
|
+
it "should validate its config" do
|
8
|
+
assert config = BettyResource.config
|
9
|
+
|
10
|
+
config.expects(:host).returns(nil)
|
11
|
+
assert_raises(BettyResource::Configuration::InvalidError) do
|
12
|
+
BettyResource.config
|
13
|
+
end
|
14
|
+
|
15
|
+
config.expects(:host).returns("")
|
16
|
+
assert_raises(BettyResource::Configuration::InvalidError) do
|
17
|
+
BettyResource.config
|
18
|
+
end
|
19
|
+
|
20
|
+
config.expects(:host).returns(" ")
|
21
|
+
assert_raises(BettyResource::Configuration::InvalidError) do
|
22
|
+
BettyResource.config
|
23
|
+
end
|
24
|
+
|
25
|
+
config.expects(:host).returns("localhost")
|
26
|
+
assert BettyResource.config
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should return a model instance" do
|
30
|
+
assert BettyResource::Relation.is_a?(BettyResource::Model)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should raise NameError when an unknown model is requested" do
|
34
|
+
assert_raises(NameError) do
|
35
|
+
assert BettyResource::DoesNotExist
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require_relative "../test_helper"
|
2
|
+
|
3
|
+
module Unit
|
4
|
+
class TestBase < MiniTest::Unit::TestCase
|
5
|
+
|
6
|
+
describe BettyResource::Configuration do
|
7
|
+
it "should be able to validate itself" do
|
8
|
+
config = BettyResource::Configuration.new
|
9
|
+
assert_raises(BettyResource::Configuration::InvalidError) do
|
10
|
+
config.validate!
|
11
|
+
end
|
12
|
+
|
13
|
+
config.host = "localhost"
|
14
|
+
assert_raises(BettyResource::Configuration::InvalidError) do
|
15
|
+
config.validate!
|
16
|
+
end
|
17
|
+
|
18
|
+
config.host = "localhost"
|
19
|
+
config.user = "foo"
|
20
|
+
config.password = "bar"
|
21
|
+
assert_nil config.validate!
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require_relative "../test_helper"
|
2
|
+
|
3
|
+
module Unit
|
4
|
+
class TestModel < MiniTest::Unit::TestCase
|
5
|
+
|
6
|
+
describe BettyResource::Model do
|
7
|
+
it "should know its properties" do
|
8
|
+
assert BettyResource::Relation.properties.is_a?(Array)
|
9
|
+
assert BettyResource::Relation.properties.any?
|
10
|
+
assert BettyResource::Relation.properties[0].is_a?(BettyResource::Model::Property)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should know its attributes" do
|
14
|
+
assert_equal %w(first_name id last_name), BettyResource::Relation.attributes.sort
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should return a new record instance" do
|
18
|
+
assert BettyResource::Relation.new.is_a?(BettyResource::Model::Record)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should not load unexisting records" do
|
22
|
+
assert_nil BettyResource::Relation.get(-1)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should fetch a record" do
|
26
|
+
relation = BettyResource::Relation.get(1)
|
27
|
+
assert_equal 1, relation.id
|
28
|
+
assert_equal "Daniel", relation.first_name
|
29
|
+
assert_equal "Willemse", relation.last_name
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should fetch multiple records" do
|
33
|
+
relations = BettyResource::Relation.all
|
34
|
+
assert_equal 100, relations.size
|
35
|
+
assert relations.first.is_a?(BettyResource::Model::Record)
|
36
|
+
|
37
|
+
relations = BettyResource::Relation.all :limit => 10
|
38
|
+
assert_equal 10, relations.size
|
39
|
+
assert relations.first.is_a?(BettyResource::Model::Record)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should directly create a record" do
|
43
|
+
relation = BettyResource::Relation.create(:first_name => "Stephan", :last_name => "Kaag")
|
44
|
+
assert relation
|
45
|
+
assert relation.id > 0
|
46
|
+
|
47
|
+
relation = BettyResource::Relation.get(relation.id)
|
48
|
+
assert_equal "Stephan", relation.first_name
|
49
|
+
assert_equal "Kaag", relation.last_name
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
metadata
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: betty_resource
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.7
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Chiel Wester
|
9
|
+
- Stephan Kaag
|
10
|
+
- Daniel Willemse
|
11
|
+
- Paul Engel
|
12
|
+
autorequire:
|
13
|
+
bindir: bin
|
14
|
+
cert_chain: []
|
15
|
+
date: 2013-01-22 00:00:00.000000000 Z
|
16
|
+
dependencies:
|
17
|
+
- !ruby/object:Gem::Dependency
|
18
|
+
name: httparty
|
19
|
+
requirement: !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ! '>='
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: '0'
|
25
|
+
type: :runtime
|
26
|
+
prerelease: false
|
27
|
+
version_requirements: !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: activesupport
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
none: false
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
type: :runtime
|
42
|
+
prerelease: false
|
43
|
+
version_requirements: !ruby/object:Gem::Requirement
|
44
|
+
none: false
|
45
|
+
requirements:
|
46
|
+
- - ! '>='
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: crack
|
51
|
+
requirement: !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ! '>='
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
type: :runtime
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ! '>='
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
- !ruby/object:Gem::Dependency
|
66
|
+
name: dirty_hashy
|
67
|
+
requirement: !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - '='
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: 0.1.3
|
73
|
+
type: :runtime
|
74
|
+
prerelease: false
|
75
|
+
version_requirements: !ruby/object:Gem::Requirement
|
76
|
+
none: false
|
77
|
+
requirements:
|
78
|
+
- - '='
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: 0.1.3
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: multi_json
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ! '>='
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
type: :runtime
|
90
|
+
prerelease: false
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
92
|
+
none: false
|
93
|
+
requirements:
|
94
|
+
- - ! '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: minitest
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ! '>='
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
type: :development
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
none: false
|
109
|
+
requirements:
|
110
|
+
- - ! '>='
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
description: Map Betty5 application resources to Ruby objects through the JSON API
|
114
|
+
email:
|
115
|
+
- chiel.wester@holder.nl
|
116
|
+
- stephan.kaag@bettyblocks.com
|
117
|
+
- daniel.willemse@holder.nl
|
118
|
+
- paul.engel@bettyblocks.com
|
119
|
+
executables: []
|
120
|
+
extensions: []
|
121
|
+
extra_rdoc_files: []
|
122
|
+
files:
|
123
|
+
- .gitignore
|
124
|
+
- CHANGELOG.rdoc
|
125
|
+
- Gemfile
|
126
|
+
- README.md
|
127
|
+
- Rakefile
|
128
|
+
- betty_resource.gemspec
|
129
|
+
- lib/betty_resource.rb
|
130
|
+
- lib/betty_resource/api.rb
|
131
|
+
- lib/betty_resource/configuration.rb
|
132
|
+
- lib/betty_resource/meta_data.rb
|
133
|
+
- lib/betty_resource/model.rb
|
134
|
+
- lib/betty_resource/model/property.rb
|
135
|
+
- lib/betty_resource/model/record.rb
|
136
|
+
- lib/betty_resource/version.rb
|
137
|
+
- script/console
|
138
|
+
- test/test_helper.rb
|
139
|
+
- test/unit/model/test_record.rb
|
140
|
+
- test/unit/test_base.rb
|
141
|
+
- test/unit/test_configuration.rb
|
142
|
+
- test/unit/test_model.rb
|
143
|
+
homepage: https://github.com/bettyblocks/betty_resource
|
144
|
+
licenses: []
|
145
|
+
post_install_message:
|
146
|
+
rdoc_options: []
|
147
|
+
require_paths:
|
148
|
+
- lib
|
149
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
150
|
+
none: false
|
151
|
+
requirements:
|
152
|
+
- - ! '>='
|
153
|
+
- !ruby/object:Gem::Version
|
154
|
+
version: '0'
|
155
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
156
|
+
none: false
|
157
|
+
requirements:
|
158
|
+
- - ! '>='
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: '0'
|
161
|
+
requirements: []
|
162
|
+
rubyforge_project:
|
163
|
+
rubygems_version: 1.8.24
|
164
|
+
signing_key:
|
165
|
+
specification_version: 3
|
166
|
+
summary: Map Betty5 application resources to Ruby objects
|
167
|
+
test_files:
|
168
|
+
- test/test_helper.rb
|
169
|
+
- test/unit/model/test_record.rb
|
170
|
+
- test/unit/test_base.rb
|
171
|
+
- test/unit/test_configuration.rb
|
172
|
+
- test/unit/test_model.rb
|
173
|
+
has_rdoc:
|