structure 0.13.1 → 0.14.1

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/.travis.yml CHANGED
@@ -1,5 +1,8 @@
1
1
  rvm:
2
2
  - 1.8.7
3
3
  - 1.9.2
4
+ - 1.9.3
4
5
  - jruby
5
6
  - rbx
7
+ - rbx-2.0
8
+ - ree
data/CHANGELOG.md CHANGED
@@ -1,26 +1,36 @@
1
- # 0.13
1
+ # CHANGELOG
2
2
 
3
- * Remove static module.
4
- * Rename .key to .attribute.
3
+ ## 0.14.1
4
+ * rename .attribute back to .key
5
+ * shorten .embeds_many and .embeds_one to .many and .one
6
+ * remove presence methods
7
+ * add options to .many
5
8
 
6
- # 0.12
9
+ ## 0.13.1
7
10
 
8
- * Add static module.
11
+ * remove static module
12
+ * rename .key to .attribute
9
13
 
10
- # 0.11
14
+ # 0.12.1
11
15
 
12
- * .key now emulates DataMapper.property.
16
+ * add static module
13
17
 
14
- # 0.10
18
+ # 0.11.1
15
19
 
16
- * Rename .has_one and .has_many to .embeds_one and .embeds_many to make room
17
- for associations.
20
+ * .key now emulates DataMapper.property
21
+
22
+ # 0.10.1
23
+
24
+ * rename .has_one and .has_many to .embeds_one and .embeds_many to make room
25
+ for associations
18
26
 
19
27
  # 0.9
20
28
 
21
- * Add presence method.
29
+ * add presence method
22
30
 
23
31
  # 0.8
24
32
 
25
- * Make JSON patch compatible with Active Support.
26
- * Remove URI from list of types.
33
+ * make JSON patch compatible with Active Support
34
+ * remove URI from list of types
35
+
36
+ The rest is history.
data/Gemfile CHANGED
@@ -2,4 +2,5 @@ source :rubygems
2
2
 
3
3
  gem 'activesupport', '>= 3.0'
4
4
  gem 'json', :platform => [:mri_18, :jruby]
5
- gem 'rake', '~> 0.9'
5
+ gem 'rake'
6
+ gem 'ruby-debug19', :platform => :mri_19, :require => 'ruby-debug'
data/README.md CHANGED
@@ -1,75 +1,28 @@
1
1
  # Structure
2
2
 
