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 CHANGED
@@ -1,9 +1,11 @@
1
1
  Structure
2
2
  =========
3
3
 
4
- Structure is a better Struct.
4
+ Structure is a Struct-like key/value container for modeling ephemeral data in
5
+ Ruby.
5
6
 
6
- It works great when modeling ephemeral data fed in from an API.
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 values:
53
+ Typecast:
52
54
 
53
55
  p1.age = '28'
54
56
  p1.age
55
57
  => 28
56
58
 
57
- Use ORM-esque association idioms:
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 elsewhere into Ruby seamlessly, provided you have the same
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
@@ -1,4 +1,4 @@
1
- # A better Ruby Struct.
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
- # A shortcut to define an attribute that corresponds to an array of other
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
- # Defines an attribute key.
26
- #
27
- # Takes a name and an optional hash of options. Available options are:
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
- type = options[:type] || String
45
- unless TYPES.include? type
46
- raise TypeError, "#{type} is not a valid type"
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
- default = options[:default]
50
- unless default.nil? || default.is_a?(type)
51
- raise TypeError, "#{default} is not #{%w{AEIOU}.include?(type.to_s[0]) ? 'an' : 'a'} #{type}"
52
- end
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
- default_attributes[name] = default
55
-
56
- module_eval do
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
- # Raise an exception rather than typecast if type is Hash or
74
- # Structure.
75
- lambda do |value|
76
- unless value.is_a? type
77
- raise TypeError, "#{value} is not a #{type}"
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
- value
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
- # Define a getter.
86
- define_method(name) { @attributes[name] }
86
+ # Define a getter.
87
+ define_method(name) { @attributes[name] }
87
88
 
88
- # Define a setter.
89
- define_method("#{name}=") do |value|
90
- @attributes[name] = value.nil? ? nil : typecast.call(value)
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
- def self.default_attributes
130
- @default_attributes ||= {}
131
- end
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
- end
141
+ end
140
142
  end
@@ -1,3 +1,3 @@
1
1
  class Structure
2
- VERSION = '0.6.0'
2
+ VERSION = '0.7.0'
3
3
  end
@@ -1,5 +1,6 @@
1
1
  class Person < Structure
2
2
  key :name
3
3
  key :age, :type => Integer
4
+ key :website, :type => URI
4
5
  has_many :friends
5
6
  end
@@ -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'
@@ -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 }
@@ -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 = "A better Struct"
12
+ s.summary = "Struct-like key/value container in Ruby"
13
13
  s.description = <<-END_OF_DESCRIPTION.strip
14
- Structure is a better Struct and does wonders when modeling ephemeral data
15
- fed in from an API. It typecasts values, works with ORM-esque association
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
- - 6
7
+ - 7
8
8
  - 0
9
- version: 0.6.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-28 00:00:00 +01:00
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 better Struct and does wonders when modeling ephemeral data
52
- fed in from an API. It typecasts values, works with ORM-esque association
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: A better Struct
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