astruct 1.0.0 → 2.7.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/.gitignore CHANGED
@@ -1,17 +1,34 @@
1
- *.gem
2
- *.rbc
3
- .bundle
4
- .config
5
- .yardoc
6
- Gemfile.lock
7
- InstalledFiles
8
- _yardoc
9
- coverage
10
- doc/
11
- lib/bundler/man
12
- pkg
13
- rdoc
14
- spec/reports
15
- test/tmp
16
- test/version_tmp
17
- tmp
1
+ # See http://help.github.com/ignore-files/ for more about ignoring files.
2
+ #
3
+ # If you find yourself ignoring temporary files generated by your text editor
4
+ # or operating system, you probably want to add a global ignore instead:
5
+ # git config --global core.excludesfile ~/.gitignore
6
+
7
+ # Ignore all of the generated gem stuff
8
+ /pkg
9
+ /*.gem
10
+
11
+ # Ignore bundler config
12
+ /.bundle
13
+ /Gemfile.lock
14
+
15
+ # Ignore all bundler caching
16
+ /vendor/cache
17
+ /vendor/ruby
18
+
19
+ # Ignore all tempfiles
20
+ /tmp
21
+
22
+ # Ignores that should be in the global gitignore
23
+ # /*.rbc
24
+ # /.config
25
+ /.yardoc
26
+ # /InstalledFiles
27
+ # /_yardoc
28
+ # /coverage/
29
+ /doc/
30
+ # /lib/bundler/man/
31
+ # /rdoc/
32
+ # /spec/reports/
33
+ # /test/tmp/
34
+ # /test/version_tmp/
data/.rvmrc ADDED
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # This is an RVM Project .rvmrc file, used to automatically load the ruby
4
+ # development environment upon cd'ing into the directory
5
+
6
+ # First we specify our desired <ruby>[@<gemset>], the @gemset name is optional,
7
+ # Only full ruby name is supported here, for short names use:
8
+ # echo "rvm use 1.9.3" > .rvmrc
9
+ environment_id="ruby-1.9.3-p194@astruct"
10
+
11
+ # Uncomment the following lines if you want to verify rvm version per project
12
+ # rvmrc_rvm_version="1.13.8 (master)" # 1.10.1 seams as a safe start
13
+ # eval "$(echo ${rvm_version}.${rvmrc_rvm_version} | awk -F. '{print "[[ "$1*65536+$2*256+$3" -ge "$4*65536+$5*256+$6" ]]"}' )" || {
14
+ # echo "This .rvmrc file requires at least RVM ${rvmrc_rvm_version}, aborting loading."
15
+ # return 1
16
+ # }
17
+
18
+ # First we attempt to load the desired environment directly from the environment
19
+ # file. This is very fast and efficient compared to running through the entire
20
+ # CLI and selector. If you want feedback on which environment was used then
21
+ # insert the word 'use' after --create as this triggers verbose mode.
22
+ if [[ -d "${rvm_path:-$HOME/.rvm}/environments"
23
+ && -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]
24
+ then
25
+ \. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
26
+ [[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]] &&
27
+ \. "${rvm_path:-$HOME/.rvm}/hooks/after_use" || true
28
+ else
29
+ # If the environment file has not yet been created, use the RVM CLI to select.
30
+ rvm --create "$environment_id" || {
31
+ echo "Failed to create RVM environment '${environment_id}'."
32
+ return 1
33
+ }
34
+ fi
35
+
36
+ # If you use bundler, this might be useful to you:
37
+ # if [[ -s Gemfile ]] && {
38
+ # ! builtin command -v bundle >/dev/null ||
39
+ # builtin command -v bundle | GREP_OPTIONS= \grep $rvm_path/bin/bundle >/dev/null
40
+ # }
41
+ # then
42
+ # printf "%b" "The rubygem 'bundler' is not installed. Installing it now.\n"
43
+ # gem install bundler
44
+ # fi
45
+ # if [[ -s Gemfile ]] && builtin command -v bundle >/dev/null
46
+ # then
47
+ # bundle install | GREP_OPTIONS= \grep -vE '^Using|Your bundle is complete'
48
+ # fi
data/Rakefile CHANGED
@@ -1,2 +1,31 @@
1
- #!/usr/bin/env rake
2
- require "bundler/gem_tasks"
1
+ #!/usr/bin/env ruby
2
+ require 'bundler/gem_tasks'
3
+ require 'rake/clean'
4
+ require 'rake/testtask'
5
+ require 'yard'
6
+
7
+ begin
8
+ Bundler.setup :default, :development
9
+ rescue Bundler::BundlerError => error
10
+ $stderr.puts error.message
11
+ $stderr.puts "Run `bundle install` to install missing gems"
12
+ exit error.status_code
13
+ end
14
+
15
+ Bundler::GemHelper.install_tasks
16
+
17
+ desc "Run all of the tests"
18
+ Rake::TestTask.new do |config|
19
+ config.libs << 'test'
20
+ config.pattern = 'test/**/*_test*'
21
+ config.verbose = true
22
+ config.warning = true
23
+ end
24
+
25
+ desc "Generate all of the docs"
26
+ YARD::Rake::YardocTask.new do |config|
27
+ config.files = Dir['lib/**/*.rb']
28
+ end
29
+
30
+ desc 'Default: run tests, and generate docs'
31
+ task :default => [ :test, :yard ]
@@ -4,9 +4,9 @@ require File.expand_path('../lib/astruct/version', __FILE__)
4
4
  Gem::Specification.new do |gem|
