structure 0.6.0 → 0.7.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.
- data/README.md +9 -7
- data/lib/structure.rb +80 -78
- data/lib/structure/version.rb +1 -1
- data/spec/models/person.rb +1 -0
- data/spec/structure/json_spec.rb +2 -2
- data/spec/structure_spec.rb +1 -0
- data/structure.gemspec +3 -5
- metadata +6 -8
data/README.md
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
Structure
|
2
2
|
=========
|
3
3
|
|
4
|
-
Structure is a
|
4
|
+
Structure is a Struct-like key/value container for modeling ephemeral data in
|
5
|
+
Ruby.
|
5
6
|
|
6
|
-
|
7
|
+
Structure typecasts, uses basic association idioms, and converts to and from
|
8
|
+
JSON seamlessly.
|
7
9
|
|
8
10
|
#_ d
|
9
11
|
##_ d#
|
@@ -48,13 +50,13 @@ Conjure an object:
|
|
48
50
|
|
49
51
|
p1 = Person.new :name => 'Gilles'
|
50
52
|
|
51
|
-
Typecast
|
53
|
+
Typecast:
|
52
54
|
|
53
55
|
p1.age = '28'
|
54
56
|
p1.age
|
55
57
|
=> 28
|
56
58
|
|
57
|
-
Use
|
59
|
+
Use AR-like association idioms:
|
58
60
|
|
59
61
|
p2 = Person.new
|
60
62
|
p1.friends << p2
|
@@ -66,14 +68,13 @@ Dump well-structured JSON:
|
|
66
68
|
json = p1.to_json
|
67
69
|
=> {"json_class":"Person","name":"John","age":28,"friends":[{"json_class":"Person","name":null,"age":null,"friends":[]}],"partner":null}
|
68
70
|
|
69
|
-
Load the JSON
|
70
|
-
models set up:
|
71
|
+
Load the JSON seamlessly back into Ruby:
|
71
72
|
|
72
73
|
person = JSON.parse(json)
|
73
74
|
person.friends.first
|
74
75
|
=> #<Person:0x0000010107d030 @attributes={:name=>nil, :age=>nil, :friends=>[], :partner=>nil}, @modifiable=true>
|
75
76
|
|
76
|
-
Throw in some Active Model modules
|
77
|
+
Throw in some Active Model modules:
|
77
78
|
|
78
79
|
require 'active_model'
|
79
80
|
|
@@ -108,3 +109,4 @@ Structure supports the following types:
|
|
108
109
|
* Integer
|
109
110
|
* String
|
110
111
|
* Structure
|
112
|
+
* URI
|
data/lib/structure.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# A
|
1
|
+
# A Struct-like data container.
|
2
2
|
class Structure
|
3
3
|
include Enumerable
|
4
4
|
|
@@ -9,87 +9,94 @@ class Structure
|
|
9
9
|
class ::FalseClass; include Boolean; end
|
10
10
|
end
|
11
11
|
|
12
|
-
TYPES = [Array, Boolean, Float, Hash, Integer, String, Structure]
|
12
|
+
TYPES = [Array, Boolean, Float, Hash, Integer, String, Structure, URI]
|
13
13
|
|
14
|
-
|
15
|
-
# objects, possibly Structures.
|
16
|
-
def self.has_many(name)
|
17
|
-
key name, :type => Array, :default => []
|
18
|
-
end
|
19
|
-
|
20
|
-
# A shortcut to define an attribute that corresponds to another Structure.
|
21
|
-
def self.has_one(name)
|
22
|
-
key name, :type => Structure
|
23
|
-
end
|
14
|
+
class << self
|
24
15
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
# * :type, which can be Array, Boolean, Float, Hash, Integer, String, or
|
30
|
-
# Structure. If not specified, type defaults to String.
|
31
|
-
# * :default, which sets the default value for the attribute.
|
32
|
-
#
|
33
|
-
# class Book
|
34
|
-
# key :title, :type => String
|
35
|
-
# key :authors, :type => Array, :default => []
|
36
|
-
# end
|
37
|
-
#
|
38
|
-
def self.key(name, options={})
|
39
|
-
name = name.to_sym
|
40
|
-
if method_defined?(name)
|
41
|
-
raise NameError, "#{name} is already defined"
|
16
|
+
# A shortcut to define an attribute that represents an array of other
|
17
|
+
# objects, possibly structures.
|
18
|
+
def has_many(name)
|
19
|
+
key name, :type => Array, :default => []
|
42
20
|
end
|
43
21
|
|
44
|
-
|
45
|
-
|
46
|
-
|
22
|
+
# A shortcut to define an attribute that represents another structure.
|
23
|
+
def has_one(name)
|
24
|
+
key name, :type => Structure
|
47
25
|
end
|
48
26
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
27
|
+
# Defines an attribute key.
|
28
|
+
#
|
29
|
+
# Takes a name and an optional hash of options. Available options are:
|
30
|
+
#
|
31
|
+
# * :type, which can be Array, Boolean, Float, Hash, Integer, String,
|
32
|
+
# Structure, or URI. If not specified, type defaults to String.
|
33
|
+
# * :default, which sets the default value for the attribute.
|
34
|
+
#
|
35
|
+
# class Book
|
36
|
+
# key :title, :type => String
|
37
|
+
# key :authors, :type => Array, :default => []
|
38
|
+
# end
|
39
|
+
def key(name, options={})
|
40
|
+
name = name.to_sym
|
41
|
+
if method_defined?(name)
|
42
|
+
raise NameError, "#{name} is already defined"
|
43
|
+
end
|
53
44
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
# Define a proc to typecast value.
|
59
|
-
typecast =
|
60
|
-
if type == Boolean
|
61
|
-
lambda do |value|
|
62
|
-
case value
|
63
|
-
when String
|
64
|
-
value =~ /1|true/i
|
65
|
-
when Integer
|
66
|
-
value != 0
|
67
|
-
else
|
68
|
-
!!value
|
69
|
-
end
|
70
|
-
end
|
71
|
-
elsif [Hash, Structure].include? type
|
45
|
+
type = options[:type] || String
|
46
|
+
unless TYPES.include? type
|
47
|
+
raise TypeError, "#{type} is not a valid type"
|
48
|
+
end
|
72
49
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
50
|
+
default = options[:default]
|
51
|
+
unless default.nil? || default.is_a?(type)
|
52
|
+
raise TypeError, "#{default} is not #{%w{AEIOU}.include?(type.to_s[0]) ? 'an' : 'a'} #{type}"
|
53
|
+
end
|
54
|
+
|
55
|
+
default_attributes[name] = default
|
56
|
+
|
57
|
+
module_eval do
|
58
|
+
|
59
|
+
# Define a proc to typecast value.
|
60
|
+
typecast =
|
61
|
+
if type == Boolean
|
62
|
+
lambda do |value|
|
63
|
+
case value
|
64
|
+
when String
|
65
|
+
value =~ /1|true/i
|
66
|
+
when Integer
|
67
|
+
value != 0
|
68
|
+
else
|
69
|
+
!!value
|
70
|
+
end
|
71
|
+
end
|
72
|
+
elsif [Hash, Structure].include? type
|
73
|
+
|
74
|
+
# Raise an exception rather than typecast if type is Hash or
|
75
|
+
# Structure.
|
76
|
+
lambda do |value|
|
77
|
+
unless value.is_a? type
|
78
|
+
raise TypeError, "#{value} is not a #{type}"
|
79
|
+
end
|
80
|
+
value
|
78
81
|
end
|
79
|
-
|
82
|
+
else
|
83
|
+
lambda { |value| Kernel.send(type.to_s, value) }
|
80
84
|
end
|
81
|
-
else
|
82
|
-
lambda { |value| Kernel.send(type.to_s, value) }
|
83
|
-
end
|
84
85
|
|
85
|
-
|
86
|
-
|
86
|
+
# Define a getter.
|
87
|
+
define_method(name) { @attributes[name] }
|
87
88
|
|
88
|
-
|
89
|
-
|
90
|
-
|
89
|
+
# Define a setter.
|
90
|
+
define_method("#{name}=") do |value|
|
91
|
+
@attributes[name] = value.nil? ? nil : typecast.call(value)
|
92
|
+
end
|
91
93
|
end
|
92
94
|
end
|
95
|
+
|
96
|
+
# Returns a hash of all attributes with default values.
|
97
|
+
def default_attributes
|
98
|
+
@default_attributes ||= {}
|
99
|
+
end
|
93
100
|
end
|
94
101
|
|
95
102
|
# Creates a new structure.
|
@@ -126,15 +133,10 @@ class Structure
|
|
126
133
|
|
127
134
|
private
|
128
135
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
def initialize_attributes
|
134
|
-
@attributes =
|
135
|
-
self.class.default_attributes.inject({}) do |attributes, (key, value)|
|
136
|
-
attributes[key] = value.is_a?(Array) ? value.dup : value
|
137
|
-
attributes
|
136
|
+
def initialize_attributes
|
137
|
+
@attributes = {}
|
138
|
+
self.class.default_attributes.each do |key, value|
|
139
|
+
@attributes[key] = value.is_a?(Array) ? value.dup : value
|
138
140
|
end
|
139
|
-
|
141
|
+
end
|
140
142
|
end
|
data/lib/structure/version.rb
CHANGED
data/spec/models/person.rb
CHANGED
data/spec/structure/json_spec.rb
CHANGED
@@ -2,8 +2,8 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Structure do
|
4
4
|
context "when `structure/json' is required" do
|
5
|
-
let(:person) { Person.new(:name => 'Joe', :age => 28) }
|
6
|
-
let(:json) { '{"json_class":"Person","name":"Joe","age":28,"friends":[]}' }
|
5
|
+
let(:person) { Person.new(:name => 'Joe', :age => 28, :website => 'http://example.com') }
|
6
|
+
let(:json) { '{"json_class":"Person","name":"Joe","age":28,"website":"http://example.com","friends":[]}' }
|
7
7
|
|
8
8
|
before do
|
9
9
|
require 'structure/json'
|
data/spec/structure_spec.rb
CHANGED
@@ -41,6 +41,7 @@ describe Structure do
|
|
41
41
|
it "returns the default attributes for the structure" do
|
42
42
|
Person.send(:default_attributes).should == { :name => nil,
|
43
43
|
:age => nil,
|
44
|
+
:website => nil,
|
44
45
|
:friends => [] }
|
45
46
|
Book.send(:default_attributes).should == { :title => nil,
|
46
47
|
:authors => nil }
|
data/structure.gemspec
CHANGED
@@ -9,12 +9,10 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.authors = ["Paper Cavalier"]
|
10
10
|
s.email = ["code@papercavalier.com"]
|
11
11
|
s.homepage = "http://rubygems.com/gems/structure"
|
12
|
-
s.summary = "
|
12
|
+
s.summary = "Struct-like key/value container in Ruby"
|
13
13
|
s.description = <<-END_OF_DESCRIPTION.strip
|
14
|
-
Structure is a
|
15
|
-
|
16
|
-
idioms, dumps good-looking JSON, and loads the same JSON seamlessly back
|
17
|
-
into Ruby.
|
14
|
+
Structure is a Struct-like key/value container for modeling ephemeral data
|
15
|
+
in Ruby.
|
18
16
|
END_OF_DESCRIPTION
|
19
17
|
|
20
18
|
s.rubyforge_project = "structure"
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
7
|
+
- 7
|
8
8
|
- 0
|
9
|
-
version: 0.
|
9
|
+
version: 0.7.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Paper Cavalier
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-05-
|
17
|
+
date: 2011-05-29 00:00:00 +01:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -48,10 +48,8 @@ dependencies:
|
|
48
48
|
type: :development
|
49
49
|
version_requirements: *id002
|
50
50
|
description: |-
|
51
|
-
Structure is a
|
52
|
-
|
53
|
-
idioms, dumps good-looking JSON, and loads the same JSON seamlessly back
|
54
|
-
into Ruby.
|
51
|
+
Structure is a Struct-like key/value container for modeling ephemeral data
|
52
|
+
in Ruby.
|
55
53
|
email:
|
56
54
|
- code@papercavalier.com
|
57
55
|
executables: []
|
@@ -106,7 +104,7 @@ rubyforge_project: structure
|
|
106
104
|
rubygems_version: 1.3.7
|
107
105
|
signing_key:
|
108
106
|
specification_version: 3
|
109
|
-
summary:
|
107
|
+
summary: Struct-like key/value container in Ruby
|
110
108
|
test_files:
|
111
109
|
- spec/models/book.rb
|
112
110
|
- spec/models/person.rb
|