diff --git a/.hound.yml b/.hound.yml new file mode 100644 index 00000000..2606b3b5 --- /dev/null +++ b/.hound.yml @@ -0,0 +1,2 @@ +ruby: + config_file: .rubocop diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 00000000..5bbd7cde --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,601 @@ +AllCops: + Exclude: + - db/schema.rb + +Style/AccessorMethodName: + Description: Check the naming of accessor methods for get_/set_. + Enabled: false + +Style/Alias: + Description: 'Use alias_method instead of alias.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#alias-method' + Enabled: false + +Style/ArrayJoin: + Description: 'Use Array#join instead of Array#*.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#array-join' + Enabled: false + +Style/AsciiComments: + Description: 'Use only ascii symbols in comments.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#english-comments' + Enabled: false + +Style/AsciiIdentifiers: + Description: 'Use only ascii symbols in identifiers.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#english-identifiers' + Enabled: false + +Style/Attr: + Description: 'Checks for uses of Module#attr.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#attr' + Enabled: false + +Metrics/BlockNesting: + Description: 'Avoid excessive block nesting' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#three-is-the-number-thou-shalt-count' + Enabled: false + +Style/CaseEquality: + Description: 'Avoid explicit use of the case equality operator(===).' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-case-equality' + Enabled: false + +Style/CharacterLiteral: + Description: 'Checks for uses of character literals.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-character-literals' + Enabled: false + +Style/ClassAndModuleChildren: + Description: 'Checks style of children classes and modules.' + Enabled: true + EnforcedStyle: nested + +Metrics/ClassLength: + Description: 'Avoid classes longer than 100 lines of code.' + Enabled: false + +Metrics/ModuleLength: + Description: 'Avoid modules longer than 100 lines of code.' + Enabled: false + +Style/ClassVars: + Description: 'Avoid the use of class variables.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-class-vars' + Enabled: false + +Style/CollectionMethods: + Enabled: true + PreferredMethods: + find: detect + inject: reduce + collect: map + find_all: select + +Style/ColonMethodCall: + Description: 'Do not use :: for method call.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#double-colons' + Enabled: false + +Style/CommentAnnotation: + Description: >- + Checks formatting of special comments + (TODO, FIXME, OPTIMIZE, HACK, REVIEW). + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#annotate-keywords' + Enabled: false + +Metrics/CyclomaticComplexity: + Description: >- + A complexity metric that is strongly correlated to the number + of test cases needed to validate a method. + Enabled: false + +Rails/Delegate: + Description: 'Prefer delegate method for delegations.' + Enabled: false + +Style/DeprecatedHashMethods: + Description: 'Checks for use of deprecated Hash methods.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#hash-key' + Enabled: false + +Style/Documentation: + Description: 'Document classes and non-namespace modules.' + Enabled: false + +Style/DotPosition: + Description: 'Checks the position of the dot in multi-line method calls.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#consistent-multi-line-chains' + EnforcedStyle: trailing + +Style/DoubleNegation: + Description: 'Checks for uses of double negation (!!).' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-bang-bang' + Enabled: false + +Style/EachWithObject: + Description: 'Prefer `each_with_object` over `inject` or `reduce`.' + Enabled: false + +Style/EmptyLiteral: + Description: 'Prefer literals to Array.new/Hash.new/String.new.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#literal-array-hash' + Enabled: false + +# Checks whether the source file has a utf-8 encoding comment or not +# AutoCorrectEncodingComment must match the regex +# /#.*coding\s?[:=]\s?(?:UTF|utf)-8/ +Style/Encoding: + Enabled: false + +Style/EvenOdd: + Description: 'Favor the use of Fixnum#even? && Fixnum#odd?' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#predicate-methods' + Enabled: false + +Style/ExtraSpacing: + Description: 'Do not use unnecessary spacing.' + Enabled: true + +Style/FileName: + Description: 'Use snake_case for source file names.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#snake-case-files' + Enabled: false + +Style/FlipFlop: + Description: 'Checks for flip flops' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-flip-flops' + Enabled: false + +Style/FormatString: + Description: 'Enforce the use of Kernel#sprintf, Kernel#format or String#%.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#sprintf' + Enabled: false + +Style/GlobalVars: + Description: 'Do not introduce global variables.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#instance-vars' + Reference: 'http://www.zenspider.com/Languages/Ruby/QuickRef.html' + Enabled: false + +Style/GuardClause: + Description: 'Check for conditionals that can be replaced with guard clauses' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-nested-conditionals' + Enabled: false + +Style/IfUnlessModifier: + Description: >- + Favor modifier if/unless usage when you have a + single-line body. + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#if-as-a-modifier' + Enabled: false + +Style/IfWithSemicolon: + Description: 'Do not use if x; .... Use the ternary operator instead.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-semicolon-ifs' + Enabled: false + +Style/InlineComment: + Description: 'Avoid inline comments.' + Enabled: false + +Style/Lambda: + Description: 'Use the new lambda literal syntax for single-line blocks.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#lambda-multi-line' + Enabled: false + +Style/LambdaCall: + Description: 'Use lambda.call(...) instead of lambda.(...).' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#proc-call' + Enabled: false + +Style/LineEndConcatenation: + Description: >- + Use \ instead of + or << to concatenate two string literals at + line end. + Enabled: false + +Metrics/LineLength: + Description: 'Limit lines to 100 characters.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#80-character-limits' + Max: 100 + +Metrics/MethodLength: + Description: 'Avoid methods longer than 10 lines of code.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#short-methods' + Enabled: false + +Style/ModuleFunction: + Description: 'Checks for usage of `extend self` in modules.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#module-function' + Enabled: false + +Style/MultilineOperationIndentation: + Description: >- + Checks indentation of binary operations that span more than + one line. + Enabled: true + EnforcedStyle: indented + +Style/NegatedIf: + Description: >- + Favor unless over if for negative conditions + (or control flow or). + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#unless-for-negatives' + Enabled: false + +Style/NegatedWhile: + Description: 'Favor until over while for negative conditions.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#until-for-negatives' + Enabled: false + +Style/Next: + Description: 'Use `next` to skip iteration instead of a condition at the end.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-nested-conditionals' + Enabled: false + +Style/NilComparison: + Description: 'Prefer x.nil? to x == nil.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#predicate-methods' + Enabled: false + +Style/Not: + Description: 'Use ! instead of not.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#bang-not-not' + Enabled: false + +Style/NumericLiterals: + Description: >- + Add underscores to large numeric literals to improve their + readability. + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#underscores-in-numerics' + Enabled: false + +Style/OneLineConditional: + Description: >- + Favor the ternary operator(?:) over + if/then/else/end constructs. + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#ternary-operator' + Enabled: false + +Style/OpMethod: + Description: 'When defining binary operators, name the argument other.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#other-arg' + Enabled: false + +Metrics/ParameterLists: + Description: 'Avoid parameter lists longer than three or four parameters.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#too-many-params' + Enabled: false + +Style/PercentLiteralDelimiters: + Description: 'Use `%`-literal delimiters consistently' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#percent-literal-braces' + Enabled: false + +Style/PerlBackrefs: + Description: 'Avoid Perl-style regex back references.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-perl-regexp-last-matchers' + Enabled: false + +Style/PredicateName: + Description: 'Check the names of predicate methods.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#bool-methods-qmark' + NamePrefixBlacklist: + - is_ + Exclude: + - spec/**/* + +Style/Proc: + Description: 'Use proc instead of Proc.new.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#proc' + Enabled: false + +Style/RaiseArgs: + Description: 'Checks the arguments passed to raise/fail.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#exception-class-messages' + Enabled: false + +Style/RegexpLiteral: + Description: 'Use / or %r around regular expressions.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#percent-r' + Enabled: false + +Style/SelfAssignment: + Description: >- + Checks for places where self-assignment shorthand should have + been used. + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#self-assignment' + Enabled: false + +Style/SingleLineBlockParams: + Description: 'Enforces the names of some block params.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#reduce-blocks' + Enabled: false + +Style/SingleLineMethods: + Description: 'Avoid single-line methods.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-single-line-methods' + Enabled: false + +Style/SignalException: + Description: 'Checks for proper usage of fail and raise.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#fail-method' + Enabled: false + +Style/SpecialGlobalVars: + Description: 'Avoid Perl-style global variables.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-cryptic-perlisms' + Enabled: false + +Style/StringLiterals: + Description: 'Checks if uses of quotes match the configured preference.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#consistent-string-literals' + EnforcedStyle: double_quotes + Enabled: true + +Style/TrailingComma: + Description: 'Checks for trailing comma in parameter lists and literals.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-trailing-array-commas' + EnforcedStyleForMultiline: comma + SupportedStyles: + - comma + - no_comma + Enabled: true + +Style/TrivialAccessors: + Description: 'Prefer attr_* methods to trivial readers/writers.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#attr_family' + Enabled: false + +Style/VariableInterpolation: + Description: >- + Don't interpolate global, instance and class variables + directly in strings. + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#curlies-interpolate' + Enabled: false + +Style/WhenThen: + Description: 'Use when x then ... for one-line cases.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#one-line-cases' + Enabled: false + +Style/WhileUntilModifier: + Description: >- + Favor modifier while/until usage when you have a + single-line body. + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#while-as-a-modifier' + Enabled: false + +Style/WordArray: + Description: 'Use %w or %W for arrays of words.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#percent-w' + Enabled: false + +# Lint + +Lint/AmbiguousOperator: + Description: >- + Checks for ambiguous operators in the first argument of a + method invocation without parentheses. + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#parens-as-args' + Enabled: false + +Lint/AmbiguousRegexpLiteral: + Description: >- + Checks for ambiguous regexp literals in the first argument of + a method invocation without parenthesis. + Enabled: false + +Lint/AssignmentInCondition: + Description: "Don't use assignment in conditions." + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#safe-assignment-in-condition' + Enabled: false + +Lint/CircularArgumentReference: + Description: "Don't refer to the keyword argument in the default value." + Enabled: false + +Lint/ConditionPosition: + Description: >- + Checks for condition placed in a confusing position relative to + the keyword. + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#same-line-condition' + Enabled: false + +Lint/DeprecatedClassMethods: + Description: 'Check for deprecated class method calls.' + Enabled: false + +Lint/DuplicatedKey: + Description: 'Check for duplicate keys in hash literals.' + Enabled: false + +Lint/EachWithObjectArgument: + Description: 'Check for immutable argument given to each_with_object.' + Enabled: false + +Lint/ElseLayout: + Description: 'Check for odd code arrangement in an else block.' + Enabled: false + +Lint/FormatParameterMismatch: + Description: 'The number of parameters to format/sprint must match the fields.' + Enabled: false + +Lint/HandleExceptions: + Description: "Don't suppress exception." + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#dont-hide-exceptions' + Enabled: false + +Lint/InvalidCharacterLiteral: + Description: >- + Checks for invalid character literals with a non-escaped + whitespace character. + Enabled: false + +Style/InitialIndentation: + Description: >- + Checks the indentation of the first non-blank non-comment line in a file. + Enabled: false + +Lint/LiteralInCondition: + Description: 'Checks of literals used in conditions.' + Enabled: false + +Lint/LiteralInInterpolation: + Description: 'Checks for literals used in interpolation.' + Enabled: false + +Lint/Loop: + Description: >- + Use Kernel#loop with break rather than begin/end/until or + begin/end/while for post-loop tests. + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#loop-with-break' + Enabled: false + +Lint/NestedMethodDefinition: + Description: 'Do not use nested method definitions.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-nested-methods' + Enabled: false + +Lint/NonLocalExitFromIterator: + Description: 'Do not use return in iterator to cause non-local exit.' + Enabled: false + +Lint/ParenthesesAsGroupedExpression: + Description: >- + Checks for method calls with a space before the opening + parenthesis. + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#parens-no-spaces' + Enabled: false + +Lint/RequireParentheses: + Description: >- + Use parentheses in the method call to avoid confusion + about precedence. + Enabled: false + +Lint/UnderscorePrefixedVariableName: + Description: 'Do not use prefix `_` for a variable that is used.' + Enabled: false + +Lint/UnneededDisable: + Description: >- + Checks for rubocop:disable comments that can be removed. + Note: this cop is not disabled when disabling all cops. + It must be explicitly disabled. + Enabled: false + +Lint/Void: + Description: 'Possible use of operator/literal/variable in void context.' + Enabled: false + +# Performance + +Performance/CaseWhenSplat: + Description: >- + Place `when` conditions that use splat at the end + of the list of `when` branches. + Enabled: false + +Performance/Count: + Description: >- + Use `count` instead of `select...size`, `reject...size`, + `select...count`, `reject...count`, `select...length`, + and `reject...length`. + Enabled: false + +Performance/Detect: + Description: >- + Use `detect` instead of `select.first`, `find_all.first`, + `select.last`, and `find_all.last`. + Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerabledetect-vs-enumerableselectfirst-code' + Enabled: false + +Performance/FlatMap: + Description: >- + Use `Enumerable#flat_map` + instead of `Enumerable#map...Array#flatten(1)` + or `Enumberable#collect..Array#flatten(1)` + Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerablemaparrayflatten-vs-enumerableflat_map-code' + Enabled: false + +Performance/ReverseEach: + Description: 'Use `reverse_each` instead of `reverse.each`.' + Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerablereverseeach-vs-enumerablereverse_each-code' + Enabled: false + +Performance/Sample: + Description: >- + Use `sample` instead of `shuffle.first`, + `shuffle.last`, and `shuffle[Fixnum]`. + Reference: 'https://github.com/JuanitoFatas/fast-ruby#arrayshufflefirst-vs-arraysample-code' + Enabled: false + +Performance/Size: + Description: >- + Use `size` instead of `count` for counting + the number of elements in `Array` and `Hash`. + Reference: 'https://github.com/JuanitoFatas/fast-ruby#arraycount-vs-arraysize-code' + Enabled: false + +Performance/StringReplacement: + Description: >- + Use `tr` instead of `gsub` when you are replacing the same + number of characters. Use `delete` instead of `gsub` when + you are deleting characters. + Reference: 'https://github.com/JuanitoFatas/fast-ruby#stringgsub-vs-stringtr-code' + Enabled: false + +# Rails + +Rails/ActionFilter: + Description: 'Enforces consistent use of action filter methods.' + Enabled: false + +Rails/Date: + Description: >- + Checks the correct usage of date aware methods, + such as Date.today, Date.current etc. + Enabled: false + +Rails/DefaultScope: + Description: 'Checks if the argument passed to default_scope is a block.' + Enabled: false + +Rails/FindBy: + Description: 'Prefer find_by over where.first.' + Enabled: false + +Rails/FindEach: + Description: 'Prefer all.find_each over all.find.' + Enabled: false + +Rails/HasAndBelongsToMany: + Description: 'Prefer has_many :through to has_and_belongs_to_many.' + Enabled: false + +Rails/Output: + Description: 'Checks for calls to puts, print, etc.' + Enabled: false + +Rails/ReadWriteAttribute: + Description: >- + Checks for read_attribute(:attr) and + write_attribute(:attr, val). + Enabled: false + +Rails/ScopeArgs: + Description: 'Checks the arguments of ActiveRecord scopes.' + Enabled: false + +Rails/TimeZone: + Description: 'Checks the correct usage of time zone aware methods.' + StyleGuide: 'https://github.com/bbatsov/rails-style-guide#time' + Reference: 'http://danilenko.org/2012/7/6/rails_timezones' + Enabled: false + +Rails/Validation: + Description: 'Use validates :attribute, hash of validations.' + Enabled: false diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9b99d3f0..1b0505dd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,3 +2,9 @@ Contributing to LaunchDarkly SDK for Ruby ========================================= We encourage pull-requests and other contributions from the community. We've also published an [SDK contributor's guide](http://docs.launchdarkly.com/v1.0/docs/sdk-contributors-guide) that provides a detailed explanation of how our SDKs work. + +Style +----- + +Our pull requests have [Hound CI](https://houndci.com/) set up to do style checking. +We also run [Rubocop](https://github.com/bbatsov/rubocop). diff --git a/Gemfile b/Gemfile index fa75df15..b4e2a20b 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,3 @@ -source 'https://rubygems.org' +source "https://rubygems.org" gemspec diff --git a/README.md b/README.md index a223680d..537eb394 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Check out our [documentation](http://docs.launchdarkly.com) for in-depth instruc Contributing ------------ -We encourage pull-requests and other contributions from the community. We've also published an [SDK contributor's guide](http://docs.launchdarkly.com/v1.0/docs/sdk-contributors-guide) that provides a detailed explanation of how our SDKs work. +See [Contributing](https://github.com/launchdarkly/ruby-client/blob/master/CONTRIBUTING.md) About LaunchDarkly ----------- diff --git a/Rakefile b/Rakefile index 2ff6513f..fd36e8a5 100644 --- a/Rakefile +++ b/Rakefile @@ -1,5 +1,5 @@ require "bundler/gem_tasks" -require 'rspec/core/rake_task' +require "rspec/core/rake_task" RSpec::Core::RakeTask.new(:spec) task default: :spec diff --git a/ldclient-rb.gemspec b/ldclient-rb.gemspec index 4e992414..91411c4c 100644 --- a/ldclient-rb.gemspec +++ b/ldclient-rb.gemspec @@ -1,15 +1,15 @@ # coding: utf-8 -lib = File.expand_path('../lib', __FILE__) +lib = File.expand_path("../lib", __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) -require 'ldclient-rb/version' +require "ldclient-rb/version" Gem::Specification.new do |spec| spec.name = "ldclient-rb" spec.version = LaunchDarkly::VERSION spec.authors = ["LaunchDarkly"] spec.email = ["team@launchdarkly.com"] - spec.summary = %q{LaunchDarkly SDK for Ruby} - spec.description = %q{Official LaunchDarkly SDK for Ruby} + spec.summary = "LaunchDarkly SDK for Ruby" + spec.description = "Official LaunchDarkly SDK for Ruby" spec.homepage = "https://github.com/launchdarkly/ruby-client" spec.license = "Apache 2.0" diff --git a/lib/ldclient-rb/config.rb b/lib/ldclient-rb/config.rb index 64e1e22e..bdfec0ed 100644 --- a/lib/ldclient-rb/config.rb +++ b/lib/ldclient-rb/config.rb @@ -1,7 +1,6 @@ -require 'logger' +require "logger" module LaunchDarkly - # # This class exposes advanced configuration options for the LaunchDarkly client library. Most users # will not need to use a custom configuration-- the default configuration sets sane defaults for most use cases. @@ -174,6 +173,5 @@ def self.default_feature_store def self.default_debug_stream false end - end end diff --git a/lib/ldclient-rb/ldclient.rb b/lib/ldclient-rb/ldclient.rb index 2440fef0..dd606459 100644 --- a/lib/ldclient-rb/ldclient.rb +++ b/lib/ldclient-rb/ldclient.rb @@ -1,14 +1,13 @@ -require 'faraday/http_cache' -require 'json' -require 'digest/sha1' -require 'thread' -require 'logger' -require 'net/http/persistent' -require 'benchmark' -require 'hashdiff' +require "faraday/http_cache" +require "json" +require "digest/sha1" +require "thread" +require "logger" +require "net/http/persistent" +require "benchmark" +require "hashdiff" module LaunchDarkly - BUILTINS = [:key, :ip, :country, :email, :firstName, :lastName, :avatar, :name, :anonymous] # @@ -17,7 +16,6 @@ module LaunchDarkly # # class LDClient - # # Creates a new client instance that connects to LaunchDarkly. A custom # configuration parameter can also supplied to specify advanced options, @@ -49,7 +47,7 @@ def initialize(api_key, config = Config.default) def flush events = [] begin - while true + loop do events << @queue.pop(true) end rescue ThreadError @@ -61,37 +59,36 @@ def flush end def post_flushed_events(events) - res = log_timings("Flush events") { + res = log_timings("Flush events") do next @client.post (@config.base_uri + "/api/events/bulk") do |req| - req.headers['Authorization'] = 'api_key ' + @api_key - req.headers['User-Agent'] = 'RubyClient/' + LaunchDarkly::VERSION - req.headers['Content-Type'] = 'application/json' + req.headers["Authorization"] = "api_key " + @api_key + req.headers["User-Agent"] = "RubyClient/" + LaunchDarkly::VERSION + req.headers["Content-Type"] = "application/json" req.body = events.to_json req.options.timeout = @config.read_timeout req.options.open_timeout = @config.connect_timeout end - } - if res.status/100 != 2 + end + if res.status / 100 != 2 @config.logger.error("[LDClient] Unexpected status code while processing events: #{res.status}") end end - def create_worker Thread.new do - while true do + loop do begin flush sleep(@config.flush_interval) - rescue Exception => exn - @config.logger.error("[LDClient] Unexpected exception in create_worker: #{exn.inspect} #{exn.to_s}\n\t#{exn.backtrace.join("\n\t")}") + rescue StandardError => exn + @config.logger.error("[LDClient] Unexpected exception in create_worker: #{exn.inspect} #{exn}\n\t#{exn.backtrace.join("\n\t")}") end end end end - def get_flag?(key, user, default=false) + def get_flag?(key, user, default = false) toggle?(key, user, default) end @@ -125,7 +122,7 @@ def get_flag?(key, user, default=false) # @param default=false [Boolean] the default value of the flag # # @return [Boolean] whether or not the flag should be enabled, or the default value if the flag is disabled on the LaunchDarkly control panel - def toggle?(key, user, default=false) + def toggle?(key, user, default = false) return default if @offline unless user @@ -133,11 +130,11 @@ def toggle?(key, user, default=false) return default end - if @config.stream? and not @stream_processor.started? + if @config.stream? && !@stream_processor.started? @stream_processor.start end - if @config.stream? and @stream_processor.initialized? + if @config.stream? && @stream_processor.initialized? feature = get_streamed_flag(key) else feature = get_flag_int(key) @@ -145,11 +142,11 @@ def toggle?(key, user, default=false) value = evaluate(feature, user) value.nil? ? default : value - add_event({kind: 'feature', key: key, user: user, value: value}) + add_event(kind: "feature", key: key, user: user, value: value) LDNewRelic.annotate_transaction(key, value) return value rescue StandardError => error - @config.logger.error("[LDClient] Unhandled exception in toggle: (#{error.class.name}) #{error.to_s}\n\t#{error.backtrace.join("\n\t")}") + @config.logger.error("[LDClient] Unhandled exception in toggle: (#{error.class.name}) #{error}\n\t#{error.backtrace.join("\n\t")}") default end @@ -174,7 +171,7 @@ def add_event(event) # @param [Hash] The user to register # def identify(user) - add_event({kind: 'identify', key: user[:key], user: user}) + add_event(kind: "identify", key: user[:key], user: user) end def set_offline @@ -186,7 +183,7 @@ def set_online end def is_offline? - return @offline + @offline end # @@ -198,23 +195,23 @@ def is_offline? # # @return [void] def track(event_name, user, data) - add_event({kind: 'custom', key: event_name, user: user, data: data }) + add_event(kind: "custom", key: event_name, user: user, data: data) end # # Returns the key of every feature # def feature_keys - get_features.map {|feature| feature[:key]} + get_features.map { |feature| feature[:key] } end # # Returns all features # def get_features - res = make_request '/api/features' + res = make_request "/api/features" - if res.status/100 == 2 + if res.status / 100 == 2 return JSON.parse(res.body, symbolize_names: true)[:items] else @config.logger.error("[LDClient] Unexpected status code #{res.status}") @@ -238,9 +235,9 @@ def get_flag_stream(key) end def get_flag_int(key) - res = log_timings("Feature request") { - next make_request '/api/eval/features/' + key - } + res = log_timings("Feature request") do + next make_request "/api/eval/features/" + key + end if res.status == 401 @config.logger.error("[LDClient] Invalid API key") @@ -252,19 +249,18 @@ def get_flag_int(key) return nil end - if res.status/100 != 2 + if res.status / 100 != 2 @config.logger.error("[LDClient] Unexpected status code #{res.status}") return nil end - JSON.parse(res.body, symbolize_names: true) end def make_request(path) @client.get (@config.base_uri + path) do |req| - req.headers['Authorization'] = 'api_key ' + @api_key - req.headers['User-Agent'] = 'RubyClient/' + LaunchDarkly::VERSION + req.headers["Authorization"] = "api_key " + @api_key + req.headers["User-Agent"] = "RubyClient/" + LaunchDarkly::VERSION req.options.timeout = @config.read_timeout req.options.open_timeout = @config.connect_timeout end @@ -275,13 +271,13 @@ def param_for_user(feature, user) id_hash = user[:key] if user[:secondary] - id_hash += '.' + user[:secondary] + id_hash += "." + user[:secondary] end hash_key = "%s.%s.%s" % [feature[:key], feature[:salt], id_hash] hash_val = (Digest::SHA1.hexdigest(hash_key))[0..14] - return hash_val.to_i(16) / Float(0xFFFFFFFFFFFFFFF) + hash_val.to_i(16) / Float(0xFFFFFFFFFFFFFFF) end def match_target?(target, user) @@ -305,26 +301,25 @@ def match_target?(target, user) return false end - end def match_user?(variation, user) if variation[:userTarget] return match_target?(variation[:userTarget], user) end - return false + false end def find_user_match(feature, user) feature[:variations].each do |variation| return variation[:value] if match_user?(variation, user) end - return nil + nil end def match_variation?(variation, user) variation[:targets].each do |target| - if !!variation[:userTarget] and target[:attribute].to_sym == :key + if !!variation[:userTarget] && target[:attribute].to_sym == :key next end @@ -332,14 +327,14 @@ def match_variation?(variation, user) return true end end - return false + false end def find_target_match(feature, user) feature[:variations].each do |variation| return variation[:value] if match_variation?(variation, user) end - return nil + nil end def find_weight_match(feature, param) @@ -350,7 +345,7 @@ def find_weight_match(feature, param) return variation[:value] if param < total end - return nil + nil end def evaluate(feature, user) @@ -373,19 +368,18 @@ def log_timings(label, &block) return block.call unless @config.log_timings? && @config.logger.debug? res = nil exn = nil - bench = Benchmark.measure { + bench = Benchmark.measure do begin res = block.call - rescue Exception => e + rescue StandardError => e exn = e end - } + end @config.logger.debug { "[LDClient] #{label} timing: #{bench}".chomp } raise exn if exn - return res + res end private :post_flushed_events, :add_event, :get_streamed_flag, :get_flag_stream, :get_flag_int, :make_request, :param_for_user, :match_target?, :match_user?, :match_variation?, :evaluate, :create_worker, :log_timings - end end diff --git a/lib/ldclient-rb/newrelic.rb b/lib/ldclient-rb/newrelic.rb index 22eeaa78..ed6eb4e4 100644 --- a/lib/ldclient-rb/newrelic.rb +++ b/lib/ldclient-rb/newrelic.rb @@ -1,19 +1,16 @@ module LaunchDarkly - class LDNewRelic begin - require 'newrelic_rpm' + require "newrelic_rpm" NR_ENABLED = defined?(::NewRelic::Agent.add_custom_parameters) - rescue Exception + rescue ScriptError, StandardError NR_ENABLED = false end def self.annotate_transaction(key, value) if NR_ENABLED - ::NewRelic::Agent.add_custom_parameters({key.to_s => value.to_s}) + ::NewRelic::Agent.add_custom_parameters(key.to_s => value.to_s) end end end - - end diff --git a/lib/ldclient-rb/store.rb b/lib/ldclient-rb/store.rb index 54f57823..932a754b 100644 --- a/lib/ldclient-rb/store.rb +++ b/lib/ldclient-rb/store.rb @@ -1,7 +1,6 @@ -require 'thread_safe' +require "thread_safe" module LaunchDarkly - # A thread-safe in-memory store suitable for use # with the Faraday caching HTTP client. Uses the # Threadsafe gem as the underlying cache. diff --git a/lib/ldclient-rb/stream.rb b/lib/ldclient-rb/stream.rb index 59e517d6..4662856f 100644 --- a/lib/ldclient-rb/stream.rb +++ b/lib/ldclient-rb/stream.rb @@ -1,9 +1,8 @@ -require 'concurrent/atomics' -require 'json' -require 'ld-em-eventsource' +require "concurrent/atomics" +require "json" +require "ld-em-eventsource" module LaunchDarkly - PUT = "put" PATCH = "patch" DELETE = "delete" @@ -16,47 +15,47 @@ def initialize end def get(key) - @lock.with_read_lock { + @lock.with_read_lock do f = @features[key.to_sym] (f.nil? || f[:deleted]) ? nil : f - } + end end def all - @lock.with_read_lock { - @features.select {|k,f| not f[:deleted]} - } + @lock.with_read_lock do + @features.select { |_k, f| not f[:deleted] } + end end def delete(key, version) - @lock.with_write_lock { + @lock.with_write_lock do old = @features[key.to_sym] - if old != nil and old[:version] < version + if !old.nil? && old[:version] < version old[:deleted] = true old[:version] = version @features[key.to_sym] = old elsif old.nil? - @features[key.to_sym] = {deleted: true, version: version} + @features[key.to_sym] = { deleted: true, version: version } end - } + end end def init(fs) - @lock.with_write_lock { + @lock.with_write_lock do @features.replace(fs) @initialized.make_true - } + end end def upsert(key, feature) - @lock.with_write_lock { + @lock.with_write_lock do old = @features[key.to_sym] - if old.nil? or old[:version] < feature[:version] + if old.nil? || old[:version] < feature[:version] @features[key.to_sym] = feature end - } + end end def initialized? @@ -118,10 +117,10 @@ def start def boot_event_manager source = EM::EventSource.new(@config.stream_uri + "/features", - {}, - {'Accept' => 'text/event-stream', - 'Authorization' => 'api_key ' + @api_key, - 'User-Agent' => 'RubyClient/' + LaunchDarkly::VERSION}) + {}, + "Accept" => "text/event-stream", + "Authorization" => "api_key " + @api_key, + "User-Agent" => "RubyClient/" + LaunchDarkly::VERSION) source.on(PUT) { |message| process_message(message, PUT) } source.on(PATCH) { |message| process_message(message, PATCH) } source.on(DELETE) { |message| process_message(message, DELETE) } @@ -157,12 +156,10 @@ def set_connected def should_fallback_update disc = @disconnected.get - disc != nil and disc < (Time.now - 120) + !disc.nil? && disc < (Time.now - 120) end # TODO mark private methods private :boot_event_manager, :process_message, :set_connected, :set_disconnected, :start_reactor - end - end diff --git a/spec/config_spec.rb b/spec/config_spec.rb index e42b98ee..da630638 100644 --- a/spec/config_spec.rb +++ b/spec/config_spec.rb @@ -1,44 +1,44 @@ -require 'spec_helper' +require "spec_helper" describe LaunchDarkly::Config do subject { LaunchDarkly::Config } - describe '.initialize' do - it 'can be initialized with default settings' do + describe ".initialize" do + it "can be initialized with default settings" do expect(subject).to receive(:default_capacity).and_return 1234 expect(subject.new.capacity).to eq 1234 end - it 'accepts custom arguments' do + it "accepts custom arguments" do expect(subject).to_not receive(:default_capacity) expect(subject.new(capacity: 50).capacity).to eq 50 end - it 'will chomp base_url and stream_uri' do - uri = 'https://test.launchdarkly.com' - config = subject.new(base_uri: uri+'/') + it "will chomp base_url and stream_uri" do + uri = "https://test.launchdarkly.com" + config = subject.new(base_uri: uri + "/") expect(config.base_uri).to eq uri end end - describe '@base_uri' do - it 'can be read' do + describe "@base_uri" do + it "can be read" do expect(subject.new.base_uri).to eq subject.default_base_uri end end - describe '.default_store' do - it 'uses Rails cache if it is available' do - rails = instance_double('Rails', cache: :cache) - stub_const('Rails', rails) + describe ".default_store" do + it "uses Rails cache if it is available" do + rails = instance_double("Rails", cache: :cache) + stub_const("Rails", rails) expect(subject.default_store).to eq :cache end - it 'uses memory store if Rails is not available' do + it "uses memory store if Rails is not available" do expect(subject.default_store).to be_an_instance_of LaunchDarkly::ThreadSafeMemoryStore end end - describe '.default_logger' do - it 'uses Rails logger if it is available' do - rails = instance_double('Rails', logger: :logger) - stub_const('Rails', rails) + describe ".default_logger" do + it "uses Rails logger if it is available" do + rails = instance_double("Rails", logger: :logger) + stub_const("Rails", rails) expect(subject.default_logger).to eq :logger end - it 'Uses logger if Rails is not available' do + it "Uses logger if Rails is not available" do expect(subject.default_logger).to be_an_instance_of Logger end end diff --git a/spec/ldclient_spec.rb b/spec/ldclient_spec.rb index ab207af1..38745e17 100644 --- a/spec/ldclient_spec.rb +++ b/spec/ldclient_spec.rb @@ -1,29 +1,29 @@ -require 'spec_helper' +require "spec_helper" describe LaunchDarkly::LDClient do subject { LaunchDarkly::LDClient } let(:client) do expect_any_instance_of(LaunchDarkly::LDClient).to receive :create_worker - subject.new('api_key') + subject.new("api_key") end let(:feature) do - data = File.read(File.join('spec', 'fixtures', 'feature.json')) + data = File.read(File.join("spec", "fixtures", "feature.json")) JSON.parse(data, symbolize_names: true) end let(:user) do - data = File.read(File.join('spec', 'fixtures', 'user.json')) + data = File.read(File.join("spec", "fixtures", "user.json")) JSON.parse(data, symbolize_names: true) end describe '#flush' do - it 'will flush and post all events' do - client.instance_variable_get(:@queue).push 'asdf' - client.instance_variable_get(:@queue).push 'asdf' + it "will flush and post all events" do + client.instance_variable_get(:@queue).push "asdf" + client.instance_variable_get(:@queue).push "asdf" expect(client).to receive(:post_flushed_events) client.flush expect(client.instance_variable_get(:@queue).length).to eq 0 end - it 'will not do anything if there are no events' do + it "will not do anything if there are no events" do expect(client).to_not receive(:post_flushed_events) expect(client.instance_variable_get(:@config).logger).to_not receive :error client.flush @@ -31,22 +31,22 @@ end describe '#post_flushed_events' do - let(:events) { ['event'] } - it 'will flush and post all events' do - result = double('result', status: 200) + let(:events) { ["event"] } + it "will flush and post all events" do + result = double("result", status: 200) expect(client.instance_variable_get(:@client)).to receive(:post).and_return result expect(client.instance_variable_get(:@config).logger).to_not receive :error client.send(:post_flushed_events, events) expect(client.instance_variable_get(:@queue).length).to eq 0 end - it 'will allow any 2XX response' do - result = double('result', status: 202) + it "will allow any 2XX response" do + result = double("result", status: 202) expect(client.instance_variable_get(:@client)).to receive(:post).and_return result expect(client.instance_variable_get(:@config).logger).to_not receive :error client.send(:post_flushed_events, events) end - it 'will work with unexpected post results' do - result = double('result', status: 418) + it "will work with unexpected post results" do + result = double("result", status: 418) expect(client.instance_variable_get(:@client)).to receive(:post).and_return result expect(client.instance_variable_get(:@config).logger).to receive :error client.send(:post_flushed_events, events) @@ -55,130 +55,130 @@ end describe '#toggle?' do - it 'will not fail' do + it "will not fail" do expect(client.instance_variable_get(:@config)).to receive(:stream?).and_raise RuntimeError expect(client.instance_variable_get(:@config).logger).to receive(:error) - result = client.toggle?(feature[:key], user, 'default') - expect(result).to eq 'default' + result = client.toggle?(feature[:key], user, "default") + expect(result).to eq "default" end - it 'requires user' do + it "requires user" do expect(client.instance_variable_get(:@config).logger).to receive(:error) - result = client.toggle?(feature[:key], nil, 'default') - expect(result).to eq 'default' + result = client.toggle?(feature[:key], nil, "default") + expect(result).to eq "default" end - it 'returns value from streamed flag if available' do + it "returns value from streamed flag if available" do expect(client.instance_variable_get(:@config)).to receive(:stream?).and_return(true).twice expect(client.instance_variable_get(:@stream_processor)).to receive(:started?).and_return true expect(client.instance_variable_get(:@stream_processor)).to receive(:initialized?).and_return true expect(client).to receive(:add_event) expect(client).to receive(:get_streamed_flag).and_return feature - result = client.toggle?(feature[:key], user, 'default') + result = client.toggle?(feature[:key], user, "default") expect(result).to eq false end - it 'returns value from normal request if streamed flag is not available' do + it "returns value from normal request if streamed flag is not available" do expect(client.instance_variable_get(:@config)).to receive(:stream?).and_return(false).twice expect(client).to receive(:add_event) expect(client).to receive(:get_flag_int).and_return feature - result = client.toggle?(feature[:key], user, 'default') + result = client.toggle?(feature[:key], user, "default") expect(result).to eq false end end describe '#get_streamed_flag' do - it 'will not check the polled flag normally' do + it "will not check the polled flag normally" do expect(client).to receive(:get_flag_stream).and_return true expect(client).to_not receive(:get_flag_int) - expect(client.send(:get_streamed_flag, 'key')).to eq true + expect(client.send(:get_streamed_flag, "key")).to eq true end - context 'debug stream' do - it 'will log an error if the streamed and polled flag do not match' do + context "debug stream" do + it "will log an error if the streamed and polled flag do not match" do expect(client.instance_variable_get(:@config)).to receive(:debug_stream?).and_return true expect(client).to receive(:get_flag_stream).and_return true expect(client).to receive(:get_flag_int).and_return false expect(client.instance_variable_get(:@config).logger).to receive(:error) - expect(client.send(:get_streamed_flag, 'key')).to eq true + expect(client.send(:get_streamed_flag, "key")).to eq true end end end describe '#get_features' do - it 'will parse and return the features list' do - result = double('Faraday::Response', status: 200, body: '{"items": ["asdf"]}') - expect(client).to receive(:make_request).with('/api/features').and_return(result) + it "will parse and return the features list" do + result = double("Faraday::Response", status: 200, body: '{"items": ["asdf"]}') + expect(client).to receive(:make_request).with("/api/features").and_return(result) data = client.send(:get_features) - expect(data).to eq ['asdf'] + expect(data).to eq ["asdf"] end - it 'will log errors' do - result = double('Faraday::Response', status: 418) - expect(client).to receive(:make_request).with('/api/features').and_return(result) + it "will log errors" do + result = double("Faraday::Response", status: 418) + expect(client).to receive(:make_request).with("/api/features").and_return(result) expect(client.instance_variable_get(:@config).logger).to receive(:error) client.send(:get_features) end end describe '#get_flag_int' do - it 'will return the parsed flag' do - result = double('Faraday::Response', status: 200, body: '{"asdf":"qwer"}') - expect(client).to receive(:make_request).with('/api/eval/features/key').and_return(result) - data = client.send(:get_flag_int, 'key') - expect(data).to eq({asdf: 'qwer'}) - end - it 'will accept 401 statuses' do - result = double('Faraday::Response', status: 401) - expect(client).to receive(:make_request).with('/api/eval/features/key').and_return(result) + it "will return the parsed flag" do + result = double("Faraday::Response", status: 200, body: '{"asdf":"qwer"}') + expect(client).to receive(:make_request).with("/api/eval/features/key").and_return(result) + data = client.send(:get_flag_int, "key") + expect(data).to eq(asdf: "qwer") + end + it "will accept 401 statuses" do + result = double("Faraday::Response", status: 401) + expect(client).to receive(:make_request).with("/api/eval/features/key").and_return(result) expect(client.instance_variable_get(:@config).logger).to receive(:error) - data = client.send(:get_flag_int, 'key') + data = client.send(:get_flag_int, "key") expect(data).to be_nil end - it 'will accept 404 statuses' do - result = double('Faraday::Response', status: 404) - expect(client).to receive(:make_request).with('/api/eval/features/key').and_return(result) + it "will accept 404 statuses" do + result = double("Faraday::Response", status: 404) + expect(client).to receive(:make_request).with("/api/eval/features/key").and_return(result) expect(client.instance_variable_get(:@config).logger).to receive(:error) - data = client.send(:get_flag_int, 'key') + data = client.send(:get_flag_int, "key") expect(data).to be_nil end - it 'will accept non-standard statuses' do - result = double('Faraday::Response', status: 418) - expect(client).to receive(:make_request).with('/api/eval/features/key').and_return(result) + it "will accept non-standard statuses" do + result = double("Faraday::Response", status: 418) + expect(client).to receive(:make_request).with("/api/eval/features/key").and_return(result) expect(client.instance_variable_get(:@config).logger).to receive(:error) - data = client.send(:get_flag_int, 'key') + data = client.send(:get_flag_int, "key") expect(data).to be_nil end end describe '#make_request' do - it 'will make a proper request' do + it "will make a proper request" do expect(client.instance_variable_get :@client).to receive(:get) - client.send(:make_request, '/asdf') + client.send(:make_request, "/asdf") end end describe '#param_for_user' do - it 'will return a consistent hash of a user key, feature key, and feature salt' do + it "will return a consistent hash of a user key, feature key, and feature salt" do param = client.send(:param_for_user, feature, user) expect(param).to be_between(0.0, 1.0).inclusive end end describe '#evaluate' do - it 'will return nil if there is no feature' do + it "will return nil if there is no feature" do expect(client.send(:evaluate, nil, user)).to eq nil end - it 'will return nil unless the feature is on' do + it "will return nil unless the feature is on" do feature[:on] = false expect(client.send(:evaluate, feature, user)).to eq nil end - it 'will return value if it matches the user' do - user = {key: 'Alida.Caples@example.com'} + it "will return value if it matches the user" do + user = { key: "Alida.Caples@example.com" } expect(client.send(:evaluate, feature, user)).to eq false - user = {key: 'foo@bar.com'} + user = { key: "foo@bar.com" } expect(client.send(:evaluate, feature, user)).to eq true end - it 'will return value if the target matches' do - user = {key: 'asdf@asdf.com', custom: {groups: 'Microsoft'}} + it "will return value if the target matches" do + user = { key: "asdf@asdf.com", custom: { groups: "Microsoft" } } expect(client.send(:evaluate, feature, user)).to eq true end - it 'will return value if the weight matches' do + it "will return value if the weight matches" do expect(client).to receive(:param_for_user).and_return 0.1 expect(client.send(:evaluate, feature, user)).to eq true expect(client).to receive(:param_for_user).and_return 0.9 @@ -187,28 +187,28 @@ end describe '#log_timings' do - let(:block) { lambda { 'result' } } - let(:label) { 'label' } - it 'will not measure if not configured to do so' do + let(:block) { lambda { "result" } } + let(:label) { "label" } + it "will not measure if not configured to do so" do expect(Benchmark).to_not receive(:measure) client.send(:log_timings, label, &block) end - context 'logging enabled' do + context "logging enabled" do before do expect(client.instance_variable_get(:@config)).to receive(:log_timings?).and_return true expect(client.instance_variable_get(:@config).logger).to receive(:debug?).and_return true end - it 'will benchmark timings and return result' do + it "will benchmark timings and return result" do expect(Benchmark).to receive(:measure).and_call_original expect(client.instance_variable_get(:@config).logger).to receive(:debug) result = client.send(:log_timings, label, &block) - expect(result).to eq 'result' + expect(result).to eq "result" end - it 'will raise exceptions if the block has them' do + it "will raise exceptions if the block has them" do block = lambda { raise RuntimeError } expect(Benchmark).to receive(:measure).and_call_original expect(client.instance_variable_get(:@config).logger).to receive(:debug) - expect{client.send(:log_timings, label, &block)}.to raise_error RuntimeError + expect { client.send(:log_timings, label, &block) }.to raise_error RuntimeError end end end diff --git a/spec/newrelic_spec.rb b/spec/newrelic_spec.rb index 558db3bb..f20afa42 100644 --- a/spec/newrelic_spec.rb +++ b/spec/newrelic_spec.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require "spec_helper" describe LaunchDarkly::LDNewRelic do subject { LaunchDarkly::LDNewRelic } diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index cc4dcb57..cc5e312b 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,7 +1,7 @@ -require 'codeclimate-test-reporter' +require "codeclimate-test-reporter" CodeClimate::TestReporter.start -require 'ldclient-rb' +require "ldclient-rb" RSpec.configure do |config| config.before(:each) do diff --git a/spec/store_spec.rb b/spec/store_spec.rb index 146c6f76..6d499e9b 100644 --- a/spec/store_spec.rb +++ b/spec/store_spec.rb @@ -1,11 +1,10 @@ -require 'spec_helper' +require "spec_helper" describe LaunchDarkly::ThreadSafeMemoryStore do subject { LaunchDarkly::ThreadSafeMemoryStore } let(:store) { subject.new } - it 'can read and write' do - store.write('key', 'value') - value = store.read 'key' - expect(store.read('key')).to eq 'value' + it "can read and write" do + store.write("key", "value") + expect(store.read("key")).to eq "value" end end diff --git a/spec/stream_spec.rb b/spec/stream_spec.rb index 6fe0d0aa..ab52ba7b 100644 --- a/spec/stream_spec.rb +++ b/spec/stream_spec.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require "spec_helper" describe LaunchDarkly::InMemoryFeatureStore do subject { LaunchDarkly::InMemoryFeatureStore } @@ -7,20 +7,20 @@ describe LaunchDarkly::StreamProcessor do subject { LaunchDarkly::StreamProcessor } let(:config) { LaunchDarkly::Config.new } - let(:processor) { LaunchDarkly::StreamProcessor.new('api_key', config) } + let(:processor) { LaunchDarkly::StreamProcessor.new("api_key", config) } describe '#start' do - it 'will check if the reactor has started' do + it "will check if the reactor has started" do expect(processor).to receive(:start_reactor).and_return false expect(EM).to_not receive(:defer) processor.start end - it 'will check if the stream processor has already started' do + it "will check if the stream processor has already started" do expect(processor).to receive(:start_reactor).and_return true processor.instance_variable_get(:@started).make_true expect(EM).to_not receive(:defer) processor.start end - it 'will boot the stream processor' do + it "will boot the stream processor" do expect(processor).to receive(:start_reactor).and_return true expect(EM).to receive(:defer) processor.start @@ -35,22 +35,22 @@ let(:put_message) { '{"key": {"value": "asdf"}}' } let(:patch_message) { '{"path": "akey", "data": {"value": "asdf", "version": 1}}' } let(:delete_message) { '{"path": "akey", "version": 2}' } - it 'will accept PUT methods' do + it "will accept PUT methods" do processor.send(:process_message, put_message, LaunchDarkly::PUT) - expect(processor.instance_variable_get(:@store).get("key")).to eq({value: 'asdf'}) + expect(processor.instance_variable_get(:@store).get("key")).to eq(value: "asdf") end - it 'will accept PATCH methods' do + it "will accept PATCH methods" do processor.send(:process_message, patch_message, LaunchDarkly::PATCH) - expect(processor.instance_variable_get(:@store).get("key")).to eq({value: 'asdf', version: 1}) + expect(processor.instance_variable_get(:@store).get("key")).to eq(value: "asdf", version: 1) end - it 'will accept DELETE methods' do + it "will accept DELETE methods" do processor.send(:process_message, patch_message, LaunchDarkly::PATCH) processor.send(:process_message, delete_message, LaunchDarkly::DELETE) expect(processor.instance_variable_get(:@store).get("key")).to eq(nil) end - it 'will log an error if the method is not recognized' do + it "will log an error if the method is not recognized" do expect(processor.instance_variable_get(:@config).logger).to receive :error - processor.send(:process_message, put_message, 'get') + processor.send(:process_message, put_message, "get") end end end diff --git a/spec/version_spec.rb b/spec/version_spec.rb index 1ab033c1..fa70a1ac 100644 --- a/spec/version_spec.rb +++ b/spec/version_spec.rb @@ -1,7 +1,7 @@ -require 'spec_helper' +require "spec_helper" describe LaunchDarkly do - it 'has a version' do + it "has a version" do expect(LaunchDarkly::VERSION).to be end end