5
5
  gem.authors = ["Kurtis Rainbolt-Greene"]
6
6
  gem.email = ["kurtisrainboltgreene@gmail.com"]
7
- gem.description = %q{An alternative to OpenStruct}
8
7
  gem.summary = %q{An alternative to OpenStruct}
9
- gem.homepage = ""
8
+ gem.description = gem.summary
9
+ gem.homepage = "http://krainboltgreene.github.com/astruct"
10
10
 
11
11
  gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
12
12
  gem.files = `git ls-files`.split("\n")
@@ -16,10 +16,7 @@ Gem::Specification.new do |gem|
16
16
  gem.version = AltStruct::VERSION
17
17
 
18
18
  gem.add_development_dependency 'rake', '~> 0.9'
19
- gem.add_development_dependency 'rocco', '~> 0.8'
20
- gem.add_development_dependency 'redcarpet', '~> 1.0'
21
- gem.add_development_dependency 'awesome_print', '~> 1.0'
22
- gem.add_development_dependency 'guard', '~> 0.10'
23
- gem.add_development_dependency 'guard-minitest', '~> 0.4'
24
- gem.add_development_dependency 'guard-rocco', '~> 0.0.3'
19
+ gem.add_development_dependency 'yard'
20
+ gem.add_development_dependency 'kramdown'
21
+ gem.add_development_dependency 'benchmark-ips'
25
22
  end
@@ -1,36 +1,17 @@
1
- require 'benchmark'
2
- require 'astruct'
1
+ require 'benchmark/ips'
2
+ require_relative '../lib/astruct'
3
3
  require 'ostruct'
4
4
 
5
- ODATA = (1..10_000).map { |i| { :"item#{i}" => i } }.inject :merge!
6
- ADATA = (1..10_000).map { |i| { :"item#{i}" => i } }.inject :merge!
5
+ DATA = (1..1_000).map { |i| { :"item#{i}" => i } }.inject :merge!
7
6
 
8
- report = Benchmark.bmbm do |x|
7
+ Benchmark.ips do |x|
9
8
  x.report "OStruct creation" do
10
9
  class OProfile < OpenStruct; end
11
- OProfile.new ODATA
10
+ OProfile.new DATA.dup
12
11
  end
13
12
 
14
13
  x.report "AStruct creation" do
15
- class AProfile; include AltStruct; end
16
- AProfile.new ADATA
14
+ class AProfile < AltStruct; end
15
+ AProfile.new DATA.dup
17
16
  end
18
17
  end
