astruct 1.0.0 → 2.7.1

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