fixtury 0.4.1 → 1.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,159 +1,130 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "fixtury/store"
3
+ require "fixtury"
4
4
  require "active_support/core_ext/class/attribute"
5
5
 
6
6
  module Fixtury
7
7
  module TestHooks
8
8
 
9
- extend ::ActiveSupport::Concern
10
-
11
- included do
12
- class_attribute :fixtury_dependencies
13
- self.fixtury_dependencies = Set.new
9
+ def self.prepended(klass)
10
+ klass.class_attribute :fixtury_dependencies
11
+ klass.fixtury_dependencies = Set.new
12
+ klass.extend ClassMethods
13
+ end
14
14
 
15
- class_attribute :local_fixtury_dependencies
16
- self.local_fixtury_dependencies = Set.new
15
+ def self.included(klass)
16
+ raise ArgumentError, "#{name} should be prepended, not included"
17
17
  end
18
18
 
19
19
  module ClassMethods
20
20
 
21
- def fixtury(*names, &definition)
22
- opts = names.extract_options!
23
-
24
- # define fixtures if blocks are given
25
- if block_given?
26
- raise ArgumentError, "A fixture cannot be defined in an anonymous class" if name.nil?
27
-
28
- namespace = fixtury_namespace
29
-
30
- ns = ::Fixtury.schema
31
-
32
- namespace.split("/").each do |ns_name|
33
- ns = ns.namespace(ns_name){}
34
- end
21
+ def fixtury_store
22
+ ::Fixtury.store
23
+ end
35
24
 
36
- names.map! do |fixture_name|
37
- ns.fixture(fixture_name, &definition)
38
- new_name = "/#{namespace}/#{fixture_name}"
39
- self.local_fixtury_dependencies += [new_name]
40
- new_name
41
- end
25
+ def fixtury_schema
26
+ ::Fixtury.schema
27
+ end
42
28
 
43
- # otherwise, just record the dependency
44
- else
45
- self.fixtury_dependencies += names.flatten.compact.map(&:to_s)
29
+ def fixtury(*searches, **opts)
30
+ pathnames = searches.map do |search|
31
+ dfn = fixtury_schema.get!(search)
32
+ dfn.pathname
46
33
  end
47
34
 
35
+ self.fixtury_dependencies += pathnames
36
+
48
37
  accessor_option = opts[:as]
49
38
  accessor_option = opts[:accessor] if accessor_option.nil? # old version, backwards compatability
50
39
  accessor_option = accessor_option.nil? ? true : accessor_option
51
40
 
52
41
  if accessor_option
53
42
 
54
- if accessor_option != true && names.length > 1
43
+ if accessor_option != true && pathnames.length > 1
55
44
  raise ArgumentError, "A named :as option is only available when providing one fixture"
56
45
  end
57
46
 
58
- names.each do |fixture_name|
59
- method_name = accessor_option == true ? fixture_name.split("/").last : accessor_option
60
- ivar = :"@#{method_name}"
47
+ pathnames.each do |pathname|
48
+ method_name = (accessor_option == true ? pathname.split("/").last : accessor_option).to_sym
49
+
50
+ if method_defined?(method_name)
51
+ raise ArgumentError, "A method by the name of #{method_name} already exists in #{self}"
52
+ end
53
+
54
+ ivar = :"@fixtury_#{method_name}"
61
55
 
62
56
  class_eval <<-EV, __FILE__, __LINE__ + 1
63
57
  def #{method_name}
64
58
  return #{ivar} if defined?(#{ivar})
65
59
 
66
- value = fixtury("#{fixture_name}")
67
- #{ivar} = value
60
+ #{ivar} = fixtury("#{pathname}")
68
61
  end
69
62
  EV
70
63
  end
71
64
  end
72
65
  end
73
66
 
74
- def fixtury_namespace
75
- name.underscore
76
- end
67
+ end
77
68
 
69
+ def before_setup(...)
70
+ fixtury_setup if fixtury_dependencies.any?
71
+ super
78
72
  end
79
73
 
80
- def fixtury(name)
81
- return nil unless fixtury_store
74
+ def after_teardown(...)
75
+ super
76
+ fixtury_teardown if fixtury_dependencies.any?
77
+ end
82
78
 
83
- name = name.to_s
84
79
 
85
- # in the case that we're looking for a relative fixture, see if it's registered relative to the test's namespace.
86
- unless name.include?("/")
87
- local_name = "/#{self.class.fixtury_namespace}/#{name}"
88
- if local_fixtury_dependencies.include?(local_name)
89
- return fixtury_store.get(local_name, execution_context: self)
90
- end
91
- end
80
+ def fixtury(name)
81
+ return nil unless self.class.fixtury_store
92
82
 