19
-
20
- puts "Astruct is #{report.map(&:to_s).map(&:split).map(&:last).map(&:to_f).inject(:/) * 100 - 100}% faster"
21
-
22
- report = Benchmark.bmbm do |x|
23
- x.report "OStruct load" do
24
- class OProfile < OpenStruct; end
25
- op = OProfile.new
26
- op.load ODATA
27
- end
28
-
29
- x.report "AStruct load" do
30
- class AProfile; include AltStruct; end
31
- ap = AProfile.new
32
- ap.load ADATA
33
- end
34
- end
35
-
36
- puts "Astruct is #{report.map(&:to_s).map(&:split).map(&:last).map(&:to_f).inject(:/) * 100 - 100}% faster"
@@ -0,0 +1,34 @@
1
+ require 'benchmark/ips'
2
+ require_relative '../lib/astruct'
3
+ require 'ostruct'
4
+
5
+ DATA = (1..1_000).map { |i| { :"item#{i}" => i } }.inject :merge!
6
+
7
+ Benchmark.ips do |x|
8
+ x.report "OStruct load" do
9
+ class OProfile < OpenStruct; end
10
+ op = OProfile.new DATA.dup
11
+ op.op2 = OProfile.new DATA.dup
12
+ op.op2.op3 = OProfile.new DATA.dup
13
+ op.inspect
14
+ end
15
+
16
+ x.report "AStruct load" do
17
+ class AProfile < AltStruct; end
18
+ ap = AProfile.new DATA.dup
19
+ ap.ap2 = AProfile.new DATA.dup
20
+ ap.ap2.ap3 = AProfile.new DATA.dup
21
+ ap.inspect
22
+ end
23
+ end
24
+
25
+ op = OProfile.new DATA.dup
26
+ op.op2 = OProfile.new DATA.dup
27
+ op.op2.op3 = OProfile.new DATA.dup
28
+ ap = AProfile.new DATA.dup
29
+ ap.ap2 = AProfile.new DATA.dup
30
+ ap.ap2.ap3 = AProfile.new DATA.dup
31
+ p ap.inspect
32
+ p op.inspect
33
+ puts "The output of each is the same: #{ap.inspect == op.inspect}"
34
+
@@ -0,0 +1,19 @@
1
+ require 'benchmark/ips'
2
+ require_relative '../lib/astruct'
3
+ require 'ostruct'
4
+
5
+ DATA = (1..1_000).map { |i| { :"item#{i}" => i } }.inject :merge!
6
+
7
+ Benchmark.ips do |x|
8
+ x.report "OStruct load" do
9
+ class OProfile < OpenStruct; end
10
+ op = OProfile.new DATA.dup
11
+ op.delete_field :item1
12
+ end
13
+
14
+ x.report "AStruct load" do
15
+ class AProfile < AltStruct; end
16
+ ap = AProfile.new DATA.dup
17
+ ap.delete :item1
18
+ end
19
+ end
@@ -0,0 +1,25 @@
1
+ require 'benchmark/ips'
2
+ require_relative '../lib/astruct'
3
+ require 'ostruct'
4
+
5
+ DATA = (1..1_000).map { |i| { :"item#{i}" => i } }.inject :merge!
6
+
7
+ Benchmark.ips do |x|
8
+ x.report "OStruct load" do
9
+ class OProfile < OpenStruct; end
10
+ op = OProfile.new DATA.dup
11
+ op.marshal_dump
12
+ end
13
+
14
+ x.report "AStruct load" do
15
+ class AProfile < AltStruct; end
16
+ ap = AProfile.new DATA.dup
17
+ ap.dump
18
+ end
19
+ end
20
+
21
+ class OProfile < OpenStruct; end
22
+ op = OProfile.new DATA.dup
23
+ class AProfile < AltStruct; end
24
+ ap = AProfile.new DATA.dup
25
+ puts "The output of each is the same: #{ap.dump == op.marshal_dump}"
@@ -0,0 +1,23 @@
1
+ require 'benchmark/ips'
2
+ require_relative '../lib/astruct'
3
+ require 'ostruct'
4
+
5
+ DATA = (1..1_000).map { |i| { :"item#{i}" => i } }.inject :merge!
6
+
7
+ Benchmark.ips do |x|
8
+ x.report "OStruct creation" do
9
+ class OProfile < OpenStruct; end
10
+ op = OProfile.new DATA.dup
11
+ op.example1 = "red"
12
+ op.example2 = "blue"
13
+ op.example3 = "green"
14
+ end
15
+
16
+ x.report "AStruct creation" do
17
+ class AProfile < AltStruct; end
18
+ ap = AProfile.new DATA.dup
19
+ ap.example1 = "red"
20
+ ap.example2 = "blue"
21
+ ap.example3 = "green"
22
+ end
23
+ end
@@ -0,0 +1,19 @@
1
+ require 'benchmark/ips'
2
+ require_relative '../lib/astruct'
3
+ require 'ostruct'
4
+
5
+ DATA = (1..1_000).map { |i| { :"item#{i}" => i } }.inject :merge!
6
+
7
+ Benchmark.ips do |x|
8
+ x.report "OStruct load" do
9
+ class OProfile < OpenStruct; end
10
+ op = OProfile.new DATA.dup
11
+ op.inspect
12
+ end
13
+
14
+ x.report "AStruct load" do
15
+ class AProfile < AltStruct; end
16
+ ap = AProfile.new DATA.dup
17
+ ap.inspect
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ require 'benchmark/ips'
2
+ require_relative '../lib/astruct'
3
+ require 'ostruct'
4
+
5
+ DATA = (1..1_000).map { |i| { :"item#{i}" => i } }.inject :merge!
6
+
7
+ Benchmark.ips do |x|
8
+ x.report "OStruct load" do
9
+ class OProfile < OpenStruct; end
10
+ op = OProfile.new
11
+ op.marshal_load DATA.dup
12
+ end
13
+
14
+ x.report "AStruct load" do
15
+ class AProfile < AltStruct; end
16
+ ap = AProfile.new
17
+ ap.load DATA.dup
18
+ end
19
+ end
@@ -1,30 +1,94 @@
1
- module AltStruct
2
- attr_reader :table
3
-
4
- def initialize(pairs = {})
5
- @table ||= {}
6
- for key, value in pairs
7
- @table.merge! define_accessor key.to_sym, value
8
- end unless pairs == {}
9
- end
10
-
11
- def define_accessor(key, value)
12
- define_singleton_method(key) { @table[key] }
13
- define_singleton_method(:"#{key}=") { |v| @table[key] = v }
14
- { key => value }.freeze
15
- end
16
-
17
- def load(pairs)
18
- for key, value in pairs
19
- @table.merge! define_accessor key.to_sym, value
20
- end unless pairs == {}
21
- end
22
-
23
- def dump(*keys)
24
- if keys == [] then @table else @table.keep_if { |k| keys.include? k } end
25
- end
26
-
27
- def inspect
28
- "#<#{self.class}:#{object_id} #{dump.map { |k,v| "#{k}=#{v.inspect}" }.join ' '}>"
29
- end
1
+ require_relative 'astruct/module'
2
+
3
+ #
4
+ # = astruct.rb: AltStruct implementation
5
+ #
6
+ # Author:: Kurtis Rainbolt-Greene
7
+ # Documentation:: Kurtis Rainbolt-Greene
8
+ #
9
+ # AltStruct is an Class and Module (AltStruct::M) that can be used to
10
+ # create hash-like classes. Allowing you to create an object that can
11
+ # dynamically accept accessors and behaves very much like a Hash.
12
+ #
13
+
14
+ #
15
+ # An AltStruct is a data structure, similar to a Hash, that allows the
16
+ # definition of arbitrary attributes with their accompanying values. This is
17
+ # accomplished by using Ruby's metaprogramming to define methods on the class
18
+ # itself.
19
+ #
20
+
21
+ #
22
+ # == Examples:
23
+ #
24
+ # require 'astruct'
25
+ #
26
+ # class Profile < AltStruct
27
+ #
28
+ # end
29
+ #
30
+ # person = Profile.new name: "John Smith"
31
+ # person.age = 70
32
+ #
33
+ # puts person.name # => "John Smith"
34
+ # puts person.age # => 70
35
+ # puts person.dump # => { :name => "John Smith", :age => 70 }
36
+ #
37
+
38
+ #
39
+ # An AltStruct employs a Hash internally to store the methods and values and
40
+ # can even be initialized with one:
41
+ #
42
+ # australia = AltStruct.new country: "Australia", population: 20_000_000
43
+ # puts australia.inspect # => <AltStruct country="Australia", population=20000000>
44
+ #
45
+
46
+ #
47
+ # Hash keys with spaces or characters that would normally not be able to use for
48
+ # method calls (e.g. ()[]*) will not be immediately available on the
49
+ # AltStruct object as a method for retrieval or assignment, but can be still be
50
+ # reached through the Object#send method.
51
+ #
52
+ # measurements = AltStruct.new "length (in inches)" => 24
53
+ # measurements.send "length (in inches)" # => 24
54
+ #
55
+ # data_point = AltStruct.new :queued? => true
56
+ # data_point.queued? # => true
57
+ # data_point.send "queued?=", false
58
+ # data_point.queued? # => false
59
+ #
60
+
61
+ #
62
+ # Removing the presence of a method requires the execution the delete_field
63
+ # or delete (like a hash) method as setting the property value to +nil+
64
+ # will not remove the method.
65
+ #
66
+ # first_pet = AltStruct.new :name => 'Rowdy', :owner => 'John Smith'
67
+ # first_pet.owner = nil
68
+ # second_pet = AltStruct.new :name => 'Rowdy'
69
+ #
70
+ # first_pet == second_pet # -> false
71
+ #
72
+ # first_pet.delete_field(:owner)
73
+ # first_pet == second_pet # -> true
74
+ #
75
+
76
+ #
77
+ # == Implementation:
78
+ #
79
+ # An AltStruct utilizes Ruby's method lookup structure to and find and define
80
+ # the necessary methods for properties. This is accomplished through the method
81
+ # method_missing and define_method.
82
+ #
83
+
84
+ #
85
+ # This should be a consideration if there is a concern about the performance of
86
+ # the objects that are created, as there is much more overhead in the setting
87
+ # of these properties compared to using a Hash or a Struct.
88
+ #
89
+ class AltStruct
90
+ # We include all of the AltStruct::M Module in order to give AltStruct
91
+ # the same behavior as OpenStruct. It's better, however, to simply
92
+ # include AltStruct::M into your own class.
93
+ include AltStruct::M
30
94
  end
