structure 0.13.1 → 0.14.1

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