-
Notifications
You must be signed in to change notification settings - Fork 226
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add pref-key
to FML feature variables
#5862
Changes from all commits
f97ae4f
1d9e3a1
13b1faf
e2edb95
5c9ca0e
badaf0a
cdbb5a6
dab7894
67267c0
426a907
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,18 +12,18 @@ public typealias GetSdk = () -> FeaturesInterface? | |
/// | ||
/// There are methods useful for testing, and more advanced uses: these all start with `with`. | ||
/// | ||
public class FeatureHolder<T> { | ||
public class FeatureHolder<T: FMLFeatureInterface> { | ||
private let lock = NSLock() | ||
private var cachedValue: T? | ||
|
||
private var getSdk: GetSdk | ||
private let featureId: String | ||
|
||
private var create: (Variables) -> T | ||
private var create: (Variables, UserDefaults?) -> T | ||
|
||
public init(_ getSdk: @escaping () -> FeaturesInterface?, | ||
featureId: String, | ||
with create: @escaping (Variables) -> T) | ||
with create: @escaping (Variables, UserDefaults?) -> T) | ||
{ | ||
self.getSdk = getSdk | ||
self.featureId = featureId | ||
|
@@ -43,18 +43,22 @@ public class FeatureHolder<T> { | |
return v | ||
} | ||
var variables: Variables = NilVariables.instance | ||
var defaults: UserDefaults? | ||
if let sdk = getSdk() { | ||
variables = sdk.getVariables(featureId: featureId, sendExposureEvent: false) | ||
defaults = sdk.userDefaults | ||
} | ||
let v = create(variables) | ||
let v = create(variables, defaults) | ||
cachedValue = v | ||
return v | ||
} | ||
|
||
/// Send an exposure event for this feature. This should be done when the user is shown the feature, and may change | ||
/// their behavior because of it. | ||
public func recordExposure() { | ||
getSdk()?.recordExposureEvent(featureId: featureId, experimentSlug: nil) | ||
if !value().isModified() { | ||
getSdk()?.recordExposureEvent(featureId: featureId, experimentSlug: nil) | ||
} | ||
} | ||
|
||
/// Send an exposure event for this feature, in the given experiment. | ||
|
@@ -67,7 +71,9 @@ public class FeatureHolder<T> { | |
/// | ||
/// - Parameter slug the experiment identifier, likely derived from the {value}. | ||
public func recordExperimentExposure(slug: String) { | ||
getSdk()?.recordExposureEvent(featureId: featureId, experimentSlug: slug) | ||
if !value().isModified() { | ||
getSdk()?.recordExposureEvent(featureId: featureId, experimentSlug: slug) | ||
} | ||
} | ||
|
||
/// Send a malformed feature event for this feature. | ||
|
@@ -121,10 +127,33 @@ public class FeatureHolder<T> { | |
/// This changes the mapping between a `Variables` and the feature configuration object. | ||
/// | ||
/// This is most likely useful during testing and other generated code. | ||
public func with(initializer: @escaping (Variables) -> T) { | ||
public func with(initializer: @escaping (Variables, UserDefaults?) -> T) { | ||
lock.lock() | ||
defer { self.lock.unlock() } | ||
cachedValue = nil | ||
create = initializer | ||
} | ||
} | ||
|
||
/// A bare-bones interface for the FML generated objects. | ||
public protocol FMLObjectInterface {} | ||
|
||
/// A bare-bones interface for the FML generated features. | ||
/// | ||
/// App developers should use the generated concrete classes, which | ||
/// implement this interface. | ||
/// | ||
public protocol FMLFeatureInterface: FMLObjectInterface { | ||
/// A test if the feature configuration has been modified somehow, invalidating any experiment | ||
/// that uses it. | ||
/// | ||
/// This may be `true` if a `pref-key` has been set in the feature manifest and the user has | ||
/// set that preference. | ||
func isModified() -> Bool | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this need the public modifier? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adding ❌ error: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cool I just wasn't sure — iirc we had a few prs in recent history just adding privacy modifiers |
||
} | ||
|
||
public extension FMLFeatureInterface { | ||
func isModified() -> Bool { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adding
|
||
return false | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -132,7 +132,7 @@ public class NimbusBuilder { | |
var resourceBundles: [Bundle] = [.main] | ||
|
||
/** | ||
* The object generated from the `nimbus.fml.yaml` file and the nimbus-gradle-plugin. | ||
* The object generated from the `nimbus.fml.yaml` file. | ||
*/ | ||
@discardableResult | ||
public func with(featureManifest: FeatureManifestInterface) -> NimbusBuilder { | ||
|
@@ -142,6 +142,17 @@ public class NimbusBuilder { | |
|
||
var featureManifest: FeatureManifestInterface? | ||
|
||
/** | ||
* Main user defaults for the app. | ||
*/ | ||
@discardableResult | ||
public func with(userDefaults: UserDefaults) -> NimbusBuilder { | ||
self.userDefaults = userDefaults | ||
return self | ||
} | ||
|
||
var userDefaults = UserDefaults.standard | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This isn't been used. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is now used! |
||
/** | ||
* The command line arguments for the app. This is useful for QA, and can be safely left in the app in production. | ||
*/ | ||
|
@@ -240,6 +251,7 @@ public class NimbusBuilder { | |
coenrollingFeatureIds: getCoenrollingFeatureIds(), | ||
dbPath: dbFilePath, | ||
resourceBundles: resourceBundles, | ||
userDefaults: userDefaults, | ||
errorReporter: errorReporter) | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
FMLFeatureInterface
/FMLFeatureObject
was introduced in Kotlin when we did thetoJSONObject
work.This is the Swift version, now we need it to implement
isModified()
.It still does not do the JSON object creation.