@@ -0,0 +1,151 @@
1
+ class AltStruct
2
+ module M
3
+ ThreadKey = :__inspect_astruct_ids__ # :nodoc:
4
+ attr_reader :table
5
+
6
+ # Create a new field for each of the key/value pairs passed.
7
+ # By default the resulting OpenStruct object will have no
8
+ # attributes. If no pairs are passed avoid any work.
9
+ #
10
+ # require 'ostruct'
11
+ # hash = { "country" => "Australia", :population => 20_000_000 }
12
+ # data = OpenStruct.new hash
13
+ #
14
+ # p data # => <OpenStruct country="Australia" population=20000000>
15
+ #
16
+ # If you happen to be inheriting then you can define your own
17
+ # @table ivar before the `super()` call. AltStruct will respect
18
+ # your @table.
19
+ #
20
+ def initialize(pairs = {})
21
+ @table ||= {}
22
+ for key, value in pairs
23
+ __new_field__ key, value
24
+ end unless pairs.empty?
25
+ end
26
+
27
+ # This is the `load()` method, which works like initialize in that it
28
+ # will create new fields for each pair passed. Notice that it
29
+ # also is a double-underbar method, making it really hard to
30
+ # overwrite. It also mimics the behavior of a Hash#merge and
31
+ # Hash#merge!
32
+ def __load__(pairs)
33
+ for key, value in pairs
34
+ __new_field__ key, value
35
+ end unless pairs.empty?
36
+ end
37
+ alias_method :marshal_load, :__load__
38
+ alias_method :load, :__load__
39
+ alias_method :merge, :__load__
40
+ alias_method :merge!, :__load__
41
+
42
+ # The `dump()` takes the table and out puts in it's natural hash
43
+ # format. In addition you can pass along a specific set of keys to
44
+ # dump.
45
+ def __dump__(*keys)
46
+ keys.empty? ? table : __dump_specific__(keys)
47
+ end
48
+ alias_method :marshal_dump, :__dump__
49
+ alias_method :dump, :__dump__
50
+ alias_method :to_hash, :__dump__
51
+
52
+ def __inspect__
53
+ "#<#{self.class}#{__dump_inspect__}>"
54
+ end
55
+ alias_method :inspect, :__inspect__
56
+ alias_method :to_s, :__inspect__
57
+
58
+ # The delete_field() method removes a key/value pair on the @table
59
+ # and on the singleton class. It also mimics the Hash#delete method.
60
+ def __delete_field__(key)
61
+ singleton_class.send :remove_method, key
62
+ singleton_class.send :remove_method, :"#{key}="
63
+ @table.delete key
64
+ end
65
+ alias_method :delete_field, :__delete_field__
66
+ alias_method :delete, :__delete_field__
67
+
68
+ # The `method_missing()` method catches all non-tabled method calls.
69
+ # The AltStruct object will return two specific errors depending on
70
+ # the call.
71
+ def method_missing(method, *args)
72
+ name = method.to_s
73
+ case
74
+ when !name.include?('=')
75
+ # This is to catch non-assignment methods
76
+ message = "undefined method `#{name}' for #{self}"
77
+ raise NoMethodError, message, caller(1)
78
+ when args.size != 1
79
+ # This is to catch the []= method
80
+ message = "wrong number of arguments (#{args.size} for 1)"
81
+ raise ArgumentError, message, caller(1)
82
+ else
83
+ __new_field__ name.chomp!('='), args.first
84
+ end
85
+ end
86
+
87
+ def ==(object)
88
+ if object.respond_to? :table
89
+ table == object.table
90
+ else
91
+ false
92
+ end
93
+ end
94
+
95
+ def freeze
96
+ super
97
+ @table.freeze
98
+ end
99
+
100
+ private
101
+
102
+ def __dump_inspect__
103
+ __create_id_list__
104
+ unless __id_exists_in_id_list?
105
+ __add_id_to_id_list__
106
+ string = __dump__.any? ? " #{__dump_string__.join ', '}" : ""
107
+ else
108
+ __remove_last_id_from_id_list__
109
+ string = __dump__.any? ? " ..." : ""
110
+ end
111
+ __remove_last_id_from_id_list__
112
+ string
113
+ end
114
+
115
+ def __define_accessor__(key, value)
116
+ define_singleton_method(key) { @table[key] }
117
+ define_singleton_method(:"#{key}=") { |v| @table[key] = v }
118
+ { key => value }.freeze
119
+ end
120
+
121
+ def __new_field__(key, value)
122
+ table.merge! __define_accessor__ key.to_sym, value
123
+ end
124
+
125
+ def __dump_specific__(keys)
126
+ @table.keep_if { |key| keys.include? key }
127
+ end
128
+
129
+ def __dump_string__
130
+ __dump__.map do |key, value|
131
+ "#{key}=#{value.inspect}"
132
+ end
133
+ end
134
+
135
+ def __add_id_to_id_list__
136
+ Thread.current[ThreadKey] << object_id
137
+ end
138
+
139
+ def __create_id_list__
140
+ Thread.current[ThreadKey] ||= []
141
+ end
142
+
143
+ def __id_exists_in_id_list?
144
+ Thread.current[ThreadKey].include?(object_id)
145
+ end
146
+
147
+ def __remove_last_id_from_id_list__
148
+ Thread.current[ThreadKey].pop
149
+ end
150
+ end
151
+ end
@@ -1,3 +1,4 @@
1
- module AltStruct
2
- VERSION = "1.0.0"
1
+ class AltStruct
2
+ # This is the AltStruct version
3
+ VERSION = "2.7.1"
3
4
  end