3
- [![travis](https://secure.travis-ci.org/papercavalier/structure.png)](http://travis-ci.org/papercavalier/structure)
3
+ Structure is a Struct-like key/value container.
4
4
 
5
- Structure is Ruby module that turns a class into a key/value container.
5
+ [![travis](https://secure.travis-ci.org/papercavalier/structure.png)](http://travis-ci.org/papercavalier/structure)
6
6
 
7
7
  ## Usage
8
8
 
9
- Set up models.
10
-
11
- ```ruby
12
- require 'structure'
13
-
14
- class Book
15
- include Structure
16
-
17
- attribute :title
18
- attribute :binding, :default => "Hardcover"
19
- attribute :year_published, Integer
20
- embeds_many :authors
21
- end
22
-
23
- class Author
24
- include Structure
25
-
26
- attribute :name
27
- attribute :role
28
- end
29
- ```
30
-
31
- Create some objects.
32
-
33
- ```ruby
34
- book = Book.new :title => "A Thousand Plateaus"
35
- author = Author.new :name => "Gilles Deleuze"
36
- book.authors << author
37
- ```
38
-
39
- Attributes in structures are typecasted.
40
-
41
- ```ruby
42
- book.year_published = "1985"
43
- puts book.year_published
44
- => 1985
45
- ```
46
-
47
- Translate to JSON and back into Ruby.
48
-
49
- ```ruby
50
- json = book.to_json
51
- puts json
52
- => {"json_class":"Book","title":"A Thousand Plateaus","binding":"Hardcover,"year_published":1985,"authors":[{"json_class":"Author","name":"Gilles Deleuze","role":null}]}
9
+ Set up a model:
53
10
 
54
- book = JSON.parse(json)
55
- puts book.authors.first.name
56
- => "Gilles Deleuze"
57
- ```
11
+ require 'structure'
58
12
 
59
- Mix in Active Model modules.
13
+ class Person < Structure
14
+ key :name
15
+ many :friends
16
+ end
60
17
 
61
- ```ruby
62
- require 'active_model'
18
+ Do things with it:
63
19
 
64
- class Book
65
- include ActiveModel::Validations
20
+ person = Person.new
21
+ friend = Person.new
22
+ person.friends << friend
23
+ puts person.to_json
24
+ => {"json_class":"Person","name":null,"friends":[{"json_class":"Person","name":null,"friends":[]}]}
66
25
 
67
- validates_presence_of :title
68
- end
26
+ Please see [the project page] [1] for more detailed info.
69
27
 
70
- book = Book.new
71
- book.valid?
72
- => false
73
- book.errors
74
- => {:title=>["can't be blank"]}
75
- ```
28
+ [1]: http://code.papercavalier.com/structure/
@@ -1,3 +1,3 @@
1
- module Structure
2
- VERSION = '0.13.1'
1
+ class Structure
2
+ VERSION = '0.14.1'
3
3
  end
data/lib/structure.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  begin
2
- ::JSON::JSON_LOADED
2
+ JSON::JSON_LOADED
3
3
  rescue NameError
4
4
  require 'json'
5
5
  end
@@ -10,35 +10,34 @@ unless defined? Boolean
10
10
  [TrueClass, FalseClass].each { |klass| klass.send :include, Boolean }
11
11
  end
12
12
 
13
- # Structure is a Ruby module that turns a class into a key/value container.
13
+ # = Structure
14
14
  #
15
- # class Person
16
- # include Structure
15
+ # Structure is a Struct-like key/value container.
17
16
  #
18
- # attribute :name
19
- # attribute :age, Integer
17
+ # class Person < Structure
18
+ # key :name
19
+ # key :age, Integer
20
20
  # end
21
21
  #
22
22
  # person = Person.new(:name => "John")
23
23
  # person.name
24
24
  # => "John"
25
25
  #
26
- module Structure
26
+ class Structure
27
27
  include Enumerable
28
28
 
29
29
  # Structure supports the following types.
30
30
  TYPES = [Array, Boolean, Float, Hash, Integer, String, Structure]
31
31
 
32
- module ClassMethods
33
- # Defines an attribute that represents an array of objects, possibly
34
- # structures.
35
- def embeds_many(key)
36
- attribute key, Array, :default => []
32
+ class << self
33
+ # Defines an attribute that represents an array of objects.
34
+ def many(name, options = {})
35
+ key name, Array, { :default => [] }.merge(options)
37
36
  end
38
37
 
39
38
  # Defines an attribute that represents another structure.
40
- def embeds_one(key)
41
- attribute key, Structure
39
+ def one(name)
40
+ key name, Structure
42
41
  end
43
42
 
44
43
  # Builds a structure out of its JSON representation.
@@ -49,33 +48,38 @@ module Structure
49
48
 
50
49
  # Defines an attribute.
51
50
  #
52
- # Takes a key, an optional type, and an optional hash of options.
51
+ # Takes a name, an optional type, and an optional hash of options.
53
52
  #
54
53
  # The type can be +Array+, +Boolean+, +Float+, +Hash+, +Integer+, +String+,
55
- # or +Structure+. If none is specified, this defaults to String.
54
+ # a +Structure+, or a subclass thereof. If none is specified, this defaults
55
+ # to +String+.
56
56
  #
57
57
  # Available options are:
58
58
  #
59
59
  # * +:default+, which sets the default value for the attribute.
60
- def attribute(key, *args)
61
- key = key.to_sym
60
+ def key(name, *args)
61
+ name = name.to_sym
62
62
  options = args.last.is_a?(Hash) ? args.pop : {}
63
63
  type = args.shift || String
64
64
  default = options[:default]
65
65
 
66
- if method_defined? key
67
- raise NameError, "#{key} is already defined"
66
+ if method_defined? name
67
+ raise NameError, "#{name} is already defined"
68
68
  end
69
69
 
70
- if TYPES.include?(type) && (default.nil? || default.is_a?(type))
71
- default_attributes[key] = default
70
+ if (type.ancestors & TYPES).empty?
71
+ raise TypeError, "#{type} is not a valid type"
72
+ end
73
+
74
+ if default.nil? || default.is_a?(type)
75
+ default_attributes[name] = default
72
76
  else
73
77
  msg = "#{default} is not a#{'n' if type.to_s.match(/^[AI]/)} #{type}"
74
78
  raise TypeError, msg
75
79
  end
76
80
 
77
81
  module_eval do
78
- # Define a closure that typecasts value.
82
+ # Typecast value based on type.
79
83
  typecast =
80
84
  if type == Boolean
81
85
  lambda do |value|
@@ -91,8 +95,6 @@ module Structure
91
95
  end
92
96
  end
93
97
  elsif [Hash, Structure].include? type
94
- # Don't bother with typecasting attributes of type +Hash+ or
95
- # +Structure+.
96
98
  lambda do |value|
97
99
  unless value.is_a? type
98
100
  raise TypeError, "#{value} is not a #{type}"
@@ -104,15 +106,10 @@ module Structure
104
106
  end
105
107
 
106
108
  # Define attribute accessors.
107
- define_method(key) { @attributes[key] }
109
+ define_method(name) { @attributes[name] }
108
110
 
109
- define_method("#{key}=") do |value|
110
- @attributes[key] = value.nil? ? nil : typecast.call(value)
111
- end
112
-
113
- # Define a method to check for presence.
114
- unless type == Array
115
- define_method("#{key}?") { !!@attributes[key] }
111
+ define_method("#{name}=") do |value|
112
+ @attributes[name] = value.nil? ? nil : typecast.call(value)
116
113
  end
117
114
  end
118
115
  end
@@ -123,10 +120,6 @@ module Structure
123
120
  end
124
121
  end
125
122
 
126
- def self.included(base)
127
- base.extend(ClassMethods)
128
- end
129
-
130
123
  # Creates a new structure.
131
124
  #
132
125
  # A hash, if provided, will seed its attributes.
@@ -140,7 +133,7 @@ module Structure
140
133
  end
141
134
 
142
135
  # A hash that stores the attributes of the structure.
143
- attr_reader :attributes
136
+ attr :attributes
144
137
 
145
138
  # Returns a Rails-friendly JSON representation of the structure.
146
139
  def as_json(options = nil)
@@ -167,11 +160,6 @@ module Structure
167
160
  @attributes.each { |value| block.call(value) }
168
161
  end
169
162
 
170
- # Returns an array populated with the attribute keys.
171
- def keys
172
- @attributes.keys
173
- end
174
-
175
163
  # Returns a JSON representation of the structure.
176
164
  def to_json(*args)
177
165
  klass = self.class.name
@@ -180,11 +168,6 @@ module Structure
180
168
  to_json(*args)
181
169
  end
182
170
 
183
- # Returns an array populated with the attribute values.
184
- def values
185
- @attributes.values
186
- end
187
-
188
171
  # Compares this object with another object for equality. A Structure is equal
189
172
  # to the other object when latter is of the same class and the two objects'
190
173
  # attributes are the same.
data/structure.gemspec CHANGED
@@ -6,11 +6,11 @@ Gem::Specification.new do |s|
6
6
  s.name = "structure"
7
7
  s.version = Structure::VERSION
8
8
  s.platform = Gem::Platform::RUBY
9
- s.authors = ["Paper Cavalier"]
9
+ s.authors = ["Hakan Ensari"]
10
10
  s.email = ["code@papercavalier.com"]
11
11
  s.homepage = "http://code.papercavalier.com/structure"
12
- s.summary = "Turns a class into a key/value container"
13
- s.description = "Structure turns a class into a key/value container."
12
+ s.summary = "A Struct-like key/value container"
13
+ s.description = "Structure is a Struct-like key/value container."
14
14
 
15
15
  s.rubyforge_project = "structure"
16
16
 
@@ -1,134 +1,129 @@
1
+ $:.push File.expand_path('../../lib', __FILE__)
2
+
1
3
  require 'rubygems'
2
4
  require 'bundler/setup'
3
- require 'test/unit'
4
5
 
5
- require File.expand_path("../../lib/structure", __FILE__)
6
+ begin
7
+ require 'ruby-debug'
8
+ rescue LoadError
9
+ end
10
+
11
+ require 'structure'
12
+ require 'test/unit'
6
13
 
7
- class Person
8
- include Structure
14
+ class Book < Structure
15
+ key :title
16
+ key :published, Boolean, :default => true
17
+ key :pages, Integer
18
+ end
9
19
 
10
- attribute :name
11
- attribute :age, Integer
12
- attribute :married, Boolean, :default => false
13
- embeds_one :spouse
14
- embeds_many :children
20
+ class Person < Structure
21
+ key :name
22
+ one :partner
23
+ many :friends
15
24
  end
16
25
 
17
26
  class TestStructure < Test::Unit::TestCase
18
27
  def test_enumeration
19
- person = Person.new
20
- assert_respond_to(person, :map)
28
+ assert_respond_to Book.new, :map
21
29
  end
22
30
 
23
- def test_method_generation
24
- person = Person.new
25
- assert_respond_to(person, :name)
26
- assert_respond_to(person, :name=)
27
- assert_respond_to(person, :name?)
31
+ def test_accessors
32
+ book = Book.new
33
+ assert_respond_to book, :title
34
+ assert_respond_to book, :title=
28
35
  end
29
36
 
30
- def test_attribute_errors
31
- assert_raise(NameError) { Person.attribute :class }
32
- assert_raise(TypeError) { Person.attribute :foo, Object }
33
- assert_raise(TypeError) { Person.attribute :foo, :default => 1 }
37
+ def test_key_errors
38
+ assert_raise(NameError) { Book.key :class }
39
+ assert_raise(TypeError) { Book.key :foo, Object }
40
+ assert_raise(TypeError) { Book.key :foo, :default => 1 }
34
41
  end
35
42
 
36
43
  def test_default_attributes
37
- assert_equal({ :name => nil, :age => nil, :married => false, :spouse => nil, :children => [] }, Person.default_attributes)
44
+ exp = { :title => nil,
45
+ :published => true,
46
+ :pages => nil }
47
+ assert_equal exp, Book.default_attributes
38
48
  end
39
49
 
40
50
  def test_initialization
41
- person = Person.new(:name => 'John', :age => 28)
42
- assert_equal('John', person.name)
43
- assert_equal(28, person.age)
51
+ book = Book.new(:title => 'Foo', :pages => 100)
52
+ assert_equal 'Foo', book.title
53
+ assert_equal 100, book.pages
44
54
  end
45
55
 
46
56
  def test_typecasting
47
- person = Person.new
57
+ book = Book.new
48
58
 
49
- person.age = "28"
50
- assert_equal(28, person.age)
59
+ book.pages = "100"
60
+ assert_equal 100, book.pages
51
61
 
52
- person.age = nil
53
- assert_nil(person.age)
54
- end
62
+ book.pages = nil
63
+ assert_nil book.pages
55
64
 
56
- def test_presence
57
- person = Person.new
58
-
59
- person.married = nil
60
- assert(!person.married?)
61
-
62
- person.married = false
63
- assert(!person.married?)
64
-
65
- person.married = true
66
- assert(person.married?)
67
- end
68
-
69
- def test_default_type
70
- person = Person.new
71
- person.name = 1
72
- assert(person.name.is_a? String)
65
+ book.title = 1
66
+ book.title = '1'
73
67
  end
74
68
 
75
69
  def test_boolean_typecasting
76
- person = Person.new
70
+ book = Book.new
77
71
 
78
- person.married = 'false'
79
- assert(person.married == false)
72
+ book.published = 'false'
73
+ assert book.published == false
80
74
 
81
- person.married = 'FALSE'
82
- assert(person.married == false)
75
+ book.published = 'FALSE'
76
+ assert book.published == false
83
77
 
84
- person.married = '0'
85
- assert(person.married == false)
78
+ book.published = '0'
79
+ assert book.published == false
86
80
 
87
- person.married = 'foo'
88
- assert(person.married == true)
81
+ book.published = 'foo'
82
+ assert book.published == true
89
83
 
90
- person.married = 0
91
- assert(person.married == false)
84
+ book.published = 0
85
+ assert book.published == false
92
86
 
93
- person.married = 10
94
- assert(person.married == true)
87
+ book.published = 10
88
+ assert book.published == true
95
89
  end
96
90
 
97
91
  def test_defaults
98
- person = Person.new
99
- assert_equal(false, person.married)
100
- assert_equal(nil, person.name)
101
- assert_equal(nil, person.spouse)
102
- assert_equal([], person.children)
92
+ assert_equal nil, Book.new.title
93
+ assert_equal true, Book.new.published
94
+ assert_equal nil, Person.new.partner
95
+ assert_equal [], Person.new.friends
103
96
  end
104
97
 
105
98
  def test_array
106
99
  person = Person.new
107
- child = Person.new
108
- person.children << child
109
- assert_equal(1, person.children.count)
110
- assert_equal(0, child.children.count)
100
+ friend = Person.new
101
+ person.friends << person
102
+ assert_equal 1, person.friends.count
103
+ assert_equal 0, friend.friends.count
111
104
  end
112
105
 
113
106
  def test_json
114
- person = Person.new(:name => 'Joe')
115
- json = person.to_json
116
- assert_equal(person, JSON.parse(json))
107
+ book = Book.new(:title => 'Foo')
108
+ json = book.to_json
109
+ assert_equal book, JSON.parse(json)
117
110
  end
118
111
 
119
112
  def test_json_with_nested_structures
120
113
  person = Person.new
121
- person.children << Person.new
114
+ person.friends << Person.new
115
+ person.partner = Person.new
122
116
  json = person.to_json
123
- assert(JSON.parse(json).children.first.is_a? Person)
117
+ assert JSON.parse(json).friends.first.is_a? Person
118
+ assert JSON.parse(json).partner.is_a? Person
124
119
  end
125
120
 
126
121
  def test_json_with_active_support
127
122
  require 'active_support/ordered_hash'
128
123
  require 'active_support/json'
129
124
 
130
- person = Person.new
131
- assert(person.as_json(:only => :name).has_key?(:name))
132
- assert(!person.as_json(:except => :name).has_key?(:name))
125
+ book = Book.new
126
+ assert book.as_json(:only => :title).has_key?(:title)
127
+ assert !book.as_json(:except => :title).has_key?(:title)
133
128
  end
134
129
  end
metadata CHANGED
@@ -1,35 +1,24 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: structure
3
- version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 13
8
- - 1
9
- version: 0.13.1
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.14.1
5
+ prerelease:
10
6
  platform: ruby
11
- authors:
12
- - Paper Cavalier
7
+ authors:
8
+ - Hakan Ensari
13
9
  autorequire:
14
10
  bindir: bin
15
11
  cert_chain: []
16
-
17
- date: 2011-07-26 00:00:00 +01:00
18
- default_executable:
12
+ date: 2011-08-11 00:00:00.000000000Z
19
13
  dependencies: []
20
-
21
- description: Structure turns a class into a key/value container.
22
- email:
14
+ description: Structure is a Struct-like key/value container.
15
+ email:
23
16
  - code@papercavalier.com
24
17
  executables: []
25
-
26
18
  extensions: []
27
-
28
19
  extra_rdoc_files: []
29
-
30
- files:
20
+ files:
31
21
  - .gitignore
32
- - .rvmrc
33
22
  - .travis.yml
34
23
  - CHANGELOG.md
35
24
  - Gemfile
@@ -39,41 +28,33 @@ files:
39
28
  - lib/structure.rb
40
29
  - lib/structure/version.rb
41
30
  - structure.gemspec
42
- - test/models.rb
43
31
  - test/structure_test.rb
44
- has_rdoc: true
45
32
  homepage: http://code.papercavalier.com/structure
46
33
  licenses: []
47
-
48
34
  post_install_message:
49
35
  rdoc_options: []
50
-
51
- require_paths:
36
+ require_paths:
52
37
  - lib
53
- required_ruby_version: !ruby/object:Gem::Requirement
38
+ required_ruby_version: !ruby/object:Gem::Requirement
54
39
  none: false
55
- requirements:
56
- - - ">="
57
- - !ruby/object:Gem::Version
58
- hash: -2785152293474576694
59
- segments:
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ segments:
60
45
  - 0
61
- version: "0"
62
- required_rubygems_version: !ruby/object:Gem::Requirement
46
+ hash: -3339689548870644271
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
48
  none: false
64
- requirements:
65
- - - ">="
66
- - !ruby/object:Gem::Version
67
- segments:
68
- - 0
69
- version: "0"
49
+ requirements:
50
+ - - ! '>='
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
70
53
  requirements: []
71
-
72
54
  rubyforge_project: structure
73
- rubygems_version: 1.3.7
55
+ rubygems_version: 1.8.6
74
56
  signing_key:
75
57
  specification_version: 3
76
- summary: Turns a class into a key/value container
77
- test_files:
78
- - test/models.rb
58
+ summary: A Struct-like key/value container
59
+ test_files:
79
60
  - test/structure_test.rb
data/.rvmrc DELETED
@@ -1 +0,0 @@
1
- rvm --create use 1.9.2@structure
data/test/models.rb DELETED
@@ -1,8 +0,0 @@
1
- class Book
2
- include Structure
3
-
4
- key :title
5
- key :authors, Array, :value => []
6
- end
7
-
8
-