structure 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
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