@@ -0,0 +1 @@
1
+ require 'astruct'
@@ -0,0 +1,236 @@
1
+ require 'minitest/autorun'
2
+ require_relative '../helper'
3
+
4
+ class TestAltStruct < MiniTest::Unit::TestCase
5
+ def setup
6
+ @empty = AltStruct.new
7
+ @example = AltStruct.new name: "Kurtis", age: 24
8
+ end
9
+
10
+ def test_equality_with_two_empty_astructs
11
+ empty2 = AltStruct.new
12
+ assert_equal @empty, empty2
13
+ end
14
+
15
+ def test_equality_vs_astruct_with_fields
16
+ refute_equal @example, @empty
17
+ end
18
+
19
+ def test_equality_vs_object_with_fake_table
20
+ empty_object = Object.new
21
+ empty_object.instance_eval { @table = { name: "Kurtis", age: 24 } }
22
+ expected = @example
23
+ actual = empty_object
24
+ refute_equal expected, actual
25
+ end
26
+
27
+ def test_inspect_with_no_fields
28
+ expected = "#<AltStruct>"
29
+ actual = @empty.inspect
30
+ assert_equal expected, actual
31
+ end
32
+
33
+ def test_inspect_with_fields
34
+ @empty.example1 = 1
35
+ @empty.example2 = 2
36
+ expected = "#<AltStruct example1=1, example2=2>"
37
+ actual = @empty.inspect
38
+ assert_equal expected, actual
39
+ end
40
+
41
+ def test_inspect_with_sub_struct_duplicate
42
+ @empty.struct2 = AltStruct.new
43
+ @empty.struct2.struct3 = @empty
44
+ expected = '#<AltStruct struct2=#<AltStruct struct3=#<AltStruct ...>>>'
45
+ actual = @empty.inspect
46
+ assert_equal expected, actual
47
+ end
48
+
49
+ def test_inspect_with_sub_struct
50
+ @example.friends = AltStruct.new name: "Jason", age: 24
51
+ @example.friends.friends = AltStruct.new name: "John", age: 15
52
+ @example.friends.friends.friends = AltStruct.new name: "Ally", age: 32
53
+ expected = '#<AltStruct name="Kurtis", age=24, friends=#<AltStruct name="Jason", age=24, friends=#<AltStruct name="John", age=15, friends=#<AltStruct name="Ally", age=32>>>>'
54
+ actual = @example.inspect
55
+ assert_equal expected, actual
56
+ end
57
+
58
+ def test_inspect_with_twice_inspected_struct
59
+ @example.inspect
60
+ @example.inspect
61
+ expected = '#<AltStruct name="Kurtis", age=24>'
62
+ actual = @example.inspect
63
+ assert_equal expected, actual
64
+ end
65
+
66
+ def test_inspect_with_empty_sub_struct
67
+ @empty.struct2 = AltStruct.new
68
+ expected = '#<AltStruct struct2=#<AltStruct>>'
69
+ actual = @empty.inspect
70
+ assert_equal expected, actual
71
+ end
72
+
73
+ def test_freeze_stops_new_assignments
74
+ @example.freeze
75
+ assert_raises(RuntimeError) { @example.age = 24 }
76
+ end
77
+
78
+ def test_freeze_still_returns_values
79
+ @example.freeze
80
+ expecteds = "Kurtis"
81
+ actual = @example.name
82
+ assert_equal expecteds, actual
83
+ end
84
+
85
+ def test_freeze_stops_reassignments
86
+ @example.freeze
87
+ assert_raises(RuntimeError) { @example.name = "Jazzy" }
88
+ end
89
+
90
+ # def test_freeze_stops_reassign_even_if_frozen_redefined
91
+ # @example.freeze
92
+ # def @example.frozen?; nil end
93
+ # @example.freeze
94
+ # message = '[ruby-core:22559]'
95
+ # assert_raises(RuntimeError, message) { @example.name = "Jazzy" }
96
+ # # assert_raises(TypeError, message) { @example.name = "Jazzy" }
97
+ # end
98
+
99
+ def test_astruct_doesn_respond_to_non_existant_keys_getter
100
+ refute_respond_to @empty, :akey
101
+ end
102
+
103
+ def test_astruct_doesn_respond_to_non_existant_keys_setter
104
+ refute_respond_to @empty, :akey=
105
+ end
106
+
107
+ def test_delete_field_removes_getter_method
108
+ bug = '[ruby-core:33010]'
109
+ @example.delete_field :name
110
+ refute_respond_to @example, :name, bug
111
+ end
112
+
113
+ def test_delete_field_removes_setter_method
114
+ bug = '[ruby-core:33010]'
115
+ @example.delete_field :name
116
+ refute_respond_to @example, :name=, bug
117
+ end
118
+
119
+ def test_delete_field_removes_table_key_value
120
+ @example.delete_field :name
121
+ expected = nil
122
+ actual = @example.table[:name]
123
+ assert_equal expected, actual
124
+ end
125
+
126
+ def test_delete_field_returns_value_of_deleted_key
127
+ expected = "Kurtis"
128
+ actual = @example.delete_field :name
129
+ assert_equal expected, actual
130
+ end
131
+
132
+ def test_method_missing_handles_square_bracket_equals
133
+ assert_raises(ArgumentError) { @empty[:foo] = :bar }
134
+ end
135
+
136
+ def test_method_missing_handles_square_brackets
137
+ assert_raises(NoMethodError) { @empty[:foo] }
138
+ end
139
+
140
+ def test_to_hash_returns_hash
141
+ expected = { name: "John Smith", age: 70, pension: 300 }
142
+ actual = AltStruct.new(expected).to_hash
143
+ assert_equal expected, actual
144
+ end
145
+
146
+ def test_to_hash_modified_modifies_astruct
147
+ @example.to_hash[:age] = 70
148
+ expected = 70
149
+ actual = @example.age
150
+ assert_equal expected, actual
151
+ end
152
+
153
+ def test_example_has_table_method
154
+ assert_respond_to @example, :table
155
+ end
156
+
157
+ def test_empty_example_has_empty_table
158
+ expected = {}
159
+ actual = @empty.table
160
+ assert_equal expected, actual
161
+ end
162
+
163
+ def test_example_has_name_method
164
+ assert_respond_to @example, :name
165
+ end
166
+
167
+ def test_example_has_given_name
168
+ expected = "Kurtis"
169
+ actual = @example.name
170
+ assert_equal expected, actual
171
+ end
172
+
173
+ def test_example_takes_name
174
+ assert_send [@example, :name=, "Dave"]
175
+ end
176
+
177
+ def test_example_has_taken_name
178
+ @example.name = "Dave"
179
+ expected = "Dave"
180
+ actual = @example.name
181
+ assert_equal expected, actual
182
+ end
183
+
184
+ def test_load_takes_a_hash
185
+ assert_send [@example, :load, { nickname: "Kurt" }]
186
+ end
187
+
188
+ def test_load_sets_methods
189
+ @example.load nickname: "Kurt"
190
+ assert_respond_to @example, :nickname
191
+ end
192
+
193
+ def test_astruct_has_getter_methods_with_non_alpha_numeric_characters
194
+ @example.load "Length (In Inchs)" => 72
195
+ assert_send [@example, :"Length (In Inchs)"]
196
+ end
197
+
198
+ def test_astruct_has_getter_methods_with_non_alpha_numeric_characters
199
+ @example.load "Length (In Inchs)" => 72
200
+ assert_send [@example, :"Length (In Inchs)=", 73]
201
+ end
202
+
203
+ def test_load_sets_correct_value
204
+ @example.load nickname: "Kurt"
205
+ expected = "Kurt"
206
+ actual = @example.nickname
207
+ assert_equal expected, actual
208
+ end
209
+
210
+ def test_example_has_dump_method
211
+ assert_respond_to @example, :dump
212
+ end
213
+
214
+ def test_dump_contains_values
215
+ expected = { name: "Kurtis", age: 24 }
216
+ actual = @example.dump
217
+ assert_equal expected, actual
218
+ end
219
+
220
+ def test_selective_dump_contains_selective_values
221
+ expected = { age: 24 }
222
+ actual = @example.dump :age
223
+ assert_equal expected, actual
224
+ end
225
+
226
+ def test_inspect_has_values_delimited_by_comma
227
+ expected = /name="Kurtis", age=24/
228
+ actual = @example.inspect
229
+ assert_match expected, actual
230
+ end
231
+
232
+ def test_other_object_isnt_affected
233
+ refute_respond_to @empty, :name
234
+ end
235
+ end
236
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: astruct
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.7.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-01-30 00:00:00.000000000 Z
12
+ date: 2012-08-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
16
- requirement: &2161261360 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,73 +21,60 @@ dependencies:
21
21
  version: '0.9'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *2161261360
