ice_nine 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/.gitignore +37 -0
  2. data/.pelusa.yml +9 -0
  3. data/.rvmrc +1 -0
  4. data/.travis.yml +17 -0
  5. data/.yardopts +1 -0
  6. data/Gemfile +32 -0
  7. data/LICENSE +20 -0
  8. data/README.md +54 -0
  9. data/Rakefile +9 -0
  10. data/TODO +3 -0
  11. data/config/flay.yml +3 -0
  12. data/config/flog.yml +2 -0
  13. data/config/roodi.yml +16 -0
  14. data/config/site.reek +91 -0
  15. data/config/yardstick.yml +2 -0
  16. data/ice_nine.gemspec +21 -0
  17. data/lib/ice_nine.rb +65 -0
  18. data/lib/ice_nine/freezer.rb +95 -0
  19. data/lib/ice_nine/freezer/array.rb +26 -0
  20. data/lib/ice_nine/freezer/hash.rb +30 -0
  21. data/lib/ice_nine/freezer/no_freeze.rb +48 -0
  22. data/lib/ice_nine/freezer/range.rb +29 -0
  23. data/lib/ice_nine/freezer/struct.rb +29 -0
  24. data/lib/ice_nine/version.rb +5 -0
  25. data/spec/rcov.opts +7 -0
  26. data/spec/spec.opts +3 -0
  27. data/spec/spec_helper.rb +23 -0
  28. data/spec/unit/ice_nine/class_methods/deep_freeze_spec.rb +193 -0
  29. data/spec/unit/ice_nine/freezer/array/class_methods/deep_freeze_spec.rb +27 -0
  30. data/spec/unit/ice_nine/freezer/class_methods/deep_freeze_spec.rb +30 -0
  31. data/spec/unit/ice_nine/freezer/class_methods/element_reference_spec.rb +85 -0
  32. data/spec/unit/ice_nine/freezer/false_class/class_methods/deep_freeze_spec.rb +22 -0
  33. data/spec/unit/ice_nine/freezer/hash/class_methods/deep_freeze_spec.rb +40 -0
  34. data/spec/unit/ice_nine/freezer/nil_class/class_methods/deep_freeze_spec.rb +22 -0
  35. data/spec/unit/ice_nine/freezer/no_freeze/class_methods/deep_freeze_spec.rb +19 -0
  36. data/spec/unit/ice_nine/freezer/numeric/class_methods/deep_freeze_spec.rb +24 -0
  37. data/spec/unit/ice_nine/freezer/range/class_methods/deep_freeze_spec.rb +30 -0
  38. data/spec/unit/ice_nine/freezer/struct/class_methods/deep_freeze_spec.rb +27 -0
  39. data/spec/unit/ice_nine/freezer/symbol/class_methods/deep_freeze_spec.rb +22 -0
  40. data/spec/unit/ice_nine/freezer/true_class/class_methods/deep_freeze_spec.rb +22 -0
  41. data/tasks/metrics/ci.rake +7 -0
  42. data/tasks/metrics/flay.rake +43 -0
  43. data/tasks/metrics/flog.rake +46 -0
  44. data/tasks/metrics/heckle.rake +210 -0
  45. data/tasks/metrics/metric_fu.rake +31 -0
  46. data/tasks/metrics/reek.rake +11 -0
  47. data/tasks/metrics/roodi.rake +17 -0
  48. data/tasks/metrics/yardstick.rake +25 -0
  49. data/tasks/spec.rake +46 -0
  50. data/tasks/yard.rake +11 -0
  51. metadata +150 -0