93
- unless fixtury_dependencies.include?(name) || local_fixtury_dependencies.include?(name)
94
- raise ArgumentError, "Unrecognized fixtury dependency `#{name}` for #{self.class}"
95
- end
83
+ dfn = self.class.fixtury_schema.get!(name)
96
84
 
97
- fixtury_store.get(name, execution_context: self)
98
- end
85
+ unless fixtury_dependencies.include?(dfn.pathname)
86
+ raise Errors::UnknownTestDependencyError, "Unrecognized fixtury dependency `#{dfn.pathname}` for #{self.class}"
87
+ end
99
88
 
100
- def fixtury_store
101
- ::Fixtury::Store.instance
89
+ self.class.fixtury_store.get(dfn.pathname)
102
90
  end
103
91
 
104
92
  def fixtury_loaded?(name)
105
- return false unless fixtury_store
93
+ return false unless self.class.fixtury_store
106
94
 
107
- fixtury_store.loaded?(name)
95
+ self.class.fixtury_store.loaded?(name)
108
96
  end
109
97
 
110
98
  def fixtury_database_connections
111
- ActiveRecord::Base.connection_handler.connection_pool_list.map(&:connection)
112
- end
113
-
114
- # piggybacking activerecord fixture setup for now.
115
- def setup_fixtures(*args)
116
- if fixtury_dependencies.any? || local_fixtury_dependencies.any?
117
- setup_fixtury_fixtures
118
- else
119
- super
120
- end
121
- end
122
-
123
- # piggybacking activerecord fixture setup for now.
124
- def teardown_fixtures(*args)
125
- if fixtury_dependencies.any? || local_fixtury_dependencies.any?
126
- teardown_fixtury_fixtures
127
- else
128
- super
129
- end
99
+ ActiveRecord::Base.connection_handler.connection_pool_list(:writing).map(&:connection)
130
100
  end
131
101
 
132
- def setup_fixtury_fixtures
102
+ def fixtury_setup
103
+ fixtury_clear_stale_fixtures!
104
+ fixtury_load_all_fixtures!
133
105
  return unless fixtury_use_transactions?
134
106
 
135
- clear_expired_fixtury_fixtures!
136
- load_all_fixtury_fixtures!
137
-
138
107
  fixtury_database_connections.each do |conn|
139
108
  conn.begin_transaction joinable: false
140
109
  end
141
110
  end
142
111
 
143
- def teardown_fixtury_fixtures
112
+ def fixtury_teardown
144
113
  return unless fixtury_use_transactions?
145
114
 
146
- fixtury_database_connections.each(&:rollback_transaction)
115
+ fixtury_database_connections.each do |conn|
116
+ conn.rollback_transaction if conn.open_transactions.positive?
117
+ end
147
118
  end
148
119
 
149
- def clear_expired_fixtury_fixtures!
150
- return unless fixtury_store
120
+ def fixtury_clear_stale_fixtures!
121
+ return unless self.class.fixtury_store
151
122
 
152
- fixtury_store.clear_expired_references!
123
+ self.class.fixtury_store.clear_stale_references!
153
124
  end
154
125
 
155
- def load_all_fixtury_fixtures!
156
- (fixtury_dependencies | local_fixtury_dependencies).each do |name|
126
+ def fixtury_load_all_fixtures!
127
+ fixtury_dependencies.each do |name|
157
128
  unless fixtury_loaded?(name)
158
129
  ::Fixtury.log("preloading #{name.inspect}", name: "test", level: ::Fixtury::LOG_LEVEL_INFO)
159
130
  fixtury(name)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Fixtury
4
4
 
5
- VERSION = "0.4.1"
5
+ VERSION = "1.0.0.beta1"
6
6
 
7
7
  end
data/lib/fixtury.rb CHANGED
@@ -1,14 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/concern"
4
+ require "active_support/core_ext/array/extract_options"
4
5
  require "active_support/core_ext/module/attribute_accessors"
5
6
  require "active_support/core_ext/module/delegation"
7
+ require "active_support/core_ext/object/acts_like"
8
+ require "active_support/core_ext/object/blank"
9
+
6
10
  require "fixtury/version"
7
- require "fixtury/schema"
11
+
12
+ require "fixtury/definition_executor"
13
+ require "fixtury/dependency"
14
+ require "fixtury/dependency_store"
15
+ require "fixtury/errors"
16
+ require "fixtury/hooks"
8
17
  require "fixtury/locator"