25
- - !ruby/object:Gem::Dependency
26
- name: rocco
27
- requirement: &2161260360 !ruby/object:Gem::Requirement
24
+ version_requirements: !ruby/object:Gem::Requirement
28
25
  none: false
29
26
  requirements:
30
27
  - - ~>
31
28
  - !ruby/object:Gem::Version
32
- version: '0.8'
33
- type: :development
34
- prerelease: false
35
- version_requirements: *2161260360
29
+ version: '0.9'
36
30
  - !ruby/object:Gem::Dependency
37
- name: redcarpet
38
- requirement: &2161259760 !ruby/object:Gem::Requirement
31
+ name: yard
32
+ requirement: !ruby/object:Gem::Requirement
39
33
  none: false
40
34
  requirements:
41
- - - ~>
35
+ - - ! '>='
42
36
  - !ruby/object:Gem::Version
43
- version: '1.0'
37
+ version: '0'
44
38
  type: :development
45
39
  prerelease: false
46
- version_requirements: *2161259760
47
- - !ruby/object:Gem::Dependency
48
- name: awesome_print
49
- requirement: &2161259300 !ruby/object:Gem::Requirement
40
+ version_requirements: !ruby/object:Gem::Requirement
50
41
  none: false
51
42
  requirements:
52
- - - ~>
43
+ - - ! '>='
53
44
  - !ruby/object:Gem::Version