data/.gitignore ADDED
@@ -0,0 +1,37 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## Rubinius
17
+ *.rbc
18
+ .rbx
19
+
20
+ ## PROJECT::GENERAL
21
+ *.gem
22
+ coverage
23
+ profiling
24
+ turbulence
25
+ rdoc
26
+ pkg
27
+ tmp
28
+ doc
29
+ log
30
+ .yardoc
31
+ measurements
32
+
33
+ ## BUNDLER
34
+ .bundle
35
+ Gemfile.lock
36
+
37
+ ## PROJECT::SPECIFIC
data/.pelusa.yml ADDED
@@ -0,0 +1,9 @@
1
+ sources: lib/**/*.rb
2
+ lints:
3
+ InstanceVariables:
4
+ limit: 1
5
+ LineRestriction:
6
+ limit: 87
7
+ ElseClauses:
8
+ exclude:
9
+ - 'IceNine::Freezer'
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use @$(basename `pwd`) --create
data/.travis.yml ADDED
@@ -0,0 +1,17 @@
1
+ language: ruby
2
+ bundler_args: --without guard metrics
3
+ script: "bundle exec rake spec"
4
+ rvm:
5
+ - 1.8.7
6
+ - 1.9.2
7
+ - 1.9.3
8
+ - jruby-18mode
9
+ - jruby-19mode
10
+ - rbx-18mode
11
+ - rbx-19mode
12
+ - ree
13
+ - ruby-head
14
+ - jruby-head
15
+ notifications:
16
+ email:
17
+ - dan.kubb@gmail.com
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ - README.md LICENSE
data/Gemfile ADDED
@@ -0,0 +1,32 @@
1
+ # encoding: utf-8
2
+
3
+ source :rubygems
4
+
5
+ gemspec
6
+
7
+ group :metrics do
8
+ gem 'fattr', '~> 2.2.1'
9
+ gem 'arrayfields', '~> 4.7.4'
10
+ gem 'flay', '~> 1.4.3'
11
+ gem 'flog', '~> 2.5.3'
12
+ gem 'map', '~> 5.4.0'
13
+ gem 'reek', '~> 1.2.8', :git => 'git://github.com/dkubb/reek.git'
14
+ gem 'roodi', '~> 2.1.0'
15
+ gem 'yardstick', '~> 0.4.0'
16
+
17
+ platforms :mri_18, :rbx do
18
+ gem 'heckle', '~> 1.4.3'
19
+ gem 'json', '~> 1.6.5'
20
+ gem 'mspec', '~> 1.5.17'
21
+ gem 'ruby2ruby', '= 1.2.2'
22
+ end
23
+
24
+ platforms :mri_18 do
25
+ gem 'metric_fu', '~> 2.1.1'
26
+ gem 'rcov', '~> 1.0.0'
27
+ end
28
+
29
+ platforms :rbx do
30
+ gem 'pelusa', '~> 0.2.0'
31
+ end
32
+ end
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Dan Kubb
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,54 @@
1
+ # Ice Nine
2
+
3
+ Deep Freeze Ruby Objects
4
+
5
+ [![Build Status](https://secure.travis-ci.org/dkubb/ice_nine.png)](http://travis-ci.org/dkubb/ice_nine)
6
+
7
+ ## Usage
8
+
9
+ ```ruby
10
+ hash = IceNine.deep_freeze('a' => '1')
11
+ array = IceNine.deep_freeze([ 'a', 'b', 'c' ])
12
+ range = IceNine.deep_freeze('a'..'z')
13
+ struct = IceNine.deep_freeze(Struct.new(:a, :b).new('a', 'b'))
14
+ object = IceNine.deep_freeze(Object.new)
15
+ user = IceNine.deep_freeze(Application::User.new('dkubb'))
16
+ ```
17
+
18
+ ## Installation
19
+
20
+ With Rubygems:
21
+
22
+ ```bash
23
+ $ gem install ice_nine
24
+ $ irb -rubygems
25
+ >> require 'ice_nine'
26
+ => true
27
+ ```
28
+
29
+ With git and local working copy:
30
+
31
+ ```bash
32
+ $ git clone git://github.com/dkubb/ice_nine.git
33
+ $ cd ice_nine
34
+ $ rake install
35
+ $ irb -rubygems
36
+ >> require 'ice_nine'
37
+ => true
38
+ ```
39
+
40
+ ## Note on Patches/Pull Requests
41
+
42
+ * If you want your code merged into the mainline, please discuss the proposed changes with me before doing any work on it. This library is still in early development, and it may not always be clear the direction it is going. Some features may not be appropriate yet, may need to be deferred until later when the foundation for them is laid, or may be more applicable in a plugin.
43
+ * Fork the project.
44
+ * Make your feature addition or bug fix.
45
+ * Follow this [style guide](https://github.com/dkubb/styleguide).
46
+ * Add specs for it. This is important so I don't break it in a future version unintentionally. Tests must cover all branches within the code, and code must be fully covered.
47
+ * Commit, do not mess with Rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
48
+ * Run "rake ci". This must pass and not show any regressions in the
49
+ metrics for the code to be merged.
50
+ * Send me a pull request. Bonus points for topic branches.
51
+
52
+ ## Copyright
53
+
54
+ Copyright © 2012 Dan Kubb. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'rake'
5
+
6
+ FileList['tasks/**/*.rake'].each { |task| import task }
7
+
8
+ desc 'Default: run all specs'
9
+ task :default => :spec
data/TODO ADDED
@@ -0,0 +1,3 @@
1
+ * Move some of spec/unit/ice_nine/class_methods/deep_freeze_spec.rb into an
2
+ integration test.
3
+ * Keep some minimal unit tests just for the functionality in the method.
data/config/flay.yml ADDED
@@ -0,0 +1,3 @@
1
+ ---
2
+ threshold: 6
3
+ total_score: 42.0
data/config/flog.yml ADDED
@@ -0,0 +1,2 @@
1
+ ---
2
+ threshold: 11.3
data/config/roodi.yml ADDED
@@ -0,0 +1,16 @@
1
+ ---
2
+ AbcMetricMethodCheck: { score: 0 }
3
+ AssignmentInConditionalCheck: { }
4
+ CaseMissingElseCheck: { }
5
+ ClassLineCountCheck: { line_count: 88 }
6
+ ClassNameCheck: { pattern: !ruby/regexp /\A(?:[A-Z]+|[A-Z][a-z](?:[A-Z]?[a-z])+)\z/ }
7
+ ClassVariableCheck: { }
8
+ CyclomaticComplexityBlockCheck: { complexity: 3 }
9
+ CyclomaticComplexityMethodCheck: { complexity: 0 }
10
+ EmptyRescueBodyCheck: { }
11
+ ForLoopCheck: { }
12
+ MethodLineCountCheck: { line_count: 0 }
13
+ MethodNameCheck: { pattern: !ruby/regexp /\A(?:[a-z\d](?:_?[a-z\d])+[?!=]?|\[\]=?|==|<=>|<<|[+*&|-])\z/ }
14
+ ModuleLineCountCheck: { line_count: 92 }
15
+ ModuleNameCheck: { pattern: !ruby/regexp /\A(?:[A-Z]+|[A-Z][a-z](?:[A-Z]?[a-z])+)\z/ }
16
+ ParameterNumberCheck: { parameter_count: 0 }
data/config/site.reek ADDED
@@ -0,0 +1,91 @@
1
+ ---
2
+ UncommunicativeParameterName:
3
+ accept: []
4
+ exclude: []
5
+ enabled: true
6
+ reject:
7
+ - !ruby/regexp /^.$/
8
+ - !ruby/regexp /[0-9]$/
9
+ - !ruby/regexp /[A-Z]/
10
+ LargeClass:
11
+ max_methods: 0
12
+ exclude: []
13
+ enabled: true
14
+ max_instance_variables: 0
15
+ UncommunicativeMethodName:
16
+ accept: []
17
+ exclude: []
18
+ enabled: true
19
+ reject:
20
+ - !ruby/regexp /^[a-z]$/
21
+ - !ruby/regexp /[0-9]$/
22
+ - !ruby/regexp /[A-Z]/
23
+ LongParameterList:
24
+ max_params: 1
25
+ exclude: []
26
+ enabled: true
27
+ overrides: {}
28
+ FeatureEnvy:
29
+ exclude: []
30
+ enabled: true
31
+ ClassVariable:
32
+ exclude: []
33
+ enabled: true
34
+ BooleanParameter:
35
+ exclude: []
36
+ enabled: true
37
+ IrresponsibleModule:
38
+ exclude: []
39
+ enabled: true
40
+ UncommunicativeModuleName:
41
+ accept: []
42
+ exclude: []
43
+ enabled: true
44
+ reject:
45
+ - !ruby/regexp /^.$/
46
+ - !ruby/regexp /[0-9]$/
47
+ NestedIterators:
48
+ ignore_iterators: []
49
+ exclude: []
50
+ enabled: true
51
+ max_allowed_nesting: 1
52
+ LongMethod:
53
+ max_statements: 5
54
+ exclude: []
55
+ enabled: true
56
+ Duplication:
57
+ allow_calls: []
58
+ exclude: []
59
+ enabled: true
60
+ max_calls: 1
61
+ UtilityFunction:
62
+ max_helper_calls: 0
63
+ exclude: []
64
+ enabled: true
65
+ Attribute:
66
+ exclude: []
67
+ enabled: false
68
+ UncommunicativeVariableName:
69
+ accept: []
70
+ exclude: []
71
+ enabled: true
72
+ reject:
73
+ - !ruby/regexp /^.$/
74
+ - !ruby/regexp /[0-9]$/
75
+ - !ruby/regexp /[A-Z]/
76
+ SimulatedPolymorphism:
77
+ exclude: []
78
+ enabled: true
79
+ max_ifs: 1
80
+ DataClump:
81
+ exclude: []
82
+ enabled: true
83
+ max_copies: 0
84
+ min_clump_size: 0
85
+ ControlCouple:
86
+ exclude: []
87
+ enabled: true
88
+ LongYieldList:
89
+ max_params: 0
90
+ exclude: []
91
+ enabled: true
@@ -0,0 +1,2 @@
1
+ ---
2
+ threshold: 100.0
data/ice_nine.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path('../lib/ice_nine/version', __FILE__)
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.name = 'ice_nine'
7
+ gem.version = IceNine::VERSION
8
+ gem.authors = [ 'Dan Kubb' ]
9
+ gem.email = [ 'dan.kubb@gmail.com' ]
10
+ gem.description = 'Deep Freeze Ruby Objects'
11
+ gem.summary = gem.description
12
+ gem.homepage = "https://github.com/dkubb/ice_nine"
13
+
14
+ gem.require_paths = %w[ lib ]
15
+ gem.files = `git ls-files`.split("\n")
16
+ gem.test_files = `git ls-files -- {spec}/*`.split("\n")
17
+ gem.extra_rdoc_files = %w[ LICENSE README.md TODO ]
18
+
19
+ gem.add_development_dependency('rake', '~> 0.9.2.2')
20
+ gem.add_development_dependency('rspec', '~> 1.3.2')
21
+ end
data/lib/ice_nine.rb ADDED
@@ -0,0 +1,65 @@
1
+ # encoding: utf-8
2
+
3
+ require 'ice_nine/freezer'
4
+ require 'ice_nine/freezer/array'
5
+ require 'ice_nine/freezer/hash'
6
+ require 'ice_nine/freezer/no_freeze'
7
+ require 'ice_nine/freezer/range'
8
+ require 'ice_nine/freezer/struct'
9
+
10
+ require 'ice_nine/version'
11
+
12
+ # Base IceNine module
13
+ module IceNine
14
+
15
+ # Deep Freeze an object
16
+ #
17
+ # @example
18
+ # object = IceNine.deep_freeze(object)
19
+ #
20
+ # @param [Object] object
21
+ #
22
+ # @return [Object]
23
+ #
24
+ # @api public
25
+ def self.deep_freeze(object)
26
+ recursion_guard(recursion_guard_key(object)) do
27
+ Freezer[object.class].deep_freeze(object)
28
+ end
29
+ object
30
+ end
31
+
32
+ # Guard the system from recursive freezing
33
+ #
34
+ # @param [String] key
35
+ #
36
+ # @return [undefined]
37
+ #
38
+ # @api private
39
+ def self.recursion_guard(key)
40
+ thread = Thread.current
41
+ return if thread[key]
42
+ begin
43
+ thread[key] = true
44
+ yield
45
+ ensure
46
+ thread[key] = nil
47
+ end
48
+ end
49
+
50
+ private_class_method :recursion_guard
51
+
52
+ # Create a unique key to guard against recursively deep freezing the object
53
+ #
54
+ # @param [#object_id]
55
+ #
56
+ # @return [String]
57
+ #
58
+ # @api private
59
+ def self.recursion_guard_key(object)
60
+ "__ice_nine_deep_freeze_#{object.object_id}"
61
+ end
62
+
63
+ private_class_method :recursion_guard_key
64
+
65
+ end # module IceNine
@@ -0,0 +1,95 @@
1
+ # encoding: utf-8
2
+
3
+ module IceNine
4
+
5
+ # The default class that handles freezing objects
6
+ class Freezer
7
+
8
+ # Configure const_get and const_defined? to not search ancestors
9
+ SKIP_ANCESTORS = (RUBY_VERSION < '1.9' ? [] : [ false ]).freeze
10
+
11
+ # Lookup the Freezer subclass by object type
12
+ #
13
+ # @example
14
+ # freezer_class = IceNine::Freezer[mod]
15
+ #
16
+ # @param [Module] mod
17
+ #
18
+ # @return [Class<Freezer>]
19
+ #
20
+ # @api public
21
+ def self.[](mod)
22
+ mod.ancestors.each do |ancestor|
23
+ name = ancestor.name.to_s
24
+ freezer = find(name) unless name.empty? # skip anonymous modules
25
+ return freezer if freezer
26
+ end
27
+ end
28
+
29
+ # Deep Freeze an object
30
+ #
31
+ # @example
32
+ # object = IceNine.deep_freeze(Object.new)
33
+ #
34
+ # @param [Object] object
35
+ #
36
+ # @return [Object]
37
+ #
38
+ # @api public
39
+ def self.deep_freeze(object)
40
+ freeze_instance_variables(object)
41
+ object.freeze
42
+ end
43
+
44
+ # Find a Freezer subclass by name
45
+ #
46
+ # @param [String] mod_name
47
+ #
48
+ # @return [Class<Freezer>]
49
+ #
50
+ # @api private
51
+ def self.find(mod_name)
52
+ namespace, const = mod_name.split('::', 2)
53
+ mod = const_lookup(namespace) if namespace
54
+ mod ? mod.find(const.to_s) : self
55
+ end
56
+
57
+ class << self
58
+ protected :find
59
+ end
60
+
61
+ # Lookup a constant in the namespace
62
+ #
63
+ # @param [String] namespace
64
+ #
65
+ # @return [Module]
66
+ # returned if a matching freezer is found
67
+ # @return [nil]
68
+ # returned if no matchiner freezer is found
69
+ #
70
+ # @api private
71
+ def self.const_lookup(namespace)
72
+ if const_defined?(namespace, *SKIP_ANCESTORS)
73
+ const_get(namespace, *SKIP_ANCESTORS)
74
+ end
75
+ end
76
+
77
+ private_class_method :const_lookup
78
+
79
+ # Handle freezing the object's instance variables
80
+ #
81
+ # @param [Object] object
82
+ #
83
+ # @return [undefined]
84
+ #
85
+ # @api private
86
+ def self.freeze_instance_variables(object)
87
+ object.instance_variables.each do |ivar_name|
88
+ IceNine.deep_freeze(object.instance_variable_get(ivar_name))
89
+ end
90
+ end
91
+
92
+ private_class_method :freeze_instance_variables
93
+
94
+ end # class Freezer
95
+ end # module IceNine