18
+ require "fixtury/path_resolver"
19
+ require "fixtury/reference"
9
20
  require "fixtury/store"
10
21
 
11
- # Top level namespace of the gem
22
+ require "fixtury/schema_node"
23
+ require "fixtury/definition"
24
+ require "fixtury/schema"
25
+
26
+
27
+ # Top level namespace of the gem. The accessors provided on the Fixtury namespace are meant to be shared
28
+ # across the entire application. The Fixtury::Schema instance is the primary interface for defining and
29
+ # accessing fixtures and can be accessed via Fixtury.schema.
12
30
  module Fixtury
13
31
 
14
32
  LOG_LEVELS = {
@@ -26,10 +44,28 @@ module Fixtury
26
44
  schema
27
45
  end
28
46
 
47
+ # Global hooks accessor. Fixtury will call these hooks at various points in the lifecycle of a fixture or setup.
48
+ def self.hooks
49
+ @hooks ||= ::Fixtury::Hooks.new
50
+ end
51
+
29
52
  # The default top level schema. Fixtury::Schema instances can be completely self-contained but most
30
53
  # usage would be through this shared definition.
31
54
  def self.schema
32
- @schema ||= ::Fixtury::Schema.new(parent: nil, name: "")
55
+ @schema ||= ::Fixtury::Schema.new
56
+ end
57
+
58
+ def self.schema=(schema)
59
+ @schema = schema
60
+ end
61
+
62
+ # Default store for fixtures. This is a shared store that can be used across the application.
63
+ def self.store
64
+ @store ||= ::Fixtury::Store.new(schema: schema)
65
+ end
66
+
67
+ def self.store=(store)
68
+ @store = store
33
69
  end
34
70
 
35
71
  def self.log_level
@@ -41,7 +77,7 @@ module Fixtury
41
77
  @log_level
42
78
  end
43
79
 
44
- def self.log(text = nil, level: LOG_LEVEL_DEBUG, name: nil)
80
+ def self.log(text = nil, level: LOG_LEVEL_DEBUG, name: nil, newline: true)
45
81
  desired_level = LOG_LEVELS.fetch(log_level) { DEFAULT_LOG_LEVEL }
46
82
  return if desired_level == LOG_LEVEL_NONE
47
83
 
@@ -53,7 +89,10 @@ module Fixtury
53
89
  msg << "]"
54
90
  msg << " #{text}" if text
55
91
  msg << " #{yield}" if block_given?
56
- puts msg
92
+ msg << "\n" if newline
93
+
94
+ print msg
95
+ msg
57
96
  end
58
97
 
59
98
  end
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fixtury
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 1.0.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Nelson
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-11-05 00:00:00.000000000 Z
11
+ date: 2024-03-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: autotest
14
+ name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
@@ -25,21 +25,21 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: bundler
28
+ name: byebug
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '2.0'
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '2.0'
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: byebug
42
+ name: globalid
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: globalid
56
+ name: activerecord
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -67,21 +67,21 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: minitest
70
+ name: m
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - "~>"
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
- version: '5.0'
75
+ version: '0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - "~>"
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
- version: '5.0'
82
+ version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: minitest-reporters
84
+ name: minitest
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
@@ -112,18 +112,18 @@ dependencies:
112
112
  name: rake
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - "~>"
115
+ - - ">="
116
116
  - !ruby/object:Gem::Version
117
- version: '13.0'
117
+ version: '0'
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - "~>"
122
+ - - ">="
123
123
  - !ruby/object:Gem::Version
124
- version: '13.0'
124
+ version: '0'
125
125
  - !ruby/object:Gem::Dependency
126
- name: sqlite
126
+ name: sqlite3
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
129
  - - ">="
@@ -136,7 +136,7 @@ dependencies:
136
136
  - - ">="
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0'
139
- description:
139
+ description:
140
140
  email:
141
141
  - mike@guideline.com
142
142
  executables: []
@@ -156,20 +156,20 @@ files:
156
156
  - lib/fixtury.rb
157
157
  - lib/fixtury/definition.rb
158
158
  - lib/fixtury/definition_executor.rb
159
- - lib/fixtury/errors/already_defined_error.rb
160
- - lib/fixtury/errors/circular_dependency_error.rb
161
- - lib/fixtury/errors/fixture_not_defined_error.rb
162
- - lib/fixtury/errors/option_collision_error.rb
163
- - lib/fixtury/errors/schema_frozen_error.rb
164
- - lib/fixtury/errors/unrecognizable_locator_error.rb
159
+ - lib/fixtury/dependency.rb
160
+ - lib/fixtury/dependency_store.rb
161
+ - lib/fixtury/errors.rb
162
+ - lib/fixtury/hooks.rb
165
163
  - lib/fixtury/locator.rb
166
164
  - lib/fixtury/locator_backend/common.rb
167
165
  - lib/fixtury/locator_backend/globalid.rb
168
166
  - lib/fixtury/locator_backend/memory.rb
169
- - lib/fixtury/path.rb
167
+ - lib/fixtury/mutation_observer.rb
168
+ - lib/fixtury/path_resolver.rb
170
169
  - lib/fixtury/railtie.rb
171
170
  - lib/fixtury/reference.rb
172
171
  - lib/fixtury/schema.rb
172
+ - lib/fixtury/schema_node.rb
173
173
  - lib/fixtury/store.rb
174
174
  - lib/fixtury/tasks.rake
175
175
  - lib/fixtury/test_hooks.rb
@@ -181,7 +181,7 @@ metadata:
181
181
  homepage_uri: https://github.com/guideline-tech/fixtury
182
182
  source_code_uri: https://github.com/guideline-tech/fixtury
183
183
  changelog_uri: https://github.com/guideline-tech/fixtury
184
- post_install_message:
184
+ post_install_message:
185
185
  rdoc_options: []
186
186
  require_paths:
187
187
  - lib
@@ -196,8 +196,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
196
196
  - !ruby/object:Gem::Version
197
197
  version: '0'
198
198
  requirements: []
199
- rubygems_version: 3.0.6
200
- signing_key:
199
+ rubygems_version: 3.5.6
200
+ signing_key:
201
201
  specification_version: 4
202
202
  summary: Treat fixtures like factories and factories like fixtures
203
203
  test_files: []
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Fixtury
4
- module Errors
5
- class AlreadyDefinedError < ::StandardError
6
-
7
- def initialize(name)
8
- super("An element identified by `#{name}` already exists.")
9
- end
10
-
11
- end
12
- end
13
- end
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Fixtury
4
- module Errors
5
- class CircularDependencyError < ::StandardError
6
-
7
- def initialize(name)
8
- super("One of the dependencies of #{name} is dependent on #{name}.")
9
- end
10
-
11
- end
12
- end
13
- end
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Fixtury
4
- module Errors
5
- class FixtureNotDefinedError < ::StandardError
6
-
7
- def initialize(name)
8
- super("A fixture identified by `#{name}` does not exist.")
9
- end
10
-
11
- end
12
- end
13
- end
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Fixtury
4
- module Errors
5
- class OptionCollisionError < ::StandardError
6
-
7
- def initialize(schema_name, option_key, old_value, new_value)
8
- super("The #{schema_name.inspect} schema #{option_key.inspect} option value of #{old_value.inspect} conflicts with the new value #{new_value.inspect}.")
9
- end
10
-
11
- end
12
- end
13
- end
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Fixtury
4
- module Errors
5
- class SchemaFrozenError < ::StandardError
6
-
7
- def initialize
8
- super("Schema is frozen. New namespaces, definitions, and enhancements are not allowed.")
9
- end
10
-
11
- end
12
- end
13
- end
@@ -1,11 +0,0 @@
1
- module Fixtury
2
- module Errors
3
- class UnrecognizableLocatorError < ::StandardError
4
-
5
- def initialize(action, thing)
6
- super("Locator did not reognize #{thing} during #{action}")
7
- end
8
-
9
- end
10
- end
11
- end
data/lib/fixtury/path.rb DELETED
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Fixtury
4
- class Path
5
-
6
- def initialize(namespace:, path:)
7
- @namespace = namespace.to_s
8
- @path = path.to_s
9
- @full_path = (
10
- @path.start_with?("/") ?
11
- @path :
12
- File.expand_path(::File.join(@namespace, @path), "/")
13
- )
14
- @segments = @full_path.split("/")
15
- end
16
-
17
- def top_level_namespace
18
- return "" if @segments.size == 1
19
-
20
- @segments.first
21
- end
22
-
23
- def relative?
24
- @path.start_with?(".")
25
- end
26
-
27
- def possible_absolute_paths
28
- @possible_absolute_paths ||= begin
29
- out = [@full_path]
30
- out << @path unless relative?
31
- out
32
- end
33
- end
34
-
35
- end
36
- end