54
- version: '1.0'
55
- type: :development
56
- prerelease: false
57
- version_requirements: *2161259300
45
+ version: '0'
58
46
  - !ruby/object:Gem::Dependency
59
- name: guard
60
- requirement: &2161258840 !ruby/object:Gem::Requirement
47
+ name: kramdown
48
+ requirement: !ruby/object:Gem::Requirement
61
49
  none: false
62
50
  requirements:
63
- - - ~>
51
+ - - ! '>='
64
52
  - !ruby/object:Gem::Version
65
- version: '0.10'
53
+ version: '0'
66
54
  type: :development
67
55
  prerelease: false
68
- version_requirements: *2161258840
69
- - !ruby/object:Gem::Dependency
70
- name: guard-minitest
71
- requirement: &2161238500 !ruby/object:Gem::Requirement
56
+ version_requirements: !ruby/object:Gem::Requirement
72
57
  none: false
73
58
  requirements:
74
- - - ~>
59
+ - - ! '>='
75
60
  - !ruby/object:Gem::Version
76
- version: '0.4'
77
- type: :development
78
- prerelease: false
79
- version_requirements: *2161238500
61
+ version: '0'
80
62
  - !ruby/object:Gem::Dependency
81
- name: guard-rocco
82
- requirement: &2161237800 !ruby/object:Gem::Requirement
63
+ name: benchmark-ips
64
+ requirement: !ruby/object:Gem::Requirement
83
65
  none: false
84
66
  requirements:
85
- - - ~>
67
+ - - ! '>='
86
68
  - !ruby/object:Gem::Version
87
- version: 0.0.3
69
+ version: '0'
88
70
  type: :development
89
71
  prerelease: false
90
- version_requirements: *2161237800
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
91
78
  description: An alternative to OpenStruct
92
79
  email:
93
80
  - kurtisrainboltgreene@gmail.com
@@ -96,6 +83,7 @@ extensions: []
96
83
  extra_rdoc_files: []
97
84
  files:
98
85
  - .gitignore
86
+ - .rvmrc
99
87
  - Gemfile
100
88
  - Guardfile
101
89
  - LICENSE
@@ -103,11 +91,18 @@ files:
103
91
  - Rakefile
104
92
  - astruct.gemspec
105
93
  - benchmark/basic_vs_ostruct.rb
94
+ - benchmark/deep_inspect_vs_ostruct.rb
95
+ - benchmark/delete_vs_ostruct.rb
96
+ - benchmark/dump_vs_ostruct.rb
97
+ - benchmark/dynamic_vs_ostruct
98
+ - benchmark/inspect_vs_ostruct.rb
99
+ - benchmark/load_vs_ostruct.rb
106
100
  - lib/astruct.rb
101
+ - lib/astruct/module.rb
107
102
  - lib/astruct/version.rb
108
- - test/test_astruct.rb
109
- - test/test_helper.rb
110
- homepage: ''
103
+ - test/helper.rb
104
+ - test/lib/astruct_test.rb
105
+ homepage: http://krainboltgreene.github.com/astruct
111
106
  licenses: []
112
107
  post_install_message:
113
108
  rdoc_options: []
@@ -121,7 +116,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
121
116
  version: '0'
122
117
  segments:
123
118
  - 0
124
- hash: 297464805306529311
119
+ hash: -3476508434562981874
125
120
  required_rubygems_version: !ruby/object:Gem::Requirement
126
121
  none: false
127
122
  requirements:
@@ -130,13 +125,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
130
125
  version: '0'
131
126
  segments:
132
127
  - 0
133
- hash: 297464805306529311
128
+ hash: -3476508434562981874
134
129
  requirements: []
135
130
  rubyforge_project:
136
- rubygems_version: 1.8.10
131
+ rubygems_version: 1.8.24
137
132
  signing_key:
138
133
  specification_version: 3
139
134
  summary: An alternative to OpenStruct
140
135
  test_files:
141
- - test/test_astruct.rb
142
- - test/test_helper.rb
136
+ - test/helper.rb
137
+ - test/lib/astruct_test.rb
138
+ has_rdoc:
@@ -1,76 +0,0 @@
1
- require 'minitest/autorun'
2
- require_relative 'test_helper'
3
-
4
- class TestAltStruct < MiniTest::Unit::TestCase
5
- def setup
6
- @empty_example = Profile.new
7
- @example = Profile.new name: "Kurtis", age: 24
8
- end
9
-
10
- def test_that_example_is_kind_of_altstruct
11
- assert_kind_of(AltStruct, @example)
12
- end
13
-
14
- def test_that_example_has_table_imethod
15
- assert_respond_to(@example, :table)
16
- end
17
-
18
- def test_that_empty_example_has_empty_table
19
- assert_equal({}, @empty_example.table)
20
- end
21
-
22
- def test_that_example_has_name_method
23
- assert_respond_to(@example, :name)
24
- end
25
-
26
- def test_that_example_has_given_name
27
- assert_equal("Kurtis", @example.name)
28
- end
29
-
30
- def test_that_example_takes_name
31
- assert_send([@example, :name=, "Dave"])
32
- end
33
-
34
- def test_that_example_has_taken_name
35
- @example.name = "Dave"
36
- assert_equal("Dave", @example.name)
37
- end
38
-
39
- def test_that_example_has_load_imethod
40
- assert_respond_to(@example, :load)
41
- end
42
-
43
- def test_that_load_takes_a_hash
44
- assert_send([@example, :load, { nickname: "Kurt" }])
45
- end
46
-
47
- def test_that_load_sets_imethods
48
- @example.load nickname: "Kurt"
49
- assert_respond_to(@example, :nickname)
50
- end
51
-
52
- def test_that_load_sets_correct_value
53
- @example.load nickname: "Kurt"
54
- assert_equal("Kurt", @example.nickname)
55
- end
56
-
57
- def test_that_example_has_dump_imethod
58
- assert_respond_to(@example, :dump)
59
- end
60
-
61
- def test_that_dump_contains_values
62
- assert_equal({ name: "Kurtis", age: 24 }, @example.dump)
63
- end
64
-
65
- def test_that_selective_dump_contains_selective_values
66
- assert_equal({ age: 24 }, @example.dump(:age))
67
- end
68
-
69
- def test_inspect_has_values
70
- assert_match(/name="Kurtis" age=24/, @example.inspect)
71
- end
72
-
73
- def test_that_other_class_isnt_affected
74
- refute_respond_to(Profile.new, :name)
75
- end
76
- end
@@ -1,6 +0,0 @@
1
- require 'minitest/autorun'
2
- require 'astruct'
3
-
4
- class Profile
5
- include AltStruct